133 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| Master Quest SQLite3
 | |
| ============
 | |
| 
 | |
| Master Quest is a brave new attempt at Data Mapping.
 | |
| 
 | |
| It kinda looks like an ORM, but it isn't. It's not SQL, it's NoSQL with benefits.
 | |
| 
 | |
| You get to choose which contraints to keep and which to forget.
 | |
| 
 | |
| Guiding Principles
 | |
| 
 | |
| * NoSQL (well, as far as you care)
 | |
| * Migrations don't suck
 | |
| * Harness the awesomeness of indexes
 | |
| * `deletedAt` to delete a record
 | |
| * `null` to delete a field
 | |
| * unindexed fields stored as json
 | |
| * ids should be one either
 | |
|   * deterministic (duplicate records not okay, last `updatedAt` wins)
 | |
|   * cryptographically random (duplicate records consolidated in application)
 | |
| * avoid mutating data (CRDT-ish style)
 | |
| * if it won't scale, don't fret it (no foreign key contraints)
 | |
| * `id` is simply named `id`
 | |
| * multi-key ids should be `sha256sum(key1 + key2 + key3)`
 | |
| * JavaScript is `camelCase`y, databases are `snake_case`y. We can handle that.
 | |
| * join tables are in alphabet order i.e. `foo`, `bar`, `bar_foo`
 | |
| 
 | |
| TODO / In Progress
 | |
| 
 | |
| * Multi-Master Replication
 | |
| * Relationships
 | |
|   * currently detaches before saving (most important)
 | |
| * MongoDB / RethinkDB -ish queries
 | |
| * RealTime
 | |
| 
 | |
| USAGE
 | |
| =====
 | |
| 
 | |
| ```bash
 | |
| npm install --save 'https://github.com/coolaj86/node-masterquest-sqlite3.git'
 | |
| ```
 | |
| 
 | |
| ```javascript
 | |
| 'use strict';
 | |
| 
 | |
| // works with sqlite3, sqlcipher, and sqlite3-cluster
 | |
| var db = new (require('sqlite3').Database)('/tmp/data.sqlite3');
 | |
| 
 | |
| require('masterquest-sqlite3').wrap(db, {
 | |
|   modelname: 'Persons'
 | |
| , indices: [ 'firstName', 'lastName' ]
 | |
| , hasMany: [ 'children' ]
 | |
| }).then(function (mq) {
 | |
| 
 | |
|   // update (or create) deterministic record
 | |
|   var john = {
 | |
|     id: 'john.doe@email.com'
 | |
|   , firstName: 'john'
 | |
|   , lastName: 'doe'
 | |
|   , dog: { name: 'ralph', color: 'gold' }
 | |
|   , children: [ 'stacey@email.com' ]
 | |
|   };
 | |
| 
 | |
|   mq.Persons.upsert(john.id, john).then(function () {
 | |
|     // note: if `dog` existed, it will be overwritten, not merged
 | |
|     // note: `children` will be removed before save
 | |
| 
 | |
|     mq.Persons.get('john.doe@email.com').then(function (data) {
 | |
|       // dog will be rehydrated from json
 | |
|       // children will not be fetched and attached
 | |
|       console.log(data);
 | |
|     });
 | |
| 
 | |
|   });
 | |
| 
 | |
| });
 | |
| ```
 | |
| 
 | |
| API
 | |
| ===
 | |
| 
 | |
| It's kinda CRUDdy... but don't let that scare you.
 | |
| 
 | |
| * `upsert(id, data[, oldId])` - creates or updates based on existence in DB (use this)
 | |
|   * modifies `createdAt` and or `updatedAt`
 | |
| * `create(id, obj)` - same as above, but fails if the object exists
 | |
| * `save(data[, oldId])` - (just don't use this, please) creates or updates based on presence of ID
 | |
| * `destroy(id)` - mark a record as `deletedAt` from DB
 | |
| * `get(id)` - grab one by id
 | |
| * `find(attrs, opts)` - grab many by indexable attributes
 | |
|   * attrs
 | |
|     * explicit `null` will find all (and requires that `limit` be set)
 | |
|     * `{ foo: 2, bar: 6 }` will find records where `foo` is `2` *and* `bar` is `6`
 | |
|   * opts
 | |
|     * `orderBy`
 | |
|     * `orderByDesc`
 | |
|     * `limit`
 | |
| 
 | |
| Schema
 | |
| ======
 | |
| 
 | |
| Anything that isn't in the schema
 | |
| 
 | |
| * `indices` specifies an array of strings
 | |
|   * `[ 'firstName', 'lastName' ]`
 | |
| * relationships are option and current only exclude during save
 | |
|   * `hasMany`, `belongsTo`, `hasOne`, `belongsToMany`, `hasAndBelongsToMany`
 | |
| * `createdAt`, `updatedAt`, `deletedAt` timestamps are always added
 | |
|   * turn off with `timestamps: false`
 | |
| * `id` is always `id`
 | |
|   * change with `idname: 'myId'`
 | |
| 
 | |
| Migrations
 | |
| ----------
 | |
| 
 | |
| You can only add indexes. You cannot rename or remove them.
 | |
| 
 | |
| To add an index, simply change the schema.
 | |
| 
 | |
| ```javascript
 | |
| { modelname: 'persons'
 | |
| , indices: [ 'firstName', 'lastName' ]
 | |
| , hasMany: [ 'children' ]
 | |
| }
 | |
| ```
 | |
| 
 | |
| LICENSE
 | |
| =======
 | |
| 
 | |
| Dual-licensed MIT and Apache-2.0
 | |
| 
 | |
| See LICENSE
 |