Skip to content

Commit

Permalink
REFACTORED to the same spec of php norm (partially)
Browse files Browse the repository at this point in the history
  • Loading branch information
reekoheek committed Jun 2, 2016
1 parent 45777cd commit 05d8e96
Show file tree
Hide file tree
Showing 24 changed files with 640 additions and 1,045 deletions.
5 changes: 5 additions & 0 deletions .jshintrc
@@ -0,0 +1,5 @@
{
"strict": true,
"esnext": true,
"node": true
}
2 changes: 1 addition & 1 deletion LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015 Ganesha
Copyright (c) 2016 PT Sagara Xinix Solusitama

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
79 changes: 42 additions & 37 deletions README.md
@@ -1,49 +1,61 @@
# node-norm

Node Norm is Javascript port of [Norm](https://github.com/xinix-technology/norm) - The PHP Data access or ORM-like or NOSQL interface to common database server.
node-norm is Javascript port of [Norm](https://github.com/xinix-technology/norm) - The data access or ORM-like or NOSQL interface to common database server.

## Features

- Adaptive persistence, currently indexedDB and memory, you can extend easily by creating new adapters
- Multiple connections to work with
- NoSQL-like approaches
- Data fixtures
- Adaptive persistence, currently memory, you can extend easily by creating new adapters,
- Multiple connections to work with,
- NoSQL-like approaches,
- Data fixtures.

## How to work with it

```javascript

var n = norm()
add('idb', norm.adapters.idb());

var friend = n('Friend').newInstance();
friend.first_name = 'John';
friend.last_name = 'Doe';
friend.save().then(function() {
console.log('Great, we have new friend');
});

n('Friend').find({'age!gte': 50}).fetch().then(function(oldFriends) {
console.log('We have ' + oldFriends.length + ' friends');
});
var norm = require('norm');

var friend = norm.Factory('Friend').newInstance();
friend
.set({
'first_name': 'John',
'last_name': 'Doe',
})
.save()
.then(function() {
console.log('Great, we have new friend');
});

norm.Factory('Friend')
.find({ 'age!gte': 50 })
.fetch()
.then(function(oldFriends) {
console.log('We have ' + oldFriends.length + ' friends');
});
```

if you work with generator on harmony spec, the code is better ;)
if you work with co generator, the code is better ;)

```javascript
// jshint esnext: true

var n = norm()
add('idb', require('norm/lib/adapters/idb')());
const norm = require('norm');
const factory = norm.Factory('Friend');

co(function *() {
var friend = factory.newInstance();
friend.set({
'first_name': 'John',
'last_name': 'Doe',
});
yield friend.save();

var friend = n('Friend').newInstance();
friend.first_name = 'John';
friend.last_name = 'Doe';
yield friend.save();
console.log('Great, we have new friend');
console.log('Great, we have new friend');

var oldFriends = yield n('Friend').find({'age!gte': 50}).fetch();
console.log('We have ' + oldFriends.length + ' friends');
var oldFriends = yield factory.find({'age!gte': 50}).fetch();

console.log(`We have ${oldFriends.length} friends`);
});

```

Expand All @@ -57,15 +69,8 @@ TBD

## Running test on browser

You can run test from web browser or node.js by using jasmine.
To run on web browser, put url to SpecRunner.html of your project directory.
For now node-norm only support server side with Node.JS

## Running test on node.js

To run on node.js, run following commands on terminal

```
npm install -g jasmine
cd $PROJECT_DIR
jasmine
```
TBD
62 changes: 62 additions & 0 deletions adapters/disk.js
@@ -0,0 +1,62 @@
'use strict';

const Memory = require('./memory');
const fs = require('fs-promise');
const path = require('path');

class Disk extends Memory {
constructor(repository, id, options) {
super(repository, id, options);

this.file = this.options.file;
}

ensureData() {
if (!this._ensured) {
var file = this.file;
return fs.ensureFile(file)
.then(() => fs.readFile(file))
.then(buffer => JSON.parse(buffer))
.catch(err => {})
.then(function(data) {
this._ensured = true;
this.data = data || {};
}.bind(this));
} else {
return Promise.resolve();
}
}

persist(collectionId, row) {
var superPersist = super.persist.bind(this);
return this.ensureData()
.then(function() {
return superPersist(collectionId, row);
})
.then(function(row) {
return fs.writeFile(this.file, JSON.stringify(this.data, null, 2))
.then(() => row);
}.bind(this));
}

remove(cursor) {
var superRemove = super.remove.bind(this);
return this.ensureData()
.then(function() {
return superRemove(cursor);
})
.then(function(row) {
return fs.writeFile(this.file, JSON.stringify(this.data, null, 2));
}.bind(this));
}

fetch(cursor) {
var superFetch = super.fetch.bind(this);
return this.ensureData()
.then(function() {
return superFetch(cursor);
});
}
}

module.exports = Disk;
183 changes: 183 additions & 0 deletions adapters/memory.js
@@ -0,0 +1,183 @@
'use strict';

const uuid = require('node-uuid');
const Connection = require('../connection');

class Memory extends Connection {

constructor(repository, id, options) {
super(repository, id);

this.options = options || {};
this.data = this.options.data || {};
}

persist(collectionId, row) {
return new Promise(function (resolve, reject) {
if (!row.$id) {
row.$id = uuid.v1();
}

// marshall row
var data = this.data[collectionId] = this.data[collectionId] || [];
var foundIndex;
if (data.some((drow, index) => {
if (drow.$id === row.$id) {
foundIndex = index;
return true;
}
})) {
data[foundIndex] = row;
} else {
data.push(row);
}

// unmarshall row
resolve(row);
}.bind(this));
}

remove(cursor) {
return this.fetch(cursor).then(function(rows) {
var data = this.data[cursor.collection.id] = this.data[cursor.collection.id] || [];

rows.forEach(function (row) {
data.some((drow, index) => {
if (drow.$id === row.$id) {
data.splice(index, 1);
return true;
}
});
}.bind(this));
}.bind(this));
}

matchCriteria(criteria, row) {
if (!criteria) {
return true;
}

for(var i in criteria) {
if (criteria[i] !== row[i]) {
return false;
}
}
return true;
}

fetch(cursor) {
return new Promise(function(resolve, reject) {
var data = this.data[cursor.collection.id] || [];
var rows = [];
var limit = cursor.limit;
var skip = cursor.skip;

for(let row of data) {
if (skip) {
skip--;
} else {
if (this.matchCriteria(cursor.criteria, row)) {
if (limit !== -1) {
if (limit <= 0) {
break;
}
limit--;
}

rows.push(row);
}
}
}
resolve(rows);
}.bind(this));
}

}

module.exports = Memory;
// (function(root, factory) {
// 'use strict';

// if (typeof module !== 'undefined' && module.exports) {
// var uuid = require('node-uuid');
// var _ = require('lodash');

// module.exports = factory(uuid, _);
// } else {
// root.norm.adapters.memory = factory(root.uuid, root._);
// }
// })(this, function(uuid, _) {
// 'use strict';

// var memoryAdapter = function(options) {
// return {
// persist: function(collection, model) {
// this.data = this.data || {};
// this.data[collection.id] = this.data[collection.id] || [];

// if (!model.$id) {
// model.$id = uuid.v1();
// this.data[collection.id].push(model);
// } else {
// var row = _.find(this.data[collection.id], function(row) {
// return row.$id === model.$id;
// });
// _.merge(row, model);
// }
// return Promise.resolve(model);
// },

// remove: function(collection, model) {
// this.data = this.data || {};
// this.data[collection.id] = this.data[collection.id] || [];

// for(var i in this.data[collection.id]) {
// var row = this.data[collection.id][i];

// if (row.$id === model.$id) {
// this.data[collection.id].splice(i, 1);
// break;
// }
// }

// return Promise.resolve();
// },

// query: function(cursor, options) {
// this.data = this.data || {};
// this.data[cursor.collection.id] = this.data[cursor.collection.id] || [];

// var criteria = cursor.criteria || {};
// var results = [];
// var maxLimit = cursor.limit();
// for(var i in this.data[cursor.collection.id]) {
// if (maxLimit <= 0) {
// break;
// }
// var row = this.data[cursor.collection.id][i];
// var caught = _.some(criteria, function(v, i) {
// var x = i.split('!');
// var k = x[0];
// var op = x[1] || 'eq';
// switch(op) {
// case 'eq':
// if (row[k] !== v) {
// return true;
// }
// break;
// default:
// throw new Error('Unimplemented');
// }
// });
// if (!caught) {
// maxLimit--;
// results.push(row);
// }
// }
// return Promise.resolve(results);
// }
// };
// };

// return memoryAdapter;
// });

0 comments on commit 05d8e96

Please sign in to comment.