项目作者: na2axl

项目描述 :
Manages JSON files as databases with JSONDB Query Language (JQL)
高级语言: JavaScript
项目地址: git://github.com/na2axl/jsondb-js.git
创建时间: 2016-09-09T13:15:20Z
项目社区:https://github.com/na2axl/jsondb-js

开源协议:GNU General Public License v3.0

下载


JSONDB

Manage local databases with JSON files and JSONDB Query Language (JQL)

MIT License

What’s that ?

JSONDB is a database manager using JSON files and a custom query
language named JQL (JSONDB Query Language).

Features

  • Database management with servers, databases and tables
  • Secure connections to servers with username and password
  • Sync and async operations
  • Easy custom query language
  • Supported JQL queries:
    • select()
    • insert()
    • replace()
    • delete()
    • update()
    • truncate()
    • count()

Getting Started

Full API and documentation will be soon available on the JSONDB website…

Install using npm

JSONDB can be installed through npm:

  1. $ npm install jsondb-js

Instantiate JSONDB

  1. var JSONDB = require("jsondb-js");
  2. var jdb = new JSONDB();

Create a server

If you don’t have created a server yet, then:

  1. // Sync
  2. jdb.createServer('server_name', 'username', 'password', connect);
  3. // Async
  4. jdb.async.createServer('server_name', 'username', 'password', function (error) {
  5. if (error) {
  6. throw error;
  7. }
  8. });

It’s useful to check if the destination folder doesn’t exist before create a server to avoid errors.

  1. // Sync
  2. if (!jdb.serverExists('server_name')) {
  3. // Then... create a server
  4. }
  5. // Async
  6. jdb.async.serverExists('server_name', function(exists) {
  7. if (!exists) {
  8. // Then... create a server
  9. }
  10. });

Connect to a server

Once instantiated, you have to connect to a server before send queries.

  1. // Sync
  2. var db = jdb.connect('server_name', 'username', 'password', 'database_name');
  3. // or...
  4. var db = jdb.connect('server_name', 'username', 'password');
  5. // Async
  6. jdb.async.connect('server_name', 'user_name', 'password', 'database_name', function (error, db) {
  7. if (error) {
  8. throw error;
  9. }
  10. // db is now a server connection...
  11. });
  12. // or...
  13. jdb.async.connect('server_name', 'user_name', 'password', function (error, db) {
  14. if (error) {
  15. throw error;
  16. }
  17. // db is now a server connection...
  18. });
  • The server_name is the name of the folder which represents a server (a folder which contains databases). This folder have to be created with jdb.createServer()
  • The username and the password are the information used to connect to the server. These information are the same used when creating the server
  • The database_name is the name of the database to use with current connection. This parameter is optional and can be set manually later.

Create a database

After connection to a server, you can create a database:

  1. // Sync
  2. db.createDatabase('database_name');
  3. // Async
  4. db.async.createDatabase('database_name', function(error) {
  5. if (error) {
  6. throw error;
  7. }
  8. });

You can also check if the database exist before the creation.

  1. // Sync
  2. if (!db.databaseExists('database_name')) {
  3. // Then... create a database
  4. }
  5. // Async
  6. db.async.databaseExists('database_name', function (exists) {
  7. if (!exists) {
  8. // Then... create a database
  9. }
  10. });

Use a database

The database to use can be set using the jdb.connect() method, or manually using jdb.setDatabase() method after a connection to a server:

  1. db.setDatabase('database_name');

Create a table

Once JSONDB is properly connected to a server and use a database, you can create a table in this database:

  1. // Sync
  2. db.createTable('table_name', prototype);
  3. // Async
  4. db.async.createTable('table_name', prototype, function(error) {
  5. if (error) {
  6. throw error;
  7. }
  8. });

The prototype is an object of column_name: column_properties pairs.

Column properties

There is a list of currently supported column properties:

  • type: Defines the type of values that the column accepts. Supported types are:
    • int, integer, number
    • decimal, float
    • string
    • char
    • bool, boolean
    • array
  • default: Sets the default value of column
  • max_length: Used by some type:
    • When used with float, the number of decimals is reduced to his value
    • When used with string, the number of characters is reduced to his value
      (starting with the first character)
  • auto_increment: Defines if a column will be an auto incremented column. When used, the column is automatically set to UNIQUE KEY
  • primary_key: Defines if a column is a PRIMARY KEY
  • unique_key: Defines if a column is an UNIQUE KEY

Send a query

JSONDB can send both direct and prepared queries.

Direct queries

  1. // ---
  2. // Sync
  3. // ---
  4. var results = db.query('my_query_string');
  5. //// Specially for select() and count() queries
  6. // You can change the fecth mode
  7. results.setFetchMode(JSONDB.FETCH_ARRAY);
  8. // or...
  9. results.setFetchMode(JSONDB.FETCH_CLASS, MyCustomClass);
  10. // Explore results using a while loop (sync)
  11. while (result = results.fetch()) {
  12. // Do stuff with result...
  13. }
  14. // Explore results using recursion (async)
  15. results.async.fetch(function(error, result, next) {
  16. if (error) {
  17. throw error;
  18. }
  19. // Stop the resursion when there is no data
  20. if (result !== false) {
  21. // Do stuff with result..
  22. next(); // Important to call the same callback function with the next data
  23. }
  24. });
  25. // -----
  26. // ---
  27. // Async
  28. // ---
  29. db.async.query('my_query_string', function(error, results) {
  30. if (error) {
  31. throw error;
  32. }
  33. //// Specially for select() and count() queries
  34. // You can change the fecth mode
  35. results.setFetchMode(JSONDB.FETCH_ARRAY);
  36. // or...
  37. results.setFetchMode(JSONDB.FETCH_CLASS, MyCustomClass);
  38. // Explore results using a while loop (sync)
  39. while (result = results.fetch()) {
  40. // Do stuff with result...
  41. }
  42. // Explore results using recursion (async)
  43. results.async.fetch(function(error, result, next) {
  44. if (error) {
  45. throw error;
  46. }
  47. // Stop the resursion when there is no data
  48. if (result !== false) {
  49. // Do stuff with result..
  50. next(); // Important to call the same callback function with the next data
  51. }
  52. });
  53. });

Prepared queries

  1. // ---
  2. // Sync
  3. // ---
  4. var query = db.prepare('my_prepared_query');
  5. query.bindValue(':key1', val1, JSONDB.PARAM_INT);
  6. query.bindValue(':key2', val2, JSONDB.PARAM_STRING);
  7. query.bindValue(':key3', val3, JSONDB.PARAM_BOOL);
  8. query.bindValue(':key4', val4, JSONDB.PARAM_NULL);
  9. query.bindValue(':key5', val5, JSONDB.PARAM_ARRAY);
  10. // Execute query synchronously...
  11. var results = query.execute();
  12. // Execute query asynchronously...`
  13. query.async.execute(function(error, results) {
  14. if (error) {
  15. throw error;
  16. }
  17. // Do stuff with results...
  18. });
  19. // -----
  20. // ---
  21. // Async
  22. // ---
  23. jdb.async.prepare('my_prepared_query', function(error, query) {
  24. if (error) {
  25. throw error;
  26. }
  27. query.bindValue(':key1', val1, JSONDB.PARAM_INT);
  28. query.bindValue(':key2', val2, JSONDB.PARAM_STRING);
  29. query.bindValue(':key3', val3, JSONDB.PARAM_BOOL);
  30. query.bindValue(':key4', val4, JSONDB.PARAM_NULL);
  31. query.bindValue(':key5', val5, JSONDB.PARAM_ARRAY);
  32. // Execute query synchronously...
  33. var results = query.execute();
  34. // Execute query asynchronously...`
  35. query.async.execute(function(error, results) {
  36. if (error) {
  37. throw error;
  38. }
  39. // Do stuff with results...
  40. });
  41. });

JQL (JSONDB Query Language)

The JQL is the query language used in JSONDB. It’s a very easy language based on extensions.
A JQL query is in this form:

  1. db.query('table_name.query(parameters,...).extension1().extension2()...');

Query Examples

select()

Select all from table users where username = id and password = pass or where mail = id and password = pass

  1. var id = JSONDB.quote(form_data.id);
  2. var pass = JSONDB.quote(form_data.password);
  3. db.query("users.select(*).where(username=" + id + ",password=" + pass + ").where(mail=" + id + ",password=" + pass + ")");

Select username and mail from table users where activated = true, order the results by username with descendant method, limit the results to the 10 users after the 5th.

  1. db.query("users.select(username,mail).where(activated=true).order(username,desc).limit(5,10)");
insert()

Insert a new user in table users

  1. var username = JSONDB.quote(form_data.username);
  2. var pass = JSONDB.quote(form_data.password);
  3. var mail = JSONDB.quote(form_data.mail);
  4. db.query("users.insert(" + username + "," + pass + "," + mail + ").in(username,password,mail)");

Multiple insertion…

  1. db.query("users.insert(" + username1 + "," + pass1 + "," + mail1 + ").and(" + username2 + "," + pass2 + "," + mail2 + ").and(" + username3 + "," + pass3 + "," + mail3 + ").in(username,password,mail)");
replace()

Replace information of the first user

  1. db.query("users.replace(" + username + "," + pass + "," + mail + ").in(username,password,mail)");

Multiple replacement…

  1. db.query("users.replace(" + username1 + "," + pass1 + "," + mail1 + ").and(" + username2 + "," + pass2 + "," + mail2 + ").and(" + username3 + "," + pass3 + "," + mail3 + ").in(username,password,mail)");
delete()

Delete all users

  1. db.query("users.delete()");

Delete all banished users

  1. db.query("users.delete().where(banished = true)");

Delete a specific user

  1. db.query("users.delete().where(username = " + username + ", mail = " + mail + ")");
update()

Activate all users

  1. db.query("users.update(activated).with(true)");

Update my information ;-)

  1. db.query("users.update(mail, password, activated, banished).with(" + mail + ", " + username + ", true, false).where(username = 'na2axl')");
truncate()

Reset the table users

  1. db.query("users.truncate()");
count()

Count all banished users

  1. db.query("users.count(*).as(banished_nb).where(banished = true)");

Count all users and group by activated

  1. db.query("users.count(*).as(users_nb).group(activated)");

Query functions

sha1()

Returns the sha1 of a text. Exemple: Update an old password by a new one:

  1. var old_password = your_sha1_encrypt_function(form_data.old);
  2. var new_password = form_data.new;
  3. var query = db.prepare("users.insert(sha1(:new)).in(password).where(sha1(password) = :old)");
  4. query.bindValue(':new', new_password);
  5. query.bindValue(':old', old_password);
  6. query.execute();
md5()

Returns the md5 of a text. Exemple:

  1. var result = db.query("users.select(md5(username)).as(username_hash).where(username = 'na2axl')");
time()

Returns the timestamp.

now()

Returns the date of today in the form year-month-day h:m:s. You can change the form of the date by using identifiers as parameters:
| Identifier | Value |
|——————|———-|
| %a | The day in 3 letters (Mon) |
| %A | The full day (Monday) |
| %d | The day of the month with a leading zero (06) |
| %m | The month of the year with a leading zero (12) |
| %e | The month of the wear without a leading zero |
| %w | The day of the week without a leading zero |
| %W | The day of the week with a leading zero |
| %b | The month in 3 letters (Jan) |
| %B | The full month (January) |
| %y | The last two digits of the year (16) |
| %Y | The full year (2016) |
| %H | The hour with a leading 0 (09) |
| %k | The hour without a leading 0 (9) |
| %M | The minutes |
| %S | The seconds |
Exemple:

  1. db.query("users.update(last_acitity).with(now('%d/%m/%Y %H:%M:%S').where(username = 'na2axl'))");
lowercase()

Returns the lower case version of a text.

uppercase()

Returns the upper case version of a text.

ucfirst()

Upper case the first letter and lower case all others in a text.

strlen()

Returns the number of characters in a text.

Supported JQL operators

  • a = b : a equal to b
  • a != b : a different than b
  • a <> b : a different than b
  • a >= b : a superior or equal to b
  • a <= b : a inferior or equal to b
  • a < b : a inferior to b
  • a > b : a superior to b
  • a %= b : a % b === 0
  • a %! b : a % b !== 0

Full example

Sync version

  1. var JSONDB = require("jsondb-js");
  2. var jdb = new JSONDB();
  3. if (!jdb.serverExists('test')) {
  4. jdb.createServer('test', 'root', '');
  5. }
  6. var db = jdb.connect('test', 'root', '');
  7. if (!db.databaseExists('test_database')) {
  8. db.createDatabase('test_database');
  9. }
  10. db.setDatabase('test_database');
  11. if (!db.tableExists('users')) {
  12. db.createTable('users', { 'id': {'type': 'int', 'auto_increment': true, 'primary_key': true},
  13. 'name': {'type': 'string', 'max_length': 30, 'not_null': true},
  14. 'last_name': {'type': 'string', 'max_length': 30, 'not_null': true},
  15. 'username': {'type': 'string', 'max_length': 15, 'unique_key': true},
  16. 'mail': {'type': 'string', 'unique_key': true},
  17. 'password': {'type': 'string', 'not_null': true},
  18. 'website': {'type': 'string'},
  19. 'activated': {'type': 'bool', 'default': false},
  20. 'banished': {'type': 'bool', 'default': false} });
  21. }
  22. // A prepared query
  23. var query = db.prepare("users.insert(:name, :sname, :username, :mail, sha1(:pass)).in(name, last_name, username, mail, password)");
  24. query.bindValue(':name', 'Nana', JSONDB.PARAM_STRING);
  25. query.bindValue(':sname', 'Axel', JSONDB.PARAM_STRING);
  26. query.bindValue(':username', 'na2axl', JSONDB.PARAM_STRING);
  27. query.bindValue(':mail', 'ax.lnana@outlook.com', JSONDB.PARAM_STRING);
  28. query.bindValue(':pass', '00%a_ComPLEx-PassWord%00', JSONDB.PARAM_STRING);
  29. query.execute();
  30. // After some insertions...
  31. // Select all users
  32. var results = db.query('users.select(id, name, last_name, username)');
  33. // Fetch with class mapping
  34. var User = function () {};
  35. User.prototype.id = 0;
  36. User.prototype.name = '';
  37. User.prototype.last_name = '';
  38. User.prototype.username = '';
  39. User.prototype.getInfo = function () {
  40. return "The user with ID: " + this.id + "has the name: " + this.name + " " + this.last_name + " and the username " + this.username + ".";
  41. };
  42. while (result = results.fetch(JSONDB.FETCH_CLASS, User)) {
  43. console.log(result.getInfo());
  44. }

Async version

  1. var JSONDB = require("jsondb-js");
  2. var jdb = new JSONDB();
  3. // Class used for mapping
  4. var User = function () {};
  5. User.prototype.id = 0;
  6. User.prototype.name = '';
  7. User.prototype.last_name = '';
  8. User.prototype.username = '';
  9. User.prototype.getInfo = function () {
  10. return "The user with ID: " + this.id + " has the name: " + this.name + " " + this.last_name + " and the username " + this.username + ".";
  11. };
  12. jdb.async.serverExists('test', function (exists) {
  13. if (!exists) {
  14. jdb.createServer('test', 'root', '');
  15. }
  16. jdb.async.connect('test', 'root', '', function (error, db) {
  17. if (error) {
  18. throw error;
  19. }
  20. db.async.databaseExists('test_database', function (exists) {
  21. if (!exists) {
  22. db.createDatabase('test_database');
  23. }
  24. db.setDatabase('test_database');
  25. db.async.tableExists('users', function (exists) {
  26. if (!exists) {
  27. db.createTable('users', { 'id': {'type': 'int', 'auto_increment': true, 'primary_key': true},
  28. 'name': {'type': 'string', 'max_length': 30, 'not_null': true},
  29. 'last_name': {'type': 'string', 'max_length': 30, 'not_null': true},
  30. 'username': {'type': 'string', 'max_length': 15, 'unique_key': true},
  31. 'mail': {'type': 'string', 'unique_key': true},
  32. 'password': {'type': 'string', 'not_null': true},
  33. 'website': {'type': 'string'},
  34. 'activated': {'type': 'bool', 'default': false},
  35. 'banished': {'type': 'bool', 'default': false} });
  36. }
  37. // A prepared query
  38. db.async.prepare("users.insert(:name, :sname, :username, :mail, sha1(:pass)).in(name, last_name, username, mail, password)", function (error, query) {
  39. if (error) {
  40. throw error;
  41. }
  42. query.bindValue(':name', 'Nana', JSONDB.PARAM_STRING);
  43. query.bindValue(':sname', 'Axel', JSONDB.PARAM_STRING);
  44. query.bindValue(':username', 'na2axl', JSONDB.PARAM_STRING);
  45. query.bindValue(':mail', 'ax.lnana@outlook.com', JSONDB.PARAM_STRING);
  46. query.bindValue(':pass', '00%a_ComPLEx-PassWord%00', JSONDB.PARAM_STRING);
  47. query.async.execute(function (error , result) {
  48. if (error) {
  49. throw error;
  50. }
  51. // Is an insert() query, so result is a boolean...
  52. // After some insertions...
  53. // Select all users
  54. db.async.query('users.select(id, name, last_name, username)', function (error, results) {
  55. if (error) {
  56. throw error;
  57. }
  58. // Is an select() query, so results is a QueryResult object...
  59. results.async.fetch(JSONDB.FETCH_CLASS, User, function (error, current, next) {
  60. if (error) {
  61. throw error;
  62. }
  63. if (current !== false) {
  64. console.log(current.getInfo());
  65. next();
  66. }
  67. });
  68. });
  69. });
  70. });
  71. });
  72. });
  73. });
  74. });

After the execution of (one of) these scripts, the table users will be a .json file which will contain:

  1. {
  2. "prototype": ["#rowid","id","name","last_name","username","mail","password","website","activated","banished"],
  3. "properties": {
  4. "last_insert_id":1,
  5. "last_valid_row_id":1,
  6. "last_link_id":1,
  7. "primary_keys":["id"],
  8. "unique_keys":["id","username","mail"],
  9. "id": {
  10. "type":"int",
  11. "auto_increment":true,
  12. "primary_key":true,
  13. "unique_key":true,
  14. "not_null":true
  15. },
  16. "name": {
  17. "type":"string",
  18. "max_length":30,
  19. "not_null":true
  20. },
  21. "last_name": {
  22. "type":"string",
  23. "max_length":30,
  24. "not_null":true
  25. },
  26. "username": {
  27. "type":"string",
  28. "max_length":15,
  29. "unique_key":true,
  30. "not_null":true
  31. },
  32. "mail": {
  33. "type":"string",
  34. "unique_key":true,
  35. "not_null":true
  36. },
  37. "password": {
  38. "type":"string",
  39. "not_null":true
  40. },
  41. "website": {
  42. "type":"string"
  43. },
  44. "activated": {
  45. "type":"bool",
  46. "default":false
  47. },
  48. "banished": {
  49. "type":"bool",
  50. "default":false
  51. }
  52. },
  53. "data": {
  54. "#1": {
  55. "#rowid":1,
  56. "id":1,
  57. "name":"Nana",
  58. "last_name":"Axel",
  59. "username":"na2axl",
  60. "mail":"ax.lnana@outlook.com",
  61. "password":"589d3c90f3f75752673ab0ccb2690832f2e15610",
  62. "website":null,
  63. "activated":false,
  64. "banished":false
  65. }
  66. }
  67. }

Contribution

Found a bug? Have a feature request? Want to contribute to this project? Please, feel free to create
a new issue on GitHub, or fork this code, hack it,
and make a pull request !

Authors

Contributors

No one… maybe you !

(c) 2016 Centers Technologies. Licensed under GPL-3.0 (read license).