Skip to content
This repository has been archived by the owner on Apr 5, 2020. It is now read-only.

Commit

Permalink
Merge pull request #9 from LucianoPAlmeida/v1.0.0
Browse files Browse the repository at this point in the history
V1.0.0
  • Loading branch information
LucianoPAlmeida authored Oct 5, 2017
2 parents 249bfd8 + 83cb753 commit 181ed42
Show file tree
Hide file tree
Showing 11 changed files with 1,296 additions and 482 deletions.
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,62 @@ You can create and drop indexes in properties.
});
```

## Operation API

Almost every method on ogmneo.Node and ogmneo.Relation have now the Operation API, that instead of executing the function on database returning a promise, it creates an ogmneo.Operation object that can be executed after by the ogmneo.OperationExecuter. Exemple:
```js
const ogmneo = require('ogmneo');

let operation = ogmneo.Node.createOperation({ name: 'name', tes: 3 }, 'test');
ogmneo.OperationExecuter.execute(operation)
.then((node) => {
//Created returned object => {id: 1, name: 'name', tes: 3}
}).catch((error) => {
//Handle error
});
```

## Transactional API
With the Operation API we can now execute as many READ or WRITE operations on the same transaction.
For exemple you want to create to nodes and then relate those two. But if the relation fails you want to rollback all the operations.
```js
const ogmneo = require('ogmneo');

let createDriver = ogmneo.Node.createOperation({name: 'Ayrton Senna', carNumber: 12 }, 'Driver');
ogmneo.OperationExecuter.write((transaction) => {
return ogmneo.OperationExecuter.execute(createDriver, transaction)
.then((driver) => {
let createCar = ogmneo.Node.createOperation({name: 'MP4/4'}, 'Car');
return ogmneo.OperationExecuter.execute(createCar, transaction).then((car) => {
                                      let relate = ogmneo.Relation.relateOperation(driver.id, 'DRIVES', car.id, {year: 1988});
return ogmneo.OperationExecuter.execute(relate, transaction);
                                   });
});
}).then((result) => {
//Result here
});
```
All of those operations will be executed on the same transaction and you can rollback anytime you want. The transaction is the [neo4j driver](https://github.com/neo4j/neo4j-javascript-driver) transaction object and you can see more about it on their docs [here](http://neo4j.com/docs/api/javascript-driver/current/class/src/v1/transaction.js~Transaction.html).

### Batching operation in a single transaction

You can also batch many operation READ or WRITE operations in a single transaction.

```js
const ogmneo = require('ogmneo');

let createUser1 = OGMNeoNode.createOperation({name: 'Ayrton Senna'}, 'Person');
let createUser2 = OGMNeoNode.createOperation({name: 'Alain Prost'}, 'Person');

OGMNeoOperationExecuter.batchWriteOperations([createUser1, createUser2]).then((result) => {
let created1 = result[0];
let created2 = result[1];
console.log(created1.name); // 'Ayrton Senna'
console.log(created2.name); // 'Alain Prost'
});
```
If one of those fails, all other operations on the transaction will be rolledback automatically.

## Documentation

See the full **API** documentation at [docs](http://ogmneo-docs.getforge.io/). All docs was generated by [JSDoc](https://github.com/jsdoc3/jsdoc).
Expand Down
21 changes: 14 additions & 7 deletions __test__/node-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,18 @@ test('Test FAIL for query param updateMany node', (assert) => {
});
});

test('Test FAIL for query param updateMany not object newProperties', (assert) => {
OGMNeoNode.updateMany('', '').catch((error) => {
assert.equal(error.message, 'The new properties must be an object');
assert.end();
});
});

test('Test empty new properties updateMany node', (assert) => {
let query = OGMQueryBuilder.create('test', new OGMNeoWhere('name', {$eq: 'name1'}));
OGMNeoNode.updateMany(query, {}).then((updateNodes) => {
assert.equal(updateNodes.length, 0);
assert.end();
OGMNeoNode.updateMany(query, {}).catch((error) => {
assert.equal(error.message, 'You must provide at least one property with NO undefined values to update');
assert.end();
});
});

Expand Down Expand Up @@ -236,8 +243,8 @@ test('Test FAIL add label ids not array', (assert) => {
});

test('Test add label empty nodesIds', (assert) => {
OGMNeoNode.addLabelToNodes('label', []).then((nodes) => {
assert.equal(nodes.length, 0);
OGMNeoNode.addLabelToNodes('label', []).catch((error) => {
assert.equal(error.message, 'You must provide at least one valid id to this operation');
assert.end();
});
});
Expand Down Expand Up @@ -273,8 +280,8 @@ test('Test FAIL remove label ids not array', (assert) => {
});

test('Test remove label empty nodesIds', (assert) => {
OGMNeoNode.removeLabelFromNodes('label', []).then((nodes) => {
assert.equal(nodes.length, 0);
OGMNeoNode.removeLabelFromNodes('label', []).catch((error) => {
assert.equal(error.message, 'You must provide at least one valid id to this operation');
assert.end();
});
});
Expand Down
85 changes: 85 additions & 0 deletions __test__/operation-executer-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
'use strict';

const test = require('tape');
const { OGMNeoOperation, OGMNeoOperationBuilder } = require('../lib/ogmneo-operation');
const OGMNeoOperationExecuter = require('../lib/ogmneo-operation-executer');
const OGMNeoNode = require('../lib/ogmneo-node');
const OGMNeo = require('../lib/ogmneo');
const OGMNeoQuery = require('../lib/ogmneo-query');
const OGMNeoWhere = require('../lib/ogmneo-where');

const _ = require('lodash');

test('Test Invalid Operation', (assert) => {
OGMNeoOperationExecuter.execute({}).catch((error) => {
assert.equal(error.message, 'The operation must be a instance of ogmneo.Operation');
assert.end();
});
});

//Testing OGMNeoOperationExecuter.write
test('Test write type on operation', (assert) => {
let create = OGMNeoNode.createOperation({name: 'Ayrton Senna', carNumber: 12 }, 'Person');
OGMNeoOperationExecuter.write((transaction) => {
return OGMNeoOperationExecuter.execute(create, transaction)
.then((created) => {
assert.equal(created.name, 'Ayrton Senna');
assert.equal(created.carNumber, 12);
let id = created.id;
created.carNumber = 1;
let update = OGMNeoNode.updateOperation(created);
return OGMNeoOperationExecuter.execute(update, transaction);
});
}).then((result) => {
assert.equal(result.name, 'Ayrton Senna');
assert.equal(result.carNumber, 1);
assert.end();
});
});

test('Test batch write type operations', (assert) => {
let createUser1 = OGMNeoNode.createOperation({name: 'Ayrton Senna'}, 'Person');
let createUser2 = OGMNeoNode.createOperation({name: 'Alain Prost'}, 'Person');

OGMNeoOperationExecuter.batchWriteOperations([createUser1, createUser2]).then((result) => {
let created1 = result[0];
let created2 = result[1];
assert.notEqual(created1.id, undefined);
assert.equal(created1.name, 'Ayrton Senna');
assert.notEqual(created2.id, undefined);
assert.equal(created2.name, 'Alain Prost');
assert.end();
});
});

test('Test batch read type operations', (assert) => {
let query1 = OGMNeoNode.findOneOperation(OGMNeoQuery.create('Person').where(OGMNeoWhere.create('name', { $eq: 'Ayrton Senna' })));
let query2 = OGMNeoNode.findOneOperation(OGMNeoQuery.create('Person').where(OGMNeoWhere.create('name', { $eq: 'Alain Prost' })));

OGMNeoOperationExecuter.batchReadOperations([query1, query2]).then((result) => {
let found1 = result[0];
let found2 = result[1];
assert.notEqual(found1.id, undefined);
assert.equal(found1.name, 'Ayrton Senna');
assert.notEqual(found2.id, undefined);
assert.equal(found2.name, 'Alain Prost');
assert.end();
});
});

test('Test validate batch operations', (assert) => {
let query1 = OGMNeoNode.findOneOperation(OGMNeoQuery.create('Person').where(OGMNeoWhere.create('name', { $eq: 'Ayrton Senna' })));

assert.throws(() => {
OGMNeoOperationExecuter._validateOperations('',OGMNeoOperation.READ);
}, /The parameter operations must be an array/);

assert.throws(() => {
OGMNeoOperationExecuter._validateOperations([''],OGMNeoOperation.READ);
}, /The parameter operations must be an array that contains only instances of ogmneo.Operation/);

assert.throws(() => {
OGMNeoOperationExecuter._validateOperations([query1], OGMNeoOperation.WRITE);
}, /The parameter operations must be an array that contains only instances of ogmneo.Operation that have type : WRITE/);
assert.end();
});
35 changes: 35 additions & 0 deletions __test__/operation-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict';

const test = require('tape');
const { OGMNeoOperation, OGMNeoOperationBuilder } = require('../lib/ogmneo-operation');
const _ = require('lodash');

test('Test create operation', (assert) => {
let operation = OGMNeoOperationBuilder.create()
.cypher('CREATE (n:Label {property: {property}}) RETURN n')
.object({property: 'value'})
.type(OGMNeoOperation.READ)
.then((result) => {
return { id: 1, property: 'value' }
}).build();

assert.equal(operation.cypher, 'CREATE (n:Label {property: {property}}) RETURN n');
assert.equal(operation.type, OGMNeoOperation.READ);
assert.deepEqual(operation.object, {property: 'value'} );
assert.true(_.isFunction(operation.then), 'Then is not a function');

assert.end();
});

test('Test operation convenience methods', (assert) => {
let operation = OGMNeoOperationBuilder.create()
.cypher('CREATE (n:Label {property: {property}}) RETURN n')
.object({property: 'value'})
.type(OGMNeoOperation.READ)
.then((result)=> {
return { id: 1, property: 'value' }
}).build();
assert.true(operation.isReadType, 'Then is not a read operation');
assert.false(operation.isWriteType, 'Then is not a write operation');
assert.end();
});
6 changes: 3 additions & 3 deletions __test__/relation-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ test('Test empty newProperties UPDATE MANY', (assert) => {
let node2 = nodes[1];
let query = OGMNeoRelationQuery.create('relatedto').relationWhere(OGMNeoWhere.create('property', { $eq: 'c' }));
OGMNeoRelation.updateMany({}, query)
.then((updatedRelations) => {
assert.equal(updatedRelations.length, 0);
.catch((error) => {
assert.equal(error.message, 'newProperties must be an object with at least one valid property to update');
assert.end();
});
});
Expand Down Expand Up @@ -163,7 +163,7 @@ test('Test FIND ONE relation', (assert) => {

Promise.all([find1, find2, find3]).then((finds) => {
assert.equal(finds[0].__type, 'relatedto');
assert.equal(finds[1], undefined);
assert.equal(finds[1], null);
let rel = finds[2];
assert.equal(rel.__type, 'relatedto');
assert.equal(rel.property, 'c');
Expand Down
12 changes: 9 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const cypher = require('./lib/ogmneo-cypher');
const index = require('./lib/ogmneo-index');
const where = require('./lib/ogmneo-where');
const relationQuery = require('./lib/ogmneo-relation-query');

const { OGMNeoOperation, OGMNeoOperationBuilder } = require('./lib/ogmneo-operation');
const OGMNeoOperationExecuter = require('./lib/ogmneo-operation-executer');
module.exports = {
Connection: connection,
OGMNeoNode: nodes,
Expand All @@ -16,13 +17,18 @@ module.exports = {
OGMNeoIndex: index,
OGMNeoWhere: where,
OGMNeoRelationQuery: relationQuery,

OGMNeoOperation: OGMNeoOperation,
OGMNeoOperationBuilder: OGMNeoOperationBuilder,
OGMNeoOperationExecuter: OGMNeoOperationExecuter,
//Simplified names
Node: nodes,
Query: query,
Relation: relations,
Cypher: cypher,
Index: index,
Where: where,
RelationQuery: relationQuery
RelationQuery: relationQuery,
Operation: OGMNeoOperation,
OperationBuilder: OGMNeoOperationBuilder,
OperationExecuter: OGMNeoOperationExecuter
};
Loading

0 comments on commit 181ed42

Please sign in to comment.