All Projects → archangel-irk → storage

archangel-irk / storage

Licence: MIT license
Mongoose-like schema validation, collections and documents on browser (client-side)

Programming Languages

HTML
75241 projects
javascript
184084 projects - #8 most used programming language
Makefile
30231 projects

Projects that are alternatives of or similar to storage

Ngx Indexed Db
A service that wraps IndexedDB database in an Angular service. It exposes very simple observables API to enable the usage of IndexedDB without most of it plumbing.
Stars: ✭ 84 (+394.12%)
Mutual labels:  schema, storage
Mongoose Patch History
Mongoose plugin that saves a history of JSON patch operations for all documents belonging to a schema in an associated 'patches' collection
Stars: ✭ 82 (+382.35%)
Mutual labels:  schema, mongoose
Sleekdb
Pure PHP NoSQL database with no dependency. Flat file, JSON based document database.
Stars: ✭ 450 (+2547.06%)
Mutual labels:  schema, storage
querymen
Querystring parser middleware for MongoDB, Express and Nodejs (MEN)
Stars: ✭ 128 (+652.94%)
Mutual labels:  schema, mongoose
mongoose-morgan
An npm package for saving morgan log inside MongoDB
Stars: ✭ 14 (-17.65%)
Mutual labels:  mongoose
mconfig
a lightweight distributed configuration center
Stars: ✭ 13 (-23.53%)
Mutual labels:  storage
ng-nest-cnode
Angular 10 Front-End and Nestjs 7 framework Back-End build Fullstack CNode
Stars: ✭ 17 (+0%)
Mutual labels:  mongoose
Online-Examination-System
Technologies : React js, Node js, Express js, Mongo Db, Ant Design, Redux js Key features: 1. User management 2. Modular code 3. Permission management 4. Persistent answers on page refresh in the test portal 5. Examination results using graphs 6. Results can directly be downloaded as excel sheet 7. Feedback system
Stars: ✭ 37 (+117.65%)
Mutual labels:  mongoose
aircnc
☕ Airbnb like (Air Coffee & Code) to booking spots for developers using ReactJS, React Native, Node.js and more.
Stars: ✭ 37 (+117.65%)
Mutual labels:  mongoose
gcp-storage-emulator
Local emulator for Google Cloud Storage
Stars: ✭ 43 (+152.94%)
Mutual labels:  storage
storage-box
Intuitive and easy-to-use storage box.
Stars: ✭ 26 (+52.94%)
Mutual labels:  storage
mini-express-boilerplate
A minimal Express boilerplate with passport user authentication, mongoose and some security setup configured
Stars: ✭ 15 (-11.76%)
Mutual labels:  mongoose
WordNook
Dynamically updating blogging website to upload articles and blog posts on various topics, developed using ejs template engine and node js in the backend.
Stars: ✭ 80 (+370.59%)
Mutual labels:  mongoose
laravel-ovh
Wrapper for OVH Object Storage integration with laravel
Stars: ✭ 30 (+76.47%)
Mutual labels:  storage
azure-storage
Azure Storage module for Nest framework (node.js) ☁️
Stars: ✭ 71 (+317.65%)
Mutual labels:  storage
beegfs-csi-driver
The BeeGFS Container Storage Interface (CSI) driver provides high performing and scalable storage for workloads running in Kubernetes.
Stars: ✭ 32 (+88.24%)
Mutual labels:  storage
schema.tl
📜 Easy-to-use TL-Schema viewer
Stars: ✭ 55 (+223.53%)
Mutual labels:  schema
storage
Multi-Factor Least Squares Monte Carlo energy storage valuation model (Python and .NET).
Stars: ✭ 24 (+41.18%)
Mutual labels:  storage
storage-abstraction
Provides an abstraction layer for interacting with a storage; the storage can be local or in the cloud.
Stars: ✭ 36 (+111.76%)
Mutual labels:  storage
to-json-schema
Converts JS objects to JSON Schema
Stars: ✭ 83 (+388.24%)
Mutual labels:  schema

Storage

Gitter Build Status Sauce Test Status Code Climate Coverage Status

Use mongoose-like schema validation, collections and documents on browser.

The library provides the most complete compatibility with mongoose.

Sauce Test Status

Documentation

API reference

Differences from mongoose

  1. Discriminator (Schema Inheritance)
  2. Saving documents.

Installation

Dependencies:

  • lodash
<script src="lodash.js"></script>
<script src="storage.js"></script>

Usage

Defining your schema

Everything in Storage starts with a Schema. Each schema maps to a Storage collection and defines the shape of the documents within that collection.

var userSchema = new Schema('User', {
  name: { type: String, required: true }
});

// or

var blogSchema = new Schema('Blog', {
  title:  String,
  author: String,
  body:   String,
  comments: [{ body: String, date: Date }],
  date: { type: Date, default: Date.now },
  hidden: Boolean,
  meta: {
    votes: Number,
    favs:  Number
  }
});

If you want to add additional keys later, use the Schema#add method.

Each key in our blogSchema defines a property in our documents which will be cast to its associated SchemaType. For example, we've defined a title which will be cast to the String SchemaType and date which will be cast to a Date SchemaType. Keys may also be assigned nested objects containing further key/type definitions (e.g. the meta property above).

The permitted SchemaTypes are

  • String
  • Number
  • Date
  • Buffer
  • Boolean
  • Mixed
  • ObjectId
  • Array

Schemas not only define the structure of your document and casting of properties, they also define document instance methods and static methods.

Create a collection

storage.createCollection('users', userSchema );

Create a document

var user = storage.users.add({name: 'Constantine'});

console.log( user.name );  // "Constantine"

Create a document without collection

var userSchema = new Schema('User', {
  name: { type: String, required: true }
});
var user = storage.Document({name: 'Constantine'}, userSchema );

console.log( user.name );  // "Constantine"

Create an empty document without collection

var userSchema = new Schema('User', {
   name: { type: String, required: true }
});
var user = storage.Document( userSchema );

console.log( user.name );  // undefined

Validation

user.name = undefined;

user.validate(function( err ){
  if ( err ) {
    console.log( err ); // ValidationError object
  }
});

Validation sync

Executes registered validation rules (skipping asynchronous validators) for this document.

doc.validateSync(); // Return StorageError if there are errors during validation, or undefined if there is no error.

Saving documents

doc.save(doneCallback); // Return Deferred (jquery like deferred) object.

Use .then(), .fail(), .done(), .always() methods.

doc.save().fail(function(err){
  console.log(err); // Return StorageError object.
});

Convert document into a plain javascript object, ready for send to server.

doc.save(function(plainDoc){
  console.log(plainDoc);
});

Virtuals

Virtuals are document properties that you can get and set but that do not get persisted to Storage. The getters are useful for formatting or combining fields, while settings are useful for de-composing a single value into multiple values for storage.

// define a schema
var personSchema = new Schema({
  name: {
    first: String,
    last: String
  }
});

// create our collection
var persons = storage.createCollection('Person', personSchema);

// create a document
var bad = persons.add({
    name: { first: 'Walter', last: 'White' }
});

Suppose we want to log the full name of bad. We could do this manually like so:

console.log(bad.name.first + ' ' + bad.name.last); // Walter White

Or we could define a virtual property getter on our personSchema so we don't need to write out this string concatenation mess each time:

personSchema.virtual('name.full').get(function () {
  return this.name.first + ' ' + this.name.last;
});

Now, when we access our virtual "name.full" property, our getter function will be invoked and the value returned:

console.log('%s is insane', bad.name.full); // Walter White is insane

Note that if the resulting record is converted to an object or JSON, virtuals are not included by default. Pass virtuals : true to either toObject() or to toJSON() to have them returned.

It would also be nice to be able to set this.name.first and this.name.last by setting this.name.full. For example, if we wanted to change bad's name.first and name.last to 'Breaking' and 'Bad' respectively, it'd be nice to just:

bad.name.full = 'Breaking Bad';

Storage lets you do this as well through its virtual property setters:

personSchema.virtual('name.full').set(function (name) {
  var split = name.split(' ');
  this.name.first = split[0];
  this.name.last = split[1];
});

...

bad.name.full = 'Breaking Bad';
console.log(bad.name.first); // Breaking
console.log(bad.name.last);  // Bad

Virtual property setters are applied before other validation. So the example above would still work even if the first and last name fields were required.

Schema options

Schema's have a few configurable options which can be passed to the constructor or set directly:

new Schema(<name>, {..}, <options>);

// or

var schema = new Schema(<name>, {..});
schema.set(option, value);

Valid options:

  • id
  • _id
  • strict
  • minimize
  • toJSON
  • toObject
  • versionKey
  • discriminatorKey

option: id

Storage assigns each of your schemas an id virtual getter by default which returns the documents _id field cast to a string, or in the case of ObjectIds, its hexString. If you don't want an id getter added to your schema, you may disable it passing this option at schema construction time.

// default behavior
var schema = new Schema({ name: String });
var pages = storage.createCollection('Page', schema);
var p = pages.add({ name: 'mongodb.org' });
console.log(p.id); // '50341373e894ad16347efe01'

// disabled id
var schema = new Schema({ name: String }, { id: false });
var pages = storage.createCollection('Page', schema);
var p = pages.add({ name: 'mongodb.org' });
console.log(p.id); // undefined

option: _id

Storage assigns each of your schemas an _id field by default if one is not passed into the Schema constructor. The type assiged is an ObjectId to coincide with MongoDBs default behavior. If you don't want an _id added to your schema at all, you may disable it using this option.

Pass this option during schema construction to prevent documents from getting an _id created by Storage (parent documents will still have an _id). Passing the option later using Schema.set('_id', false) will not work. See issue #1512.

// default behavior
var schema = new Schema({ name: String });
var pages = storage.createCollection('Page', schema);
var p = pages.add({ name: 'mongodb.org' });
console.log(p); // { _id: '50341373e894ad16347efe01', name: 'mongodb.org' }

// disabled _id
var schema = new Schema({ name: String }, { _id: false });

// Don't set _id to false after schema construction as in
// var schema = new Schema({ name: String });
// schema.set('_id', false);

var pages = storage.createCollection('Page', schema);
var p = pages.add({ name: 'mongodb.org' });
console.log(p); // { name: 'mongodb.org' }

Note that currently you must disable the _id

option: strict

The strict option, (enabled by default), ensures that values passed to our document constructor that were not specified in our schema do not get saved to the document.

var thingSchema = new Schema({..})
var things = storage.createCollection('Thing', thingSchema);
var thing = things.add({ iAmNotInTheSchema: true });
console.log( thing.iAmNotInTheSchema ); // undefined

// set to false..
var thingSchema = new Schema({..}, { strict: false });
var thing = things.add({ iAmNotInTheSchema: true });
console.log( thing.iAmNotInTheSchema ); // undefined
console.log( thing.toObject() ); // Object {iAmNotInTheSchema: true, _id: ObjectId}

This also affects the use of doc.set() to set a property value.

var thingSchema = new Schema({..})
var things = storage.createCollection('Thing', thingSchema);
var thing = things.add();
thing.set('iAmNotInTheSchema', true);
console.log( thing.toObject() ); // Object {iAmNotInTheSchema: true, _id: ObjectId}

This value can be overridden at the model instance level by passing a second boolean argument:

var things = storage.createCollection('Thing');
var thing = things.add(doc, true);  // enables strict mode
var thing = things.add(doc, false); // disables strict mode

The strict option may also be set to "throw" which will cause errors to be produced instead of dropping the bad data.

NOTE: do not set to false unless you have good reason.

NOTE: Any key/val set on the instance that does not exist in your schema is always ignored, regardless of schema option.

var thingSchema = new Schema({..})
var things = storage.createCollection('Thing', thingSchema);
var thing = things.add();
thing.iAmNotInTheSchema = true;
console.log( thing.iAmNotInTheSchema ); // true
console.log( thing.toObject() ); // Object {_id: ObjectId}

option: toJSON

Exactly the same as the toObject option but only applies when the documents toJSON method is called.

var schema = new Schema({ name: String });
schema.path('name').get(function (v) {
  return v + ' is my name';
});
schema.set('toJSON', { getters: true, virtuals: false });
var persons = storage.createCollection('Person', schema);
var person = persons.add({ name: 'Max Headroom' });
console.log( person.toObject() ); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom' }
console.log( person.toJSON() ); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }
// since we know toJSON is called whenever a js object is stringified:
console.log(JSON.stringify( person )); // { "_id": "504e0cd7dd992d9be2f20b6f", "name": "Max Headroom is my name" }

option: toObject

Documents have a toObject method which converts the mongoose document into a plain javascript object. This method accepts a few options. Instead of applying these options on a per-document basis we may declare the options here and have it applied to all of this schemas documents by default.

To have all virtuals show up in your console.log output, set the toObject option to { getters: true }:

var schema = new Schema({ name: String });
schema.path('name').get(function (v) {
  return v + ' is my name';
});
schema.set('toObject', { getters: true });
var persons = storage.createCollection('Person', schema);
var person = persons.add({ name: 'Max Headroom' });
console.log( person.toObject() ); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }

Storage has Schema Inheritance via Discriminator functionality:

// in Storage
var PersonSchema = new Schema('Person', {
  name: String,
  createdAt: Date
});

var BossSchema = new Schema('Boss', PersonSchema, { department: String });

// in Mongoose
function BaseSchema() {
  Schema.apply(this, arguments);

  this.add({
    name: String,
    createdAt: Date
  });
}
util.inherits(BaseSchema, Schema);

var PersonSchema = new BaseSchema();
var BossSchema = new BaseSchema({ department: String });

var Person = mongoose.model('Person', PersonSchema);
var Boss = Person.discriminator('Boss', BossSchema);

Differences from mongoose: since we have no models, the discriminator is implemented inside of the schemes, this allows the use of more pleasant syntax.

Building from sources

  1. Clone the repo from GitHub

     git clone https://github.com/archangel-irk/storage.git
     cd storage
    
  2. Acquire build dependencies. Make sure you have Node.js installed on your workstation. Now run:

     npm install -g grunt-cli
     npm install
    

    The first npm command sets up the popular Grunt build tool. You might need to run this command with sudo if you're on Linux or Mac OS X, or in an Administrator command prompt on Windows. The second npm command fetches the remaining build dependencies.

  3. Run the build and test tools

     grunt
    

    Now you'll find the built file in dist/storage.js.

Running the tests

After npm install you have the karma test runner locally, now run:

grunt test

Also you can see the code coverage in test/coverage/.

License

MIT license - http://www.opensource.org/licenses/mit-license.php

Todo

  • It was written that the discriminator is implemented incompletely, check it out.
  • collection.find() by discriminatorKey (see mongoose query.js prepareDiscriminatorCriteria method)
  • eng docs for schema inheritance (discriminator)
  • assert.ifError(err) -> move to .fail(function( err ){});
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].