Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

decypher

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

decypher - npm Package Compare versions

Comparing version 0.12.0 to 0.13.0

384

batch.js

@@ -0,1 +1,2 @@

/* eslint no-unused-vars: 0 */
/**

@@ -7,63 +8,105 @@ * Decypher Batch

*/
var utils = require('./utils.js'),
isPlainObject = utils.isPlainObject,
assign = utils.assign,
var MultiDirectedGraph = require('graphology').MultiDirectedGraph,
Query = require('./query.js'),
helpers = require('./helpers.js');
helpers = require('./helpers.js'),
utils = require('./utils.js');
var escapeIdentifier = helpers.escapeIdentifier,
nodePattern = helpers.nodePattern,
relationshipPattern = helpers.relationshipPattern;
// node or relationship can be created node ref. int or string, predicate
// TODO: optimize the query
// TODO: static method on batches for one-shot
// #.createNode(label, map)
// #.createRelationship(type, fromNode, toNode, map)
// #.deleteNode(node)
// #.deleteRelationship(relationship)
// #.updateNodeProperties(node, map)
// #.updateRelationshipProperties(relationship, map)
// #.setNodeProperty
// #.setRelationshipProperty
// #.removeNodeProperty
// #.setNodeProperty
// #.removeNodeLabel
// #.addNodeLabel
/**
* Reference classes.
*/
function BatchNode(identifier) {
this.identifier = identifier;
}
BatchNode.prototype.toString = function() {
return this.identifier;
};
function BatchRelationship(identifier) {
this.identifier = identifier;
}
BatchRelationship.prototype.toString = function() {
return this.identifier;
};
/**
* Helpers.
*/
function buildObject(key, value) {
if (!key)
return null;
function createIncrementalId() {
var id = 0;
var o = {};
o[key] = value;
return o;
return function() {
return id++;
};
}
function validData(o) {
return o && !!Object.keys(o).length;
function isValidNodeRepresentation(representation) {
return (
typeof representation === 'string' ||
typeof representation === 'number' ||
representation instanceof BatchNode ||
utils.isPlainObject(representation)
);
}
function isValidRelationshipRepresentation(representation) {
return (
typeof representation === 'string' ||
typeof representation === 'number' ||
representation instanceof BatchRelationship ||
utils.isPlainObject(representation)
);
}
/**
* Handler classes.
* Hash functions.
*/
function Node(batch, id, data, labels) {
function newNodeIdentifier(id) {
return 'nN' + id;
}
var external = id || id === 0;
function newNodePropsIdentifier(id) {
return 'nNP' + id;
}
// Properties
this.batch = batch;
this.id = id || null;
this.identifier = 'N' + (!external ? 'i' + (batch.nodesCounter++) : 'e' + id);
this.param = 'p' + this.identifier;
this.data = data || null;
this.labels = labels;
this.external = external;
function existingNodeIdentifier(id) {
return 'eN' + id;
}
function Edge(batch, id, source, predicate, target, data) {
function newEdgeIdentifier(id) {
return 'nE' + id;
}
var external = id || id === 0;
function newEdgePropsIdentifier(id) {
return 'nEP' + id;
}
// Properties
this.batch = batch;
this.id = id || null;
this.identifier = 'R' + (!external ? 'i' + (batch.edgesCounter++) : 'e' + id);
this.param = 'p' + this.identifier;
this.source = source;
this.target = target;
this.predicate = predicate;
this.data = data || null;
this.external = external;
function existingEdgeIdentifier(id) {
return 'eE' + id;
}
function hashLabels(labels) {
return labels.join('§');
}
/**
* Main class.
* Batch main class.
*/

@@ -75,171 +118,188 @@ function Batch() {

// Counters & indexes
this.nodesCounter = 0;
this.edgesCounter = 0;
this.nodes = {};
this.externalNodes = {};
this.edges = [];
this.unlinks = [];
// Properties
this.graph = new MultiDirectedGraph();
this.generateNodeId = createIncrementalId();
this.generateEdgeId = createIncrementalId();
}
/**
* Private prototype.
* Internal node resolution.
*/
Batch.prototype._externalNode = function(id) {
if (typeof id !== 'string' && typeof id !== 'number')
throw Error('decypher.Batch: invalid node. Should be either a node handler or a raw Neo4j id.');
Batch.prototype.resolveNode = function(caller, representation) {
if (!this.externalNodes[id])
this.externalNodes[id] = new Node(this, id, {});
// BatchNode reference:
if (representation instanceof BatchNode) {
if (!this.graph.hasNode(representation))
throw new Error('decypher.Batch.' + caller + ': could not find given node in internal graph. This reference probably belongs to another batch.');
return this.externalNodes[id];
return representation.identifier;
}
// Existing node
if (typeof representation === 'string' ||
typeof representation === 'number') {
var identifier = existingNodeIdentifier(representation);
if (!this.graph.hasNode(identifier))
this.graph.addNode(identifier, {
id: representation,
existing: true
});
return identifier;
}
};
/**
* Public prototype.
* Creating a node.
*/
Batch.prototype.createNode = function(labelOrLabels, properties) {
var labels = [];
// Saving a node
Batch.prototype.create = function(data, labels) {
labels = labels || [];
if (labelOrLabels)
labels = labels.concat(labelOrLabels);
if (!isPlainObject(data))
throw Error('decypher.Batch.save: provided data is not an object.');
if (properties && !utils.isPlainObject(properties))
throw new Error('decypher.Batch.createNode: invalid properties. Expecting a plain object.');
// Coercing labels to array
labels = [].concat(labels);
var id = this.generateNodeId(),
identifier = newNodeIdentifier(id);
// Giving an id to the created node
var node = new Node(this, null, data, labels);
this.nodes[node.identifier] = node;
this.graph.addNode(identifier, {
id: id,
existing: false,
properties: properties || {},
labels: labels
});
return node;
return new BatchNode(identifier);
};
// Updating a node
Batch.prototype.update = function(node, data) {
if (!isPlainObject(data))
throw Error('decypher.Batch.update: provided data is not an object.');
/**
* Creating a relationship.
*/
Batch.prototype.createRelationship = function(type, source, target, properties) {
if (typeof type !== 'string')
throw new Error('decypher.Batch.createRelationship: invalid relationship type. Expecting a string.');
if (!(node instanceof Node))
node = this._externalNode(node);
if (!isValidNodeRepresentation(source))
throw new Error('decypher.Batch.createRelationship: invalid source node. Expecting a Neo4j id, a node\'s reference in the batch or a predicate.');
node.data = assign({}, node.data, data);
if (!isValidNodeRepresentation(target))
throw new Error('decypher.Batch.createRelationship: invalid target node. Expecting a Neo4j id, a node\'s reference in the batch or a predicate.');
return node;
};
if (properties && !utils.isPlainObject(properties))
throw new Error('decypher.Batch.createRelationship: invalid properties. Expecting a plain object.');
// Setting a property
// Batch.prototype.set = function(id, key, value) {
var id = this.generateEdgeId(),
identifier = newEdgeIdentifier(id);
// };
var sourceIdentifier = this.resolveNode('createRelationship', source),
targetIdentifier = this.resolveNode('createRelationship', target);
// Removing a property
// Batch.prototype.remove = function(id, key) {
this.graph.addEdgeWithKey(
identifier,
sourceIdentifier,
targetIdentifier,
{
id: id,
existing: false,
type: type,
properties: properties || {}
}
);
// };
// Relate two nodes
Batch.prototype.relate = function(source, predicate, target, data) {
data = data || null;
if (!(source instanceof Node))
source = this._externalNode(source);
if (!(target instanceof Node))
target = this._externalNode(target);
var edge = new Edge(this, null, source, predicate, target, data);
this.edges.push(edge);
return edge;
return new BatchRelationship(identifier);
};
// Unrelate two nodes
// TODO: how to delete a relation strictly
Batch.prototype.unrelate = function(source, predicate, target) {
if (!(source instanceof Node))
source = this._externalNode(source);
if (!(target instanceof Node))
target = this._externalNode(target);
this.unlinks.push({source: source, target: target, predicate: predicate});
return;
};
Batch.prototype.delete = function() {
};
/**
* Building the batch's query.
*/
Batch.prototype.query = function() {
var query = new Query(),
matchSegment = query.segment(),
createSegment = query.segment();
createSegment = query.segment(),
updateSegment = query.segment(),
nodesToCreate = [],
relationshipsToCreate = [];
var params = {};
//-- Registering external nodes
Object.keys(this.externalNodes).forEach(function(k) {
var node = this.externalNodes[k];
var nodes = this.graph.nodes(),
edges = this.graph.edges();
matchSegment
.match(nodePattern({identifier: node.identifier}))
.where('id(' + node.identifier + ') = ' + node.id);
var node,
edge,
source,
target,
pattern,
attr,
propsIdentifier,
i,
l;
if (validData(node.data))
query.set(node.identifier + ' += {' + node.param + '}', buildObject(node.param, node.data));
}, this);
for (i = 0, l = nodes.length; i < l; i++) {
node = nodes[i];
attr = this.graph.getNodeAttributes(node);
//-- Internal nodes
Object.keys(this.nodes).forEach(function(k) {
var node = this.nodes[k];
if (!attr.existing) {
propsIdentifier = newNodePropsIdentifier(attr.id);
pattern = {
identifier: node,
labels: attr.labels
};
createSegment
.create(nodePattern({identifier: node.identifier, data: node.param}), buildObject(node.param, node.data));
if (Object.keys(attr.properties).length) {
pattern.data = propsIdentifier;
params[propsIdentifier] = attr.properties;
}
var labels = node.labels.map(function(label) {
return node.identifier + ':' + escapeIdentifier(label);
});
nodesToCreate.push(helpers.nodePattern(pattern));
}
else {
query.set(labels);
}, this);
// We need to match the node in the graph
matchSegment.match(helpers.nodePattern(node));
matchSegment.where('id(' + node + ') = ' + attr.id);
}
}
//-- Unlinks
this.unlinks.forEach(function(unlink, i) {
matchSegment
.match(relationshipPattern({
for (i = 0, l = edges.length; i < l; i++) {
edge = edges[i];
source = this.graph.source(edge);
target = this.graph.target(edge);
attr = this.graph.getEdgeAttributes(edge);
if (!attr.existing) {
propsIdentifier = newEdgePropsIdentifier(attr.id);
pattern = {
direction: 'out',
identifier: 'U' + i,
predicate: unlink.predicate,
source: unlink.source.identifier,
target: unlink.target.identifier
}));
source: source,
target: target,
type: attr.type
};
query.delete('U' + i);
});
if (Object.keys(attr.properties).length) {
pattern.data = propsIdentifier;
params[propsIdentifier] = attr.properties;
}
//-- Edges
this.edges.forEach(function(edge) {
createSegment
.create(relationshipPattern({
direction: 'out',
predicate: edge.predicate,
data: edge.data ? edge.param : null,
source: edge.source.identifier,
target: edge.target.identifier
}));
relationshipsToCreate.push(helpers.relationshipPattern(pattern));
}
}
if (validData(edge.data))
query.params(buildObject(edge.param, edge.data));
});
if (nodesToCreate.length)
createSegment.create(nodesToCreate);
if (relationshipsToCreate.length)
createSegment.create(relationshipsToCreate);
query.params(params);
return query;
};
Batch.prototype.build = function() {
return this.query().build();
};
/**
* Exporting.
*/
module.exports = Batch;

@@ -64,2 +64,7 @@ /**

// Convenient inspect method
Expression.prototype.inspect = function() {
return 'Expression (' + this.toString() + ')';
};
module.exports = Expression;

@@ -50,2 +50,5 @@ /**

var labels = [].concat(opts.label || opts.labels || []),
hasLabels = !!labels.length;
if (typeof opts === 'string')

@@ -62,10 +65,7 @@ return nodePattern({identifier: opts});

if (opts.label)
if (Array.isArray(opts.label))
pattern += ':' + opts.label.map(escapeIdentifier).join(':');
else
pattern += ':' + escapeIdentifier(opts.label);
if (hasLabels)
pattern += ':' + labels.map(escapeIdentifier).join(':');
if (opts.data) {
if (opts.identifier || opts.label)
if (opts.identifier || hasLabels)
pattern += ' ';

@@ -92,2 +92,5 @@

var types = [].concat(opts.type || opts.types || []),
hasTypes = !!types.length;
var pattern = '';

@@ -103,3 +106,3 @@

if (opts.identifier || opts.predicate || opts.data) {
if (opts.identifier || hasTypes || opts.data) {
pattern += '[';

@@ -110,9 +113,9 @@

if (opts.predicate)
pattern += [].concat(opts.predicate).map(function(predicate) {
return ':' + escapeIdentifier(predicate);
if (hasTypes)
pattern += types.map(function(type) {
return ':' + escapeIdentifier(type);
}).join('|');
if (opts.data) {
if (opts.identifier || opts.predicate)
if (opts.identifier || hasTypes)
pattern += ' ';

@@ -119,0 +122,0 @@

{
"name": "decypher",
"version": "0.12.0",
"version": "0.13.0",
"description": "A handful of cypher utilities for Node.js",
"main": "index.js",
"scripts": {
"lint": "eslint ./src ./test",
"lint": "eslint ./*.js ./test",
"test": "mocha -R spec ./test"

@@ -34,3 +34,4 @@ },

"dependencies": {
"escape-regexp": "0.0.1"
"escape-regexp": "0.0.1",
"graphology": "^0.7.0"
},

@@ -37,0 +38,0 @@ "eslintConfig": {

@@ -116,3 +116,3 @@ /**

return string.replace(INTERPOLATION_REGEX, function(match, identifier) {
if (params.hasOwnProperty(identifier)) {
if (params.hasOwnProperty(identifier)) {
var value = params[identifier];

@@ -212,2 +212,17 @@

// Convenient inspect method
Query.prototype.inspect = function() {
var dummy = {
statements: this.statements(),
params: this.params()
};
Object.defineProperty(dummy, 'constructor', {
enumerable: false,
value: Query
});
return dummy;
};
module.exports = Query;

@@ -292,3 +292,3 @@ [![Build Status](https://travis-ci.org/Yomguithereal/decypher.svg)](https://travis-ci.org/Yomguithereal/decypher)

// * `identifier`: a string
// * `label`: a string
// * `label` or `labels`: a string or an array of strings
// * `data`:

@@ -342,3 +342,3 @@ // - if string, will produce a single parameter

// * `identifier`: a string
// * `predicate`: a string or an array of strings
// * `type` or `types`: a string or an array of strings
// * `data`:

@@ -360,3 +360,3 @@ // - if string, will produce a single parameter

identifier: 'r',
predicate: 'KNOWS'
type: 'KNOWS'
});

@@ -367,3 +367,3 @@ >>> '-[r:KNOWS]->'

direction: 'in',
predicate: ['PLAYS_IN', 'KNOWS']
types: ['PLAYS_IN', 'KNOWS']
});

@@ -380,3 +380,3 @@ >>> '<-[:PLAYS_IN|:KNOWS]-'

helpers.relationshipPattern({
predicate: 'KNOWS',
type: 'KNOWS',
data: {since: 1975}

@@ -388,3 +388,3 @@ });

direction: 'out',
predicate: 'PLAYED_IN',
type: 'PLAYED_IN',
source: 'a',

@@ -391,0 +391,0 @@ target: {

@@ -40,2 +40,3 @@ /**

'LOAD CSV FROM',
'LOAD CSV WITH HEADERS FROM',
'MATCH',

@@ -86,2 +87,3 @@ 'MERGE',

'FALSE',
'FIELDTERMINATOR',
'IS',

@@ -88,0 +90,0 @@ 'NULL',

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc