Jsoncan
- An agile json based database.
- load seamlessly with zero config.
- if you are developing a project like static site, personal blog or business website, jsoncan will be quite useful.
- all the data is saved in json files, it's like a cache system, and it works the way.
- using in the right place, it will be convenient, fast and effective.
Install
npm install jsoncan
Version
1.1.1
Usage
create and connection
var Jsoncan = require('jsoncan');
var PATH = path.join(__dirname, 'data');
var tables = {
people: {
id: {
text: 'user id',
type: 'autoIncrement'
},
name: {
text: 'your name',
type: 'string',
max: 30,
min: 2,
required: true
}
}
};
var can = new Jsoncan(PATH, tables);
var People = can.open('people');
var Doctor = can.open('doctor', schemas);
primary key
- All the tables will be automatically added an "_id" field as the only primary key.
- You need not to define _id field in table schemas.
- You can add multiply unique keys, which are similar to primary key.
insert
when a record inserted, a new "_id" value will be assigned to it.
var Tom;
People.insert({name: 'Tom'}, function (e, record) {
Tom = record;
console.log(record);
});
People.insertAll([{name: 'David'}, {name: 'Bill'}], function (e, records) {
console.log(records);
});
finder
- using finder to retrieve one record, when no data found, they will return null value.
- finder(_id) find by primary key.
- finder(uniqueName, value) find by unique key.
- find(_id) and findBy(uniqueName, value) are aliases.
People.finder(Tom._id).exec(function (e, record) {...});
People.find(Tom._id).exec(function (e, record) {...});
var man = People.find(_id).execSync();
People.finder('id', Tom.id).exec(function (e, record) {...});
People.findBy('id', Tom.id).exec(function (e, record) {...});
var otherMan = People.findBy('name', 'xxx').execSync();
query or findAll
using query() to retrieve multiply records. findAll() is alias.
Product.query({price: ['>', 100], name: ['like', '%haha%']}).exec(function (e, records) {...} );
Product.findAll(filters).exec(callback);
Product.query()
.where('price', '>', 100)
.where('name', 'like', '%haha%')
.exec(callback);
var men = People.query({age: ['between', 18, 36]}).execSync();
People.query().where(age, ['>=', 18]).order('name').skip(100).limit(10).select('id, name').exec(callback);
var query = People.query();
query.where('age', 8).select();
query.where('age', '>', 8).select();
query.where('text', 'like', '%hello%').select();
query.where('name', 'pattern', /^Liu/i).select();
query.where('name', 'in', ['Tom', 'Mike', 'Jobs']).select();
query.where('age', '>', 8).where('name', 'Tom').select();
query.where({age: ['>', 8], name: 'Tom'}).select();
query.select()
query.select('id', 'name');
query.select(['id', 'name']);
query.select('id, name');
query.order(age);
query.order(age, true);
query.order('id').skip(3).limit(10);
query.exec(function (e, records) { ... });
var records = query.execSync();
query.count(function (e, count) {...});
var count = query.countSync();
update
Product.update(product._id, {price: 199.99}, function (e, record) {...});
User.updateBy('email', user.email, {age: 22}, function (e, record) {...});
User.updateAll({age: 17}, {class: 'xxx'}, function (e, records) {...});
Product.updateSync(product._id, {price: 199.99});
User.updateBySync('email', user.email, {age: 22});
User.updateAllSync({age: 17}, {class: 'xxx'});
remove
User.remove(_id, function (e) {...});
User.removeBy('class', 'xxx', function (e) {...});
User.removeAll({age, 10}, function (e) {...});
User.removeSync(_id);
User.removeBySync('class', 'xxx');
User.removeAllSync({age, 10});
the model way
There are three ways to create a model object:
- var model = Table.create({/data/});
- var model = Table.load(_id);
- var model = Table.loadBy(uniqueName, value);
var Product = can.open('product');
var productA = Product.create({name: 'xxx'});
productA.set(price, 2.99);
product.save(function (e, records) {...});
var productB = Product.load('the_primary_id');
var productC = product.loadBy(an_unique_name, 'xxxx');
productA.set(name, 'xxx').save(callback);
productA.remove(callback);
productA.set(price, 2.99).saveSync();
productA.set({name: 'xxx', price: 2.99}).saveSync();
productA.removeSync();
validate
For data safe, jsoncan will always validate the data automatically before save the data into the json file.
all the validate rules are defined in field schemas object.
the validate part is based on validator.js
so far, you can add these rules.
- isUnique
- isNull
- isRequired
- required // alias isRequired
- shouldAfter [date string]
- shouldBefore [date string]
- length
- size // alias length
- max // max size
- min // min size
- maxValue
- minValue
- pattern [regex object]
in insert or update process, if validate failed, it will throw an error.
var productA = Product.loadBy('name', 'xxx');
productA.set('name', 'a duplicated value').save(function (e, record) {
console.log(e);
});
you can also validate data in model way
var productA = Product.model({name: 'xxx', price: xxx, label: xxx});
productA.validate();
product.isValid
validateMessages = productA.messages;
schemas
the table schemas defined in a normal hash object.
except the above validate rule keys, a schema also support these keys:
- text
- type
- default
- format // define a function which format a value for presentation.
- logic // define a function to create a runtime value by other fields value.
- decimals // used for float type.
- values // used for enum or map fields.
- suffix // used for presentation
- prefix // used for presentation
- validate // a custom validate function, when failed return message or return null.
- isFake // for field like 'passwordConfirm', it 's basically same as normal field, except it will never be saved!
- autoIncrement // the first number for autoIncrement field, default is 1
- step // for autoIncrement, default is 1
- isIndex // index field
field types including:
- 'string'
- 'int'
- 'float'
- 'boolean'
- 'map'
- 'hash' // map alias
- 'ref' // new added, reference field
- 'enum'
- 'date'
- 'datetime'
- 'timestamp'
- 'autoIncrement'
- 'password' // will hash password automatically, and you can use Table.isValidPassword(inputedPassword) to check. see safepass.
- 'created' // will set a current timestamp value when record created.
- 'modified' // will be always updated to current timestamp when record saved.
- 'text',
- 'primary' // only for _id field
- 'random' // alpha number random, default length 8
- 'alias' // a logic field, used with "logic" key.
- 'email'
- 'password'
- 'url'
- 'uuid'
- 'alpha'
- 'numeric'
- 'alphanumeric'
- 'ip' // same as ip4
- 'ip4'
- 'ip6'
- 'creditCard'
- 'credit card' // same as creditCard
- 'object' // array, hash, function, up to you
examples:
var schemas = {
id: {
text: 'user id',
type: 'random',
isUnique: true,
size: 10
},
firstName: {
text: 'first name',
type: 'string',
max: 50,
min: 2,
required: true,
},
lastName: {
type: 'alias',
logic: function (data) {
return [data.firstName, data.lastName].join('.');
}
},
password: {
type: 'password',
size: 30,
required: true
},
passwordConfirm: {
type: 'string',
size: 30,
isFake: true,
validate: function (value, data) {
if (value == undefined || value == '' || value == null) {
return 'please input password confirmation';
} else if (value != data.password) {
return 'twice inputed passwords are not same!';
}
}
},
country: {
text: 'country',
type: 'map',
requred: true,
values: {
'cn': 'China',
'uk': 'England',
'jp': 'Japan',
'us': 'USA'
}
},
age: {
text: 'age',
type: 'int',
default: 10
},
sex: {
text: 'status',
type: 'enum',
values: ['female', 'male']
},
balance: {
text: 'cash balance',
type: 'float',
default: 0.00,
prefix: '$'
},
created: {
type: 'created',
format: function (t) {
var d = new Date(t);
return [d.getFullYear(), d.getMonth() + 1, d.getDate()].join('-') + ' ' + [d.getHours(), d.getMinutes(), d.getSeconds()].join(':');
}
},
modified: {
type: 'modified'
}
};
var People = can.open('people', schemas);
indexes
please see the test file.
references
please see the test file.
Blog.findBy('id', 'id value').ref('categories').hasMany('comments').exec(callback);
Product.query(filters).ref('categories').hasMany('factories').execSync();
more detail
Please see the test part.
performance test
Please see the performance part.