add jsonapi datastore

wechat_user_type
Ge Hao 8 years ago
parent 6b765db2f5
commit 053d5d94a4
  1. 21
      node_modules/jsonapi-datastore/LICENSE.md
  2. 187
      node_modules/jsonapi-datastore/README.md
  3. 264
      node_modules/jsonapi-datastore/dist/jsonapi-datastore.js
  4. 112
      node_modules/jsonapi-datastore/package.json

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Lucas Hosseini
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,187 @@
# jsonapi-datastore
[![Build Status](https://travis-ci.org/beauby/jsonapi-datastore.svg)](https://travis-ci.org/beauby/jsonapi-datastore)
JavaScript client-side [JSON API](http://jsonapi.org) data handling made easy.
Current version is v0.4.0-beta. It is still a work in progress, but should do what it says.
## Description
The [JSONAPI](http://jsonapi.org) standard is great for exchanging data (which is its purpose), but the format is not ideal to work directly with in an application.
jsonapi-datastore is a JavaScript framework-agnostic library (but an [AngularJS version](#angularjs) is provided for convenience) that takes away the burden of handling [JSONAPI](http://jsonapi.org) data on the client side.
What it does:
- read JSONAPI payloads,
- rebuild the underlying data graph,
- allows you to query models and access their relationships directly,
- create new models,
- serialize models for creation/update.
What it does not do:
- make requests to your API. You design your endpoints URLs, the way you handle authentication, caching, etc. is totally up to you.
## Installing
Install jsonapi-datastore with `bower` by running:
```
$ bower install jsonapi-datastore
```
or with `npm` by running:
```
$ npm install jsonapi-datastore
```
## Parsing data
Just call the `.sync()` method of your store.
```javascript
var store = new JsonApiDataStore();
store.sync(data);
```
This parses the data and incorporates it in the store, taking care of already existing records (by updating them) and relationships.
## Parsing with meta data
If you have meta data in your payload use the `.syncWithMeta` method of your store.
```javascript
var store = new JsonApiDataStore();
store.syncWithMeta(data);
```
This does everything that `.sync()` does, but returns an object with data and meta split.
## Retrieving models
Just call the `.find(type, id)` method of your store.
```javascript
var article = store.find('article', 123);
```
or call the `.findAll(type)` method of your store to get all the models of that type.
```javascript
var articles = store.findAll('article');
```
All the attributes *and* relationships are accessible through the model as object properties.
```javascript
console.log(article.author.name);
```
In case a related resource has not been fetched yet (either as a primary resource or as an included resource), the corresponding property on the model will contain only the `type` and `id` (and the `._placeHolder` property will be set to `true`). However, the models are *updated in place*, so you can fetch a related resource later, and your data will remain consistent.
## Serializing data
Just call the `.serialize()` method on the model.
```javascript
console.log(article.serialize());
```
## Examples
```javascript
// Create a store:
var store = new JsonApiDataStore();
// Then, given the following payload, containing two `articles`, with a related `user` who is the author of both:
var payload = {
data: [{
type: 'article',
id: 1337,
attributes: {
title: 'Cool article'
},
relationships: {
author: {
data: {
type: 'user',
id: 1
}
}
}
}, {
type: 'article',
id: 300,
attributes: {
title: 'Even cooler article'
},
relationships: {
author: {
data: {
type: 'user',
id: 1
}
}
}
}]
};
// we can sync it:
var articles = store.sync(payload);
// which will return the list of synced articles.
// Later, we can retrieve one of those:
var article = store.find('article', 1337);
// If the author resource has not been synced yet, we can only access its id and its type:
console.log(article.author);
// { id: 1, _type: 'article' }
// If we do sync the author resource later:
var authorPayload = {
data: {
type: 'user',
id: 1,
attributes: {
name: 'Lucas'
}
}
};
store.sync(authorPayload);
// we can then access the author's name through our old `article` reference:
console.log(article.author.name);
// 'Lucas'
// We can also serialize any whole model in a JSONAPI-compliant way:
console.log(article.serialize());
// ...
// or just a subset of its attributes/relationships:
console.log(article.serialize({ attributes: ['title'], relationships: []}));
// ...
```
## Documentation
See [DOCUMENTATION.md](DOCUMENTATION.md).
## What's missing
Currently, the store does not handle `links` attributes or resource-level or relationship-level meta.
## Notes
### AngularJS
jsonapi-datastore is bundled with an AngularJs wrapper. Just include `ng-jsonapi-datastore.js` in your `index.html` and require the module `beauby.jsonApiDataStore` in your application.
You can then use the `JsonApiDataStore` factory, which is essentially defined as follows:
```javascript
{
store: new JsonApiDataStore(),
Model: JsonApiDataStoreModel
}
```
so that you can use it as follows:
```javascript
angular
.module('myApp')
.controller('myController', function(JsonApiDataStore) {
var article = JsonApiDataStore.store.find('article', 1337);
var newArticle = new JsonApiDataStore.Model('article');
newArticle.setAttribute('title', 'My cool article');
console.log(newArticle.serialize());
});
```
## Contributing
All pull-requests welcome!

@ -0,0 +1,264 @@
/**
* @class JsonApiDataStoreModel
*/
"use strict";
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var JsonApiDataStoreModel = (function () {
/**
* @method constructor
* @param {string} type The type of the model.
* @param {string} id The id of the model.
*/
function JsonApiDataStoreModel(type, id) {
_classCallCheck(this, JsonApiDataStoreModel);
this.id = id;
this._type = type;
this._attributes = [];
this._relationships = [];
}
/**
* @class JsonApiDataStore
*/
/**
* Serialize a model.
* @method serialize
* @param {object} opts The options for serialization. Available properties:
*
* - `{array=}` `attributes` The list of attributes to be serialized (default: all attributes).
* - `{array=}` `relationships` The list of relationships to be serialized (default: all relationships).
* @return {object} JSONAPI-compliant object
*/
_createClass(JsonApiDataStoreModel, [{
key: "serialize",
value: function serialize(opts) {
var self = this,
res = { data: { type: this._type } },
key;
opts = opts || {};
opts.attributes = opts.attributes || this._attributes;
opts.relationships = opts.relationships || this._relationships;
if (this.id !== undefined) res.data.id = this.id;
if (opts.attributes.length !== 0) res.data.attributes = {};
if (opts.relationships.length !== 0) res.data.relationships = {};
opts.attributes.forEach(function (key) {
res.data.attributes[key] = self[key];
});
opts.relationships.forEach(function (key) {
function relationshipIdentifier(model) {
return { type: model._type, id: model.id };
}
if (!self[key]) {
res.data.relationships[key] = { data: null };
} else if (self[key].constructor === Array) {
res.data.relationships[key] = {
data: self[key].map(relationshipIdentifier)
};
} else {
res.data.relationships[key] = {
data: relationshipIdentifier(self[key])
};
}
});
return res;
}
/**
* Set/add an attribute to a model.
* @method setAttribute
* @param {string} attrName The name of the attribute.
* @param {object} value The value of the attribute.
*/
}, {
key: "setAttribute",
value: function setAttribute(attrName, value) {
if (this[attrName] === undefined) this._attributes.push(attrName);
this[attrName] = value;
}
/**
* Set/add a relationships to a model.
* @method setRelationship
* @param {string} relName The name of the relationship.
* @param {object} models The linked model(s).
*/
}, {
key: "setRelationship",
value: function setRelationship(relName, models) {
if (this[relName] === undefined) this._relationships.push(relName);
this[relName] = models;
}
}]);
return JsonApiDataStoreModel;
})();
var JsonApiDataStore = (function () {
/**
* @method constructor
*/
function JsonApiDataStore() {
_classCallCheck(this, JsonApiDataStore);
this.graph = {};
}
/**
* Remove a model from the store.
* @method destroy
* @param {object} model The model to destroy.
*/
_createClass(JsonApiDataStore, [{
key: "destroy",
value: function destroy(model) {
delete this.graph[model._type][model.id];
}
/**
* Retrieve a model by type and id. Constant-time lookup.
* @method find
* @param {string} type The type of the model.
* @param {string} id The id of the model.
* @return {object} The corresponding model if present, and null otherwise.
*/
}, {
key: "find",
value: function find(type, id) {
if (!this.graph[type] || !this.graph[type][id]) return null;
return this.graph[type][id];
}
/**
* Retrieve all models by type.
* @method findAll
* @param {string} type The type of the model.
* @return {object} Array of the corresponding model if present, and empty array otherwise.
*/
}, {
key: "findAll",
value: function findAll(type) {
var self = this;
if (!this.graph[type]) return [];
return Object.keys(self.graph[type]).map(function (v) {
return self.graph[type][v];
});
}
/**
* Empty the store.
* @method reset
*/
}, {
key: "reset",
value: function reset() {
this.graph = {};
}
}, {
key: "initModel",
value: function initModel(type, id) {
this.graph[type] = this.graph[type] || {};
this.graph[type][id] = this.graph[type][id] || new JsonApiDataStoreModel(type, id);
return this.graph[type][id];
}
}, {
key: "syncRecord",
value: function syncRecord(rec) {
var self = this,
model = this.initModel(rec.type, rec.id),
key;
function findOrInit(resource) {
if (!self.find(resource.type, resource.id)) {
var placeHolderModel = self.initModel(resource.type, resource.id);
placeHolderModel._placeHolder = true;
}
return self.graph[resource.type][resource.id];
}
delete model._placeHolder;
for (key in rec.attributes) {
model._attributes.push(key);
model[key] = rec.attributes[key];
}
if (rec.relationships) {
for (key in rec.relationships) {
var rel = rec.relationships[key];
if (rel.data !== undefined) {
model._relationships.push(key);
if (rel.data === null) {
model[key] = null;
} else if (rel.data.constructor === Array) {
model[key] = rel.data.map(findOrInit);
} else {
model[key] = findOrInit(rel.data);
}
}
if (rel.links) {
console.log("Warning: Links not implemented yet.");
}
}
}
return model;
}
/**
* Sync a JSONAPI-compliant payload with the store and return any metadata included in the payload
* @method syncWithMeta
* @param {object} data The JSONAPI payload
* @return {object} The model/array of models corresponding to the payload's primary resource(s) and any metadata.
*/
}, {
key: "syncWithMeta",
value: function syncWithMeta(payload) {
var primary = payload.data,
syncRecord = this.syncRecord.bind(this);
if (!primary) return [];
if (payload.included) payload.included.map(syncRecord);
return {
data: primary.constructor === Array ? primary.map(syncRecord) : syncRecord(primary),
meta: "meta" in payload ? payload.meta : null
};
}
/**
* Sync a JSONAPI-compliant payload with the store.
* @method sync
* @param {object} data The JSONAPI payload
* @return {object} The model/array of models corresponding to the payload's primary resource(s).
*/
}, {
key: "sync",
value: function sync(payload) {
return this.syncWithMeta(payload).data;
}
}]);
return JsonApiDataStore;
})();
if ('undefined' !== typeof module) {
module.exports = {
JsonApiDataStore: JsonApiDataStore,
JsonApiDataStoreModel: JsonApiDataStoreModel
};
}

@ -0,0 +1,112 @@
{
"_args": [
[
{
"raw": "jsonapi-datastore",
"scope": null,
"escapedName": "jsonapi-datastore",
"name": "jsonapi-datastore",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"/Users/liuxy/work/wechat_program_front"
]
],
"_from": "jsonapi-datastore@latest",
"_id": "jsonapi-datastore@0.4.0-beta",
"_inCache": true,
"_installable": true,
"_location": "/jsonapi-datastore",
"_nodeVersion": "0.12.7",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/jsonapi-datastore-0.4.0-beta.tgz_1458052797419_0.7578040463849902"
},
"_npmUser": {
"name": "beauby",
"email": "lucas.hosseini@gmail.com"
},
"_npmVersion": "2.13.5",
"_phantomChildren": {},
"_requested": {
"raw": "jsonapi-datastore",
"scope": null,
"escapedName": "jsonapi-datastore",
"name": "jsonapi-datastore",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"_requiredBy": [
"#USER"
],
"_resolved": "https://registry.npmjs.org/jsonapi-datastore/-/jsonapi-datastore-0.4.0-beta.tgz",
"_shasum": "b499fce924d45e2bc3c6178681520063e2361f10",
"_shrinkwrap": null,
"_spec": "jsonapi-datastore",
"_where": "/Users/liuxy/work/wechat_program_front",
"author": {
"name": "Lucas Hosseini",
"email": "lucas.hosseini@gmail.com"
},
"bugs": {
"url": "https://github.com/beauby/jsonapi-datastore/issues"
},
"dependencies": {},
"description": "JavaScript client-side JSON API data handling made easy.",
"devDependencies": {
"babel": "^5.8.23",
"chai": "^3.2.0",
"gulp": "^3.9.0",
"gulp-babel": "^5.2.1",
"gulp-concat": "^2.6.0",
"gulp-jsbeautify": "^0.1.1",
"gulp-jscs": "^2.0.0",
"gulp-jshint": "^1.11.2",
"gulp-markdox": "^0.1.1",
"gulp-mocha": "^2.1.3",
"gulp-rename": "^1.2.2",
"gulp-uglify": "^1.2.0",
"gulp-wrap": "^0.11.0",
"mocha": "^2.2.5"
},
"directories": {
"test": "test"
},
"dist": {
"shasum": "b499fce924d45e2bc3c6178681520063e2361f10",
"tarball": "https://registry.npmjs.org/jsonapi-datastore/-/jsonapi-datastore-0.4.0-beta.tgz"
},
"files": [
"dist/"
],
"gitHead": "56512d7be9b424cbd0da0a71acbed65eab14e042",
"homepage": "https://github.com/beauby/jsonapi-datastore#readme",
"keywords": [
"JSON",
"parsing",
"serializing",
"datastore",
"JSONAPI"
],
"license": "MIT",
"main": "dist/node-jsonapi-datastore.js",
"maintainers": [
{
"name": "beauby",
"email": "lucas.hosseini@gmail.com"
}
],
"name": "jsonapi-datastore",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/beauby/jsonapi-datastore.git"
},
"scripts": {
"test": "gulp test"
},
"version": "0.4.0-beta"
}
Loading…
Cancel
Save