{"_id":"perstore","_rev":"11-e90dd42a15ccb46aa76eccf316c6b59b","name":"perstore","dist-tags":{"latest":"0.3.3"},"versions":{"0.3.0":{"name":"perstore","version":"0.3.0","author":{"name":"Kris Zyp"},"email":"kriszyp@gmail.com","contributors":[{"name":"Vladimir Dronnikov","email":"dronnikov@gmail.com"}],"keywords":["persistence","object","store","persevere"],"maintainers":[{"name":"dojofoundation","email":"kzyp@dojofoundation.org"}],"engines":{"node":">=0.1.30","rhino":true},"mappings":{"tunguska":"http://github.com/kriszyp/tunguska/zipball/v0.2.2","rql":"jar:http://github.com/kriszyp/rql/zipball/v0.2.2!/","patr":"jar:http://github.com/kriszyp/patr/zipball/v0.2.2!/","promised-io":"jar:http://github.com/kriszyp/promised-io/zipball/v0.2.2!/","json-schema":"http://github.com/kriszyp/json-schema/zipball/v0.2.1","mysql-native":"jar:http://github.com/sidorares/nodejs-mysql-native/zipball/master!/lib/mysql-native/","mongodb":"jar:http://github.com/christkv/node-mongodb-native/zipball/V0.9.4.4!/lib/mongodb/"},"overlay":{"narwhal":{"mappings":{"fs-promise":"./engines/rhino/lib/fs-promise","store-engine":"./engines/rhino/lib/store-engine/"}},"node":{"mappings":{"store-engine":"./engines/node/lib/store-engine/"}}},"usesSystemModules":["path"],"licenses":[{"type":"AFLv2.1","url":"http://trac.dojotoolkit.org/browser/dojo/trunk/LICENSE#L43"},{"type":"BSD","url":"http://trac.dojotoolkit.org/browser/dojo/trunk/LICENSE#L13"}],"repository":{"type":"git","url":"git://github.com/kriszyp/tunguska.git"},"directories":{"lib":"."},"dependencies":{"tunguska":">=0.3.0","rql":">=0.3.1","promised-io":">=0.3.0","json-schema":">=0.2.1"},"devDependencies":{"patr":">0.2.6"},"jars":["jars/perstore.jar"],"_npmUser":{"name":"dojofoundation","email":"kzyp@dojofoundation.org"},"_id":"perstore@0.3.0","_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.0","_defaultsLoaded":true,"dist":{"shasum":"c84b99d9bf010236e950c16c8b20ac6696827f51","tarball":"https://registry.npmjs.org/perstore/-/perstore-0.3.0.tgz","integrity":"sha512-rgFOswEwIVJn++gvjrOBvqSABznXXk8unzK0ttCA9orHeUsrdlOJl6lB2up2HUEno3WgoavIzLjbiwGpdRs0TQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGKF3jOX6hMwqwuNG4iV6bGinr9ueYDZSXGGglI4TnLyAiBj9ESLaRRXeFQzSDMNwrAGs8yQLqLryOFvV+ARJk4FeA=="}]}},"0.3.1":{"name":"perstore","version":"0.3.1","author":{"name":"Kris Zyp"},"email":"kriszyp@gmail.com","contributors":[{"name":"Vladimir Dronnikov","email":"dronnikov@gmail.com"}],"keywords":["persistence","object","store","persevere"],"maintainers":[{"name":"dojofoundation","email":"kzyp@dojofoundation.org"}],"engines":{"node":">=0.1.30","rhino":true},"mappings":{"tunguska":"http://github.com/kriszyp/tunguska/zipball/v0.2.2","rql":"jar:http://github.com/kriszyp/rql/zipball/v0.2.2!/","patr":"jar:http://github.com/kriszyp/patr/zipball/v0.2.2!/","promised-io":"jar:http://github.com/kriszyp/promised-io/zipball/v0.2.2!/","json-schema":"http://github.com/kriszyp/json-schema/zipball/v0.2.1","mysql-native":"jar:http://github.com/sidorares/nodejs-mysql-native/zipball/master!/lib/mysql-native/","mongodb":"jar:http://github.com/christkv/node-mongodb-native/zipball/V0.9.4.4!/lib/mongodb/"},"overlay":{"narwhal":{"mappings":{"fs-promise":"./engines/rhino/lib/fs-promise","store-engine":"./engines/rhino/lib/store-engine/"}},"node":{"mappings":{"store-engine":"./engines/node/lib/store-engine/"}}},"usesSystemModules":["path"],"licenses":[{"type":"AFLv2.1","url":"http://trac.dojotoolkit.org/browser/dojo/trunk/LICENSE#L43"},{"type":"BSD","url":"http://trac.dojotoolkit.org/browser/dojo/trunk/LICENSE#L13"}],"repository":{"type":"git","url":"git://github.com/kriszyp/tunguska.git"},"directories":{"lib":"."},"dependencies":{"tunguska":">=0.3.0","rql":">=0.3.1","promised-io":">=0.3.0","json-schema":">=0.2.1"},"devDependencies":{"patr":">0.2.6"},"jars":["jars/perstore.jar"],"_npmUser":{"name":"dojofoundation","email":"kzyp@dojofoundation.org"},"_id":"perstore@0.3.1","_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.0","_defaultsLoaded":true,"dist":{"shasum":"0bebd508b1efe5abf26ad0832a978944a33b0517","tarball":"https://registry.npmjs.org/perstore/-/perstore-0.3.1.tgz","integrity":"sha512-ujs+aoHxnHJEiaCnbVEYpYOKvcA8syiFRffZlgxQKL/jrST+5XtICKjb/A18UiyBg6vgfVdI4+OahSO3WxVinQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFm8PTXs31lVcQzgh7DoLltrauuKl5+F08vINyu7NyRyAiAvw28sgX66dgYRBOofToudRG0Faj5/BQts5UUzmdfR5A=="}]}},"0.3.2":{"name":"perstore","version":"0.3.2","author":{"name":"Kris Zyp"},"email":"kriszyp@gmail.com","contributors":[{"name":"Vladimir Dronnikov","email":"dronnikov@gmail.com"}],"keywords":["persistence","object","store","persevere"],"maintainers":[{"name":"dojofoundation","email":"kzyp@dojofoundation.org"}],"engines":{"node":">=0.1.30","rhino":true},"mappings":{"tunguska":"http://github.com/kriszyp/tunguska/zipball/v0.2.2","rql":"jar:http://github.com/kriszyp/rql/zipball/v0.2.2!/","patr":"jar:http://github.com/kriszyp/patr/zipball/v0.2.2!/","promised-io":"jar:http://github.com/kriszyp/promised-io/zipball/v0.2.2!/","json-schema":"http://github.com/kriszyp/json-schema/zipball/v0.2.1","mysql-native":"jar:http://github.com/sidorares/nodejs-mysql-native/zipball/master!/lib/mysql-native/","mongodb":"jar:http://github.com/christkv/node-mongodb-native/zipball/V0.9.4.4!/lib/mongodb/"},"overlay":{"narwhal":{"mappings":{"fs-promise":"./engines/rhino/lib/fs-promise","store-engine":"./engines/rhino/lib/store-engine/"}},"node":{"mappings":{"store-engine":"./engines/node/lib/store-engine/"}}},"usesSystemModules":["path"],"licenses":[{"type":"AFLv2.1","url":"http://trac.dojotoolkit.org/browser/dojo/trunk/LICENSE#L43"},{"type":"BSD","url":"http://trac.dojotoolkit.org/browser/dojo/trunk/LICENSE#L13"}],"repository":{"type":"git","url":"http://github.com/kriszyp/tunguska"},"directories":{"lib":"."},"dependencies":{"tunguska":">=0.3.0","rql":">=0.3.1","promised-io":">=0.3.0","json-schema":">=0.2.1"},"devDependencies":{"patr":">0.2.6"},"jars":["jars/perstore.jar"],"readme":"Perstore is a cross-platform JavaScript object store interface for mapping persistent \r\nobjects to various different storage mediums using an interface based on\r\nW3C's [IndexedDB object store API](http://www.w3.org/TR/IndexedDB/#object-store-sync)\r\nand analogous to the HTTP REST interface. Perstore\r\nincludes JavaScript object-relational mapping for SQL databases, JSON file storage,\r\nand hopefully support for many other object/document style storage systems that\r\nprovide more direct object storage. Perstore provides model classes that wrap data\r\nstores, and supports JSON Schema integrity enforcement, link management, and \r\nprototype construction. Perstore also provides faceted access to models for an\r\nobject-capability based security model.\r\n\r\nSetup\r\n=====\r\n\r\nPerstore can be installed with NPM via:\r\n\r\n\tnpm install perstore\r\n\r\nHowever, one of the easiest way to get started with Perstore is to start with the \r\n[Persevere example app](http://github.com/persvr/persevere-example-wiki),\r\nwhich can be installed with:\r\n\r\n\tnpm install persevere-example-wiki\r\n\r\nPerstore can be installed in RingoJS likewise:\r\n\r\n\tringo-admin install persvr/perstore\r\n\r\nSee the [Persevere installation instructions for more information](http://persvr.org/Page/Installation).\r\n\r\nPerstore also requires a local.json file to be present in the current working directory.\r\nAn example of this file can be found [here](https://github.com/persvr/persevere-example-wiki/blob/master/local.json).\r\n\r\nModel\r\n=====\r\n\r\nPerstore provides the tools for building data models. With Perstore we can create data\r\nstores that connect to different database backends. We can then build on the basic\r\nstores with data model and facets that provide application logic, data constraints,\r\naccess definitions, data change responses, and queries. Typical usage of Perstore looks like:\r\n\r\n // first setup the object store, here we use SQL/ORM store\r\n var store = require(\"perstore/store/sql\").SQLStore({\r\n type: \"mysql\",\r\n table: \"my_table\",\r\n idColumn: \"id\"\r\n });\r\n \r\n // now we can setup a model that wraps the data store\r\n var MyModel = require(\"perstore/model\")(store, {\r\n \tproperties: {\r\n \t\t// we can define optionally define type constraints on properties\r\n \t\tfoo: String\r\n \t},\r\n \tprototype: {\r\n \t\t// we can define functions on the prototype of the model objects as well\r\n \t\tgetFoo: function(){\r\n \t\t\treturn this.foo;\r\n \t\t}\r\n \t}\r\n });\r\n // now we can interact with the store and it's objects\r\n var someObject = MyModel.get(someId); // retrieve a persisted object\r\n someObject.getFoo(); // returns the current value of foo\r\n someObject.foo = \"bar\"; // make a change\r\n someObject.save(); // and save it\r\n \r\n MyModel.delete(someOtherId); // delete an object\r\n \r\n var MyFacet = require(\"facet\").Restrictive(MyModel, {\r\n });\r\n\r\n\tMyFacet.delete(someId) -> will fail, as the facet has not allowed access to delete().\r\n\t\r\nA model is defined with the Model constructor in the \"MyModel\" module. A Model definition\r\nmay follow the JSON schema definition for contractual constraints (usually defining property\r\ntype constraints in the \"properties\" property and relations with the \"links\" property). \r\nproperty. It may also contain a \"prototype\" property which defines the prototype object\r\nfor all instances of the model. Methods can be defined on the prototype object, as well\r\nas directly on the model. REST methods such as get, put, and delete are implemented\r\ndirectly on the model, and can be overridden for specific functionality.\r\n \r\nPerstore provides easy to use object persistence mechanism. Persisted model object\r\ninstances have two default methods and a property:\r\n\r\n- save() - Saves any changes that have been made to an object to the data store.\r\n- load() - If the object has not been fully loaded (sometime queries may return partial\r\nobject), the object will be fully loaded from the data store.\r\n- schema - This is a reference to the schema for this object. Schema objects are augmented\r\n(if it does not previously exist) with a getId method that can be used to retrieve the identity \r\nof an object:\r\n\r\n object.schema.getId(object) -> identity of object\r\n\r\n\r\nIn the initial example, object persistence is demonstrated with the \"someObject\"\r\nvariable. The object is loaded (via the get call to the model), modified, and saved\r\n(with the save() call).\r\n\r\nFacets provide secure, controlled access to models. The facet module comes provides\r\ntwo facet constructors: Permissive and Restrictive. A Permissive facet allows all actions\r\non the model by default. Methods can be defined/overridden in the Permissive definition\r\nto control or disable access to certain functionality. A Restrictive facet only allows read\r\naccess methods by default (get and query). One can define/override methods to allow\r\nexplicit access to other methods such as put or create. An example facet that only\r\nallows read access and creation of new objects:\r\n\r\n var facet = require(\"facet\").Restrictive(model, {\r\n create: function(object){ // allow create\r\n return model.create(object);\r\n }\r\n });\r\n\r\nModels wrap data stores, which provide the low level interaction with the database or \r\nstorage system. Perstore comes with several data stores including (in the perstore/store directory)\r\nmongodb, redis, sql, memory, file, and HTTP/remote storage. Perstore also includes \r\nseveral store wrappers that can be used to compose more \r\nsophisticated stores by adding functionality (also in the store directory), including cache,\r\naggregate, replicated, and inherited. The store implementations and store wrappers\r\nare described in more detail in the modules section below.\r\n\r\nThe following is store API for Perstore. The same API is used for data stores, store \r\nmodels, and facets. All of the functions are optional. If they do not exist, it indicates \r\nthat the store or model does not support or allow the said functionality. All of the \r\nfunctions may return a promise instead of \r\nthe actual return value if they require asynchronous processing to complete the \r\noperation. They are roughly listed in order of importance:\r\n\r\nget(id, directives) - Finds the persisted record with the given identifier from the store and returns \r\nan object representation (should always be a new object).\r\n\r\nput(object, directives) - Stores the given object in storage. The record may or may not \r\nalready exist. The optional second parameter \r\ndefines the primary identifier for storing the object. If the second parameter is omitted, the\r\nkey may be specified the primary identifier property. If that is not specified, the key may be\r\nauto-generated. The primary identifer for the object should be returned\r\n\r\ndelete(id, directives) - Deletes the record with the given identifier from the store.\r\n\r\nquery(queryString, directives) - This executes a query against the data store. The \r\nqueryString parameter defines the actual query, and the options parameter should be\r\nan object that provides extra information. The following properties on the directives\r\nobject may be included:\r\n\r\n- start - The offset index to start at in the result set\r\n- end - The offset index to end at in the result set\r\n- parameters - An array of values for parameterized queries\r\n\r\nThe function should generally return an array representing the result set of the query \r\n(unless the query creates a single aggregate object or value). Perstore is designed to leverage [http://github.com/persvr/rql](resource query language)\r\nfor querying, and included stores use RQL (although they may not implement every\r\nfeature in RQL), although stores can utilize alternate query languages. \r\n\r\nadd(object, directives) - Stores a new record. This acts similar to put, but should only be called\r\nwhen the record does not already exist. Stores do not need to implement this \r\nmethod, but may implement for ease of differentiating between creation of new \r\nrecords and updates. This should return the identifier of the newly create record. If an\r\nobject already exists with the given identity, this should throw an error. \r\n\r\nconstruct(object, directives) - This constructs a new persistable object. This does not\r\nactually store the object, but returns an object with a save() method that\r\ncan be called to store the object when it is ready. This method does not apply to stores,\r\nonly models and facets.\r\n\r\nsubscribe(resource, callback) - Subscribes to changes in the given resource or set of \r\nresources. The callback is called whenever data is changed in the monitored resource(s).\r\n\r\ntransaction() - Starts a new transaction for the store. This should return\r\na transaction object with the following functions. Each of these functions are optional\r\nand only called if they exist:\r\n\r\n- commit() - This is called when a transaction is committed.\r\n- requestCommit() - This is called on all the databases/stores prior to committing the\r\ntransaction. If this succeeds (doesn't throw an error), the store should guarantee the\r\nsuccess of a subsequent commit() operation. This provides two phase commit \r\nsemantics. \r\n- abort() - This is called when a transaction is aborted.\r\n- suspend() - This is called when a transaction is suspended. This happens when an \r\nevent is finished, but a promise for the continuance of the action is still in progress. \r\nAfter being suspended, this transaction is no longer the active transaction.\r\n- resume() - This is called when a transaction is resumed. This happens when a promise\r\nresumes the execution of an action.\r\n\r\n(See Transactions section below for more information)\r\n\r\nPerstore is designed to allow easy construction of new data stores. A data store \r\nin Perstore is a JavaScript object with any or all of the functions defined above.\r\n\r\nQuerying\r\n========\r\n\r\nPerstore provides a query parsing and execution through [http://github.com/persvr/rql](resource query language) \r\n(RQL). RQL can be thought as basically a set of\r\nnestable named operators which each have a set of arguments. RQL is designed to\r\nhave an extremely simple, but extensible grammar that can be written in a URL friendly query string. A simple RQL\r\nquery with a single operator that indicates a search for any resources with a property of\r\n\"foo\" that has value of 3 could be written:\r\n\r\n eq(foo,3)\r\n\r\nRQL is a compatible superset of standard HTML form URL encoding. The following query\r\nis identical to the query (it is sugar for the query above):\r\n\r\n foo=3\r\n\r\nWe can use this query format to query stores and models. For example:\r\n\r\n MyModel.query(\"foo=3\").forEach(function(object){\r\n // for each object with a property of foo equal to 3\r\n });\r\n\r\nWe can also construct queries using chained operator calls in JavaScript. We could\r\nwrite this query:\r\n\r\n MyModel.query().eq(\"foo\",3).forEach(...);\r\n\r\nThe RQL grammar is based around standard URI delimiters. The standard rules for \r\nencoding strings with URL encoding (%xx) are observed. RQL also supersets FIQL. \r\nTherefore we can write a query that finds resources with a \"price\" property below\r\n10 with a \"lt\" operator using FIQL syntax:\r\n\r\n price=lt=10\r\n\r\nWhich is identical (and sugar for call operator syntax known as the normalized form):\r\n\r\n lt(price,10)\r\n\r\nOne can combine conditions with multiple operators with \"&\":\r\n\r\n foo=3&price=lt=10\r\n\r\nIs the same as:\r\n\r\n eq(foo,3)<(price,10)\r\n\r\nWhich is also the same as:\r\n\r\n and(eq(foo,3),lt(price,10))\r\n\r\nAnd thus can be used to query a store:\r\n\r\n\tMyModel.query(\"foo=3&price=lt=10\")...\r\n\r\nOr using chained JS calls to perform the same query:\r\n\r\n MyModel.query().eq(\"foo\",3).lt(\"price\",10)...\r\n\r\nThe | operator can be used to indicate an \"or\" operation. We can also use paranthesis\r\nto group expressions. For example:\r\n\r\n (foo=3|foo=bar)&price=lt=10\r\n \r\nWhich is the same as:\r\n\r\n and(or(eq(foo,3),eq(foo,bar)),lt(price,10))\r\n\r\nAnd to query a model/store:\r\n\r\n MyModel.query(\"(foo=3|foo=bar)&price=lt=10\")...\r\n \r\nAnd using chained JS calls: \r\n\r\n\tvar query = MyModel.query();\r\n\tquery.or(query.eq(\"foo\",3),query.eq(\"foo\",\"bar\")).lt(\"price\",10)...\r\n\r\nSometimes it makes sense to use the with statement (despite the fact that some \r\nthink it should never be used). This actually makes the syntax look very similar\r\nto the query string format. For example:\r\n\r\n\twith(MyModel.query()){\r\n\t\tor(eq(\"foo\",3),eq(\"foo\",\"bar\")).lt(\"price\",10)...\r\n\t}\r\n\r\nFor a more a complete reference guide to the RQL and the available query operators,\r\nsee [[http://github.com/persvr/rql]]. This also provides information on\r\nthe parsed query data structure which is important if you want to implement your\r\nown custom stores.\r\n\r\n# Modules\r\n\r\nThis section covers the modules that are included with Perstore.\r\n\r\n## transaction\r\n\r\n require(\"perstore/transaction\").transaction(doTransaction);\r\n\r\nTransactions provide a means for committing multiple changes to a database \r\natomically. The store API includes transaction semantics for communicating transactions\r\nto the underlying databases. Perstore provides transactional management for delegating\r\ntransaction operations to the appropriate stores and databases. To start a transaction,\r\ncall the transaction function on the stores module with a callback that will perform any\r\nof the actions of the transaction:\r\n\r\n require(\"perstore/transaction\").transaction(function(){\r\n \tModel.put(...);\r\n \tModel.delete(...);\r\n });\r\n \r\nThe callback function may return a promise if the transaction will involve actions that\r\nextend beyond the duration of the function call. When the promise is resolved the \r\ntransaction will be committed (or if the promise errors out, the transaction will be \r\naborted).\r\n\r\nPerstore includes a JSGI middleware component for wrapping requests in transactions.\r\nThis will make the life of the request be one transaction, committed when the response\r\nis ready to send (or aborted for an error).\r\n\r\n transactionApp = require(\"perstore/jsgi/transactional\").Transactional(nextApp);\r\n\r\n### Implementing Transactions\r\n\r\nIf you are writing your store that needs to be transaction aware, there are two \r\ndifferent options for implementing transaction handling. The simplest approach is to\r\nimplement the implement the transaction method on your store and then use the\r\nAutoTransaction store wrapper provided by the \"stores\" module:\r\n\r\n var AutoTransaction = require(\"perstore/transaction\").AutoTransaction;\r\n myTransactionalStore = AutoTransaction({\r\n transaction: function(){\r\n // prepare the transaction\r\n return {\r\n commit: function{\r\n // commit the transaction\r\n },\r\n // implement the rest of the handlers\r\n abort:...\r\n }\r\n }\r\n });\r\n\r\nThe AutoTransaction wrappers provides two important functions. First, if any of your\r\nstore methods are called outside of a global transaction, a transaction will automatically\r\nbe started before calling the method and committed afterwards. Second, if a global\r\ntransaction is in process, the transaction method will be called on the first access of\r\nthis store and be committed when the global transaction is committed.\r\n\r\nThe other approach to transaction handling is to provide a \"database\" object. This can\r\nbe useful for situations where transaction management needs to exist outside of \r\nindividual stores (and may cross stores). One can implement a \"database\" object that\r\nprovides the transaction method with the same API as the store's transaction method.\r\nThe database object can be registered with:\r\n\r\n require(\"perstore/transaction\").registerDatabase(transaction: function(){\r\n // prepare the transaction\r\n return {...}\r\n });\r\n \r\nThis transaction method will be called whenever a global transaction is started.\r\n\r\n## model\r\n\r\n\tvar Model = require(\"perstore/model\");\r\n\tModel(name, store, schema);\r\n\r\nThis module provides facitilities for creating data models. The most common function\r\nto use is the module's return value, the Model constructor. This takes a store and\r\na schema. The store is the underlying source of the persisted data for the model,\r\nand the schema can be used to define data constraints, the prototype, and relations.\r\n\r\nThe schema object follows the [JSON Schema specification](http://json-schema.org),\r\npermitting property definition objects to constrain different properties on the data model.\r\nFor example:\r\n\r\n\tModel(store, {\r\n\t\tproperties: {\r\n\t\t\t// we can use the explicit JSON Schema definition object, or the String constructor as a shortcut\r\n\t\t\tname: {type: \"string\"}, \r\n\t\t\tage: {\r\n\t\t\t\ttype:\"number\",\r\n\t\t\t\tminimum: 0,\r\n\t\t\t\tmaximum: 125\r\n\t\t\t}\r\n\t\t}\r\n\t});\r\n\r\nData models also follow the store API. The schema object can overwrite the default \r\nimplementation of the store methods to provide specific functionality. For example,\r\nwe could provide our own implementation of the put() method:\r\n\r\n\tModel(store, {\r\n\t\tput: function(object, directives){\r\n\t\t\t// our code, implement any logic in here\r\n\t\t\t\r\n\t\t\t// we can now call the store object to store the data \r\n\t\t\treturn store.put(object, directives);\r\n\t\t},\r\n\t\t...\r\n\r\nThe schema object can also include a prototype object. The prototype will be the \r\nthe base for all instances to inherit methods (and properties) from. \r\n \r\n## facet\r\n\r\n\trestrictedFacet = require(\"perstore/facet\").Restrictive(model, schema);\r\n\trestrictedFacet = require(\"perstore/facet\").Permissive(model, schema);\r\n\t\r\nFacets are type of model that wraps an existing model and adds additional constraints\r\nand/or functionality. Facets allow you to derive different entry points to data models\r\nwith different levels of access and capabilities. Facets can be used with the security\r\nmodel to vary access level by user or other entry variables.\r\n\r\nThe Restrictive facet restricts the model to a readonly data model by default. One\r\ncan override methods to create more specific levels of access. For example, here\r\nwe could define a facet that is readonly except when the object's status is currently in\r\ndraft:\r\n\r\n var facet = require(\"facet\").Restrictive(model, {\r\n put: function(object){ // allow create\r\n \tif(model.get(object.id).status == \"draft\"){\r\n \treturn model.put(object);\r\n }\r\n }\r\n });\r\n\r\nThe Permissive facet provides all the capabilities of the underlying data model by default.\r\nOne can then override methods to restrict access, or add JSON Schema constraints\r\nto constrain the ways that data can be changed through this facet.\r\n\t\r\n## errors\r\n\r\n\tthrow require(\"perstore/errors\").AccessError(reason);\r\n\tthrow require(\"perstore/errors\").MethodNotAllowedError(reason);\r\n\tthrow require(\"perstore/errors\").DatabaseError(reason);\r\n\tthrow require(\"perstore/errors\").PreconditionFailed(reason);\r\n\r\nThis module provides a set of error constructors for throwing data errors. These \r\ncan be used in conjunction with Pintura's error handling middleware to propagate\r\nerrors with known HTTP status codes.\r\n\r\n## stores\r\n\r\n\tstore = require(\"perstore/stores\").DefaultStore(options);\r\n\r\nThis creates a store using the default store for Perstore, which is a Replicated Persistent (perstore/store/memory)\r\nstore. This is the quickest way to create a new store, particularly if you getting a prototype\r\nup and running.\r\n\r\n## store (folder)\r\n\r\nThe modules in the store folder provide store implementations and store wrappers.\r\nThese provide access to various data sources and add functionality to these stores.\r\n\r\n### mongodb\r\n\r\n\tstore = require(\"perstore/store/mongodb\").MongoDB({\r\n\t\tcollection: collection\r\n\t});\r\n\r\nThis is an object store that uses a MongoDB database for storage. MongoDB provides\r\na powerful backend for Perstore because it is specifically designed for JSON-style\r\nobject storage. This store has good querying capabilites, supporting a large set of \r\nthe RQL operators. This store requires installation\r\nof the mongodb package (npm install mongodb).\r\n\r\nThe MongoDB store looks to the local.json for configuration information, using either the\r\ndatabase.url property or the database.host, database.name, and database.port properties.\r\nFor example, our local.json could configuration the database:\r\n\r\n\t\"database\": {\r\n\t\t\"host\": \"localhost\",\r\n\t\t\"name\": \"wiki\",\r\n\t},\r\n\r\n(we omitted the port, which defaults to 27017)\r\n\r\nWe also must indicate which collection to use for the store. This is provided in the options\r\nparameter to the constructor.\r\n\r\nThis store is only available for NodeJS.\r\n\r\n### sql\r\n\r\n\tstore = require(\"perstore/store/mongodb\").SQLStore({\r\n\t\ttable: table,\r\n\t\tidColumn: idColumn\r\n\t});\r\n\r\n\r\nThis is store connects to an SQL backend and maps SQL rows to objects. RQL queries \r\nare converted to SQL, and a large set of the RQL queries are supported. On Node.js, this store requires installation\r\nof the mysql-native package (npm install mysql-native).\r\n\r\nThe SQLStore looks to the local.json for configuration information. In Node, it uses the \r\ndatabase.type, database.host, database.port, database.name, database.username, and database.password\r\nproperties to connect to the database. For example, our local.json could configuration the database:\r\n\r\n\t\"database\": {\r\n\t\t\"type\": \"mysql\",\r\n\t\t\"host\": \"localhost\",\r\n\t\t\"username\": \"root\",\r\n\t\t\"password\": \"password\",\r\n\t\t\"name\": \"wiki\",\r\n\t},\r\n\r\nThe type parameter indicates which SQL vendor dialect to use. Supported options are \r\n\"mysql\", \"sqlite\", \"derby\", \"hsqldb\", \"oracle\", \"postgres\", \"mssql\". \r\n\r\nIn Rhino, the \"connection\" property is used to configure the database, using a JDBC\r\nconnection string, and a driver property can be used to explicitly identifier the database\r\ndriver class to use (it will be determined from the type parameter otherwise).\r\n \r\nWe also must indicate which table and which column is the primary key to use for the store. This is provided in the options\r\nparameter to the constructor. The configuration parameter to the store can also\r\noverride the configuration information in local.json.\r\n\r\n### memory\r\n\r\nThis module provides an in-memory data store. This actually exports three different\r\nstore constructors for different storage capabilities:\r\n\r\n\tstore = require(\"perstore/store/memory\").Memory(options);\r\n\r\nThe Memory store keeps all data in memory (no persistence to disk). The options parameter\r\ncan include an optional \"log\" property indicating whether or not to keep a log of data revisions.\r\nThe \"log\" parameter defaults to true. \r\n\r\nThe options parameter may also include an optional \"index\" property that is a \r\nhash of the all the objects to initialize the store with, where the property names are the\r\nids and the property values are the objects in the store.\r\n\r\n\tstore = require(\"perstore/store/memory\").ReadOnly(options);\r\n\r\nThe ReadOnly store is equivalent to the Memory constructor except it generates a readonly store, and\r\ndoes not have any add, put, or delete methods.\r\n\r\n\tstore = require(\"perstore/store/memory\").Persistent(options);\r\n\r\nThe Persistent store is equivalent to the Memory constructor except it will persist\r\nthe data to a file. The data is persisted to a file in extended JSON format. The options\r\nparameter for the store supports an optional \"file\" parameter or \"path\" parameter to\r\nspecify the filename of the target file for persisting data, or the directory path to store\r\nfiles.\r\n\r\nThe Persistent store is the default store for Perstore.\r\n\r\n### redis\r\n\r\n\tstore = require(\"perstore/store/redis\").Redis({\r\n\t\tcollection: collection\r\n\t});\r\n\r\nThis is object store that uses a Redis database for storage. This requires the installation\r\nof the redis package.\r\n\r\n### remote\r\n\r\n\tstore = require(\"perstore/store/remote\").Remote(request, url);\r\n\r\nThis can connect to a remote HTTP/REST based JSON server to store and \r\nretrieve data. The optional request parameter is the function that will perform the \r\nremote requests, and defaults to an HTTP requester if no value is provided. The\r\nurl specifies the URL of target server.\r\n\r\n\r\nPerstore also includes several store wrappers that can be used to compose more \r\nsophisticated stores by adding functionality (also in the store directory), including cache,\r\naggregate, replicated, and inherited. The store implementations and store wrappers\r\nare described in more detail in the modules section below.\r\n\r\n### cache\r\n\r\n\tstore = require(\"perstore/store/cache\").Cache(masterStore, cacheStore, options);\r\n\r\nThis module adds caching support to a provided store. The main store is the first\r\nparameter, and data retrieved from that store is cached in the provided cacheStore.\r\nTypically the cacheStore would be an in-memory store, to provide quick access to\r\nfrequently accessed data. The options parameter provides several configuration options:\r\n\r\n* defaultExpiresTime - Default amount of time before an object in the cache expires in milliseconds, defaults to 2000.\r\n* cleanupInterval - Amount of time before cleaning up expired objects in the cache, in milliseconds, defaults to 1000.\r\n* cacheWrites - Determines whether or not to cache writes to the caching store (all writes go to the master store), defaults to true.\r\n\r\n### aggregate\r\n\r\n\tstore = require(\"perstore/store/aggregate\").Aggregate(stores, properties);\r\n\r\nThis store combines record data from multiple stores into a single object store. The\r\nstores argument should be an array of stores. When an object is requested, the request\r\nis made to each of the stores, and the returned objects are mixed together. When \r\na write is performed, the object can then be split up into the properties that are handled\r\nby each of the underlying stores. The properties argument specifies the properties\r\nfor each store. The properties argument should be an array (where each entry defines the \r\nproperties for the store with the corresponding index) of arrays of strings with the names\r\nof the properties for each store.\r\n\r\n### notifying\r\n\r\n\tnotifyingStore = require(\"perstore/store/notifying\").Notifying(sourceStore);\r\n\r\nThis store wrapper adds notification support to stores, allowing store consumers to\r\nlisten for data changes. We can listen for data changes by making a subscription and\r\nadding a listener:\r\n\r\n\tnotifyingStore.subscribe(\"*\").observe(listener);\r\n\r\n### replicated\r\n\r\n\tstore = require(\"perstore/store/replicated\").Replicated(sourceStore);\r\n\r\nThis store wrapper provides data replication across different processes. This is needed for memory\r\nstores in a multi-process applications where all processes need to be synchronized\r\naccess to data that is stored in separate memory spaces for each process.\r\n\r\n### inherited\r\n\r\n\tsuperStore = require(\"perstore/store/inherited\").Inherited(sourceStore);\r\n\tsubStore = require(\"perstore/store/inherited\").Inherited(sourceStore);\r\n\r\nInherited provides a super-sub type relationship between data stores. The Inherited constructor\r\nadds support for distinguishing different types in storage. The hierarchical relationships\r\nmust be defined at the model level with the schema \"extends\" property. \r\n\r\n## util (folder)\r\n\r\nThe util folder includes various utility modules used by Perstore.\r\n\r\n### json-ext\r\n\r\n\tjsonString = require(\"perstore/util/json-ext\").stringify(object);\r\n\tobject = require(\"perstore/util/json-ext\").parse(jsonString);\r\n\r\nThis provides support for JavaScript based object literals that extend basic JSON. This module\r\ncan serialize and parse JSON-style object literals with constructs including NaN, Infinity, \r\nundefined, and primitive function constructors (String, Number, etc.)\r\n\r\n### settings\r\n\r\n\tmySetting = require(\"perstore/util/settings\").mySetting;\r\n\t\r\nThis module parses the JSON in the local.json file found in the current working directory\r\nand puts all the properties on the module's export.\r\n\r\n### extend-error\r\n\r\n\tCustomTypeError = require(\"perstore/util/extend-error\")(TypeError, \"CustomTypeError\");\r\n\r\nThis module provides an easy tool to create custom error constructors.\r\n\r\n## jsgi\r\n\r\n### transactional\r\n\r\n transactionApp = require(\"perstore/jsgi/transactional\").Transactional(nextApp);\r\n\r\nThis module is a JSGI middleware module providing transaction wrapping around\r\na request/response cycle. See the Transaction section above for more information.\r\n\r\nLicensing\r\n--------\r\n\r\nPerstore is part of the Persevere project, and therefore is licensed under the\r\nAFL or BSD license. The Persevere project is administered under the Dojo foundation,\r\nand all contributions require a Dojo CLA.\r\n\r\nProject Links\r\n------------\r\n\r\nSee the main Persevere project for more information:\r\n\r\n### Homepage:\r\n\r\n* [http://persvr.org/](http://persvr.org/)\r\n\r\n### Source & Download:\r\n\r\n* [http://github.com/persvr/perstore/](http://github.com/persvr/perstore)\r\n\r\n### Mailing list:\r\n\r\n* [http://groups.google.com/group/persevere-framework](http://groups.google.com/group/persevere-framework)\r\n\r\n### IRC:\r\n\r\n* [\\#persevere on irc.freenode.net](http://webchat.freenode.net/?channels=persevere)\r\n","_id":"perstore@0.3.2","description":"Perstore is a cross-platform JavaScript object store interface for mapping persistent \r objects to various different storage mediums using an interface based on\r W3C's [IndexedDB object store API](http://www.w3.org/TR/IndexedDB/#object-store-sync)\r and analogous to the HTTP REST interface. Perstore\r includes JavaScript object-relational mapping for SQL databases, JSON file storage,\r and hopefully support for many other object/document style storage systems that\r provide more direct object storage. Perstore provides model classes that wrap data\r stores, and supports JSON Schema integrity enforcement, link management, and \r prototype construction. Perstore also provides faceted access to models for an\r object-capability based security model.","dist":{"shasum":"5c8bb101cb511bd90199f46f3ddf69a9d61b2989","tarball":"https://registry.npmjs.org/perstore/-/perstore-0.3.2.tgz","integrity":"sha512-FZTf70HUzYhZrupyzmwrCvdg3kC11InYCEBqp7gunXYWQZSFXAAK9zrGvjlNnfM7JGJV9/Bq2re7ECARJXoIDw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHCaRArjnopwgdDdLz97nwBaXU2KOOOBuNBFeM40Bf1kAiBZzFoHlNlM+9a7T7ZexrPLawvXIam1rijI1X54YKhvfA=="}]},"_npmVersion":"1.1.59","_npmUser":{"name":"dojofoundation","email":"kriszyp@gmail.com"}},"0.3.3":{"name":"perstore","version":"0.3.3","author":{"name":"Kris Zyp"},"email":"kriszyp@gmail.com","contributors":[{"name":"Vladimir Dronnikov","email":"dronnikov@gmail.com"}],"keywords":["persistence","object","store","persevere"],"maintainers":[{"name":"dojofoundation","email":"kzyp@dojofoundation.org"}],"engines":{"node":">=0.1.30","rhino":true},"mappings":{"tunguska":"http://github.com/kriszyp/tunguska/zipball/v0.2.2","rql":"jar:http://github.com/kriszyp/rql/zipball/v0.2.2!/","patr":"jar:http://github.com/kriszyp/patr/zipball/v0.2.2!/","promised-io":"jar:http://github.com/kriszyp/promised-io/zipball/v0.2.2!/","json-schema":"http://github.com/kriszyp/json-schema/zipball/v0.2.1","mysql-native":"jar:http://github.com/sidorares/nodejs-mysql-native/zipball/master!/lib/mysql-native/","mongodb":"jar:http://github.com/christkv/node-mongodb-native/zipball/V0.9.4.4!/lib/mongodb/"},"overlay":{"narwhal":{"mappings":{"fs-promise":"./engines/rhino/lib/fs-promise","store-engine":"./engines/rhino/lib/store-engine/"}},"node":{"mappings":{"store-engine":"./engines/node/lib/store-engine/"}}},"usesSystemModules":["path"],"licenses":[{"type":"AFLv2.1","url":"http://trac.dojotoolkit.org/browser/dojo/trunk/LICENSE#L43"},{"type":"BSD","url":"http://trac.dojotoolkit.org/browser/dojo/trunk/LICENSE#L13"}],"repository":{"type":"git","url":"http://github.com/kriszyp/tunguska"},"directories":{"lib":"."},"dependencies":{"tunguska":">=0.3.0","rql":">=0.3.1","promised-io":">=0.3.0","json-schema":">=0.2.1"},"devDependencies":{"patr":">0.2.6"},"jars":["jars/perstore.jar"],"readme":"Perstore is a cross-platform JavaScript object store interface for mapping persistent \r\nobjects to various different storage mediums using an interface based on\r\nW3C's [IndexedDB object store API](http://www.w3.org/TR/IndexedDB/#object-store-sync)\r\nand analogous to the HTTP REST interface. Perstore\r\nincludes JavaScript object-relational mapping for SQL databases, JSON file storage,\r\nand hopefully support for many other object/document style storage systems that\r\nprovide more direct object storage. Perstore provides model classes that wrap data\r\nstores, and supports JSON Schema integrity enforcement, link management, and \r\nprototype construction. Perstore also provides faceted access to models for an\r\nobject-capability based security model.\r\n\r\nSetup\r\n=====\r\n\r\nPerstore can be installed with NPM via:\r\n\r\n\tnpm install perstore\r\n\r\nHowever, one of the easiest way to get started with Perstore is to start with the \r\n[Persevere example app](http://github.com/persvr/persevere-example-wiki),\r\nwhich can be installed with:\r\n\r\n\tnpm install persevere-example-wiki\r\n\r\nPerstore can be installed in RingoJS likewise:\r\n\r\n\tringo-admin install persvr/perstore\r\n\r\nSee the [Persevere installation instructions for more information](http://persvr.org/Page/Installation).\r\n\r\nPerstore also requires a local.json file to be present in the current working directory.\r\nAn example of this file can be found [here](https://github.com/persvr/persevere-example-wiki/blob/master/local.json).\r\n\r\nModel\r\n=====\r\n\r\nPerstore provides the tools for building data models. With Perstore we can create data\r\nstores that connect to different database backends. We can then build on the basic\r\nstores with data model and facets that provide application logic, data constraints,\r\naccess definitions, data change responses, and queries. Typical usage of Perstore looks like:\r\n\r\n // first setup the object store, here we use SQL/ORM store\r\n var store = require(\"perstore/store/sql\").SQLStore({\r\n type: \"mysql\",\r\n table: \"my_table\",\r\n idColumn: \"id\"\r\n });\r\n \r\n // now we can setup a model that wraps the data store\r\n var MyModel = require(\"perstore/model\")(store, {\r\n \tproperties: {\r\n \t\t// we can define optionally define type constraints on properties\r\n \t\tfoo: String\r\n \t},\r\n \tprototype: {\r\n \t\t// we can define functions on the prototype of the model objects as well\r\n \t\tgetFoo: function(){\r\n \t\t\treturn this.foo;\r\n \t\t}\r\n \t}\r\n });\r\n // now we can interact with the store and it's objects\r\n var someObject = MyModel.get(someId); // retrieve a persisted object\r\n someObject.getFoo(); // returns the current value of foo\r\n someObject.foo = \"bar\"; // make a change\r\n someObject.save(); // and save it\r\n \r\n MyModel.delete(someOtherId); // delete an object\r\n \r\n var MyFacet = require(\"facet\").Restrictive(MyModel, {\r\n });\r\n\r\n\tMyFacet.delete(someId) -> will fail, as the facet has not allowed access to delete().\r\n\t\r\nA model is defined with the Model constructor in the \"MyModel\" module. A Model definition\r\nmay follow the JSON schema definition for contractual constraints (usually defining property\r\ntype constraints in the \"properties\" property and relations with the \"links\" property). \r\nproperty. It may also contain a \"prototype\" property which defines the prototype object\r\nfor all instances of the model. Methods can be defined on the prototype object, as well\r\nas directly on the model. REST methods such as get, put, and delete are implemented\r\ndirectly on the model, and can be overridden for specific functionality.\r\n \r\nPerstore provides easy to use object persistence mechanism. Persisted model object\r\ninstances have two default methods and a property:\r\n\r\n- save() - Saves any changes that have been made to an object to the data store.\r\n- load() - If the object has not been fully loaded (sometime queries may return partial\r\nobject), the object will be fully loaded from the data store.\r\n- schema - This is a reference to the schema for this object. Schema objects are augmented\r\n(if it does not previously exist) with a getId method that can be used to retrieve the identity \r\nof an object:\r\n\r\n object.schema.getId(object) -> identity of object\r\n\r\n\r\nIn the initial example, object persistence is demonstrated with the \"someObject\"\r\nvariable. The object is loaded (via the get call to the model), modified, and saved\r\n(with the save() call).\r\n\r\nFacets provide secure, controlled access to models. The facet module comes provides\r\ntwo facet constructors: Permissive and Restrictive. A Permissive facet allows all actions\r\non the model by default. Methods can be defined/overridden in the Permissive definition\r\nto control or disable access to certain functionality. A Restrictive facet only allows read\r\naccess methods by default (get and query). One can define/override methods to allow\r\nexplicit access to other methods such as put or create. An example facet that only\r\nallows read access and creation of new objects:\r\n\r\n var facet = require(\"facet\").Restrictive(model, {\r\n create: function(object){ // allow create\r\n return model.create(object);\r\n }\r\n });\r\n\r\nModels wrap data stores, which provide the low level interaction with the database or \r\nstorage system. Perstore comes with several data stores including (in the perstore/store directory)\r\nmongodb, redis, sql, memory, file, and HTTP/remote storage. Perstore also includes \r\nseveral store wrappers that can be used to compose more \r\nsophisticated stores by adding functionality (also in the store directory), including cache,\r\naggregate, replicated, and inherited. The store implementations and store wrappers\r\nare described in more detail in the modules section below.\r\n\r\nThe following is store API for Perstore. The same API is used for data stores, store \r\nmodels, and facets. All of the functions are optional. If they do not exist, it indicates \r\nthat the store or model does not support or allow the said functionality. All of the \r\nfunctions may return a promise instead of \r\nthe actual return value if they require asynchronous processing to complete the \r\noperation. They are roughly listed in order of importance:\r\n\r\n* get(id, directives) - Finds the persisted record with the given identifier from the store and returns \r\nan object representation (should always be a new object).\r\n\r\n* put(object, directives) - Stores the given object in storage. The record may or may not \r\nalready exist. The optional second parameter \r\ndefines the primary identifier for storing the object. If the second parameter is omitted, the\r\nkey may be specified the primary identifier property. If that is not specified, the key may be\r\nauto-generated. The primary identifer for the object should be returned\r\n\r\n* delete(id, directives) - Deletes the record with the given identifier from the store.\r\n\r\n* query(queryString, directives) - This executes a query against the data store. The \r\nqueryString parameter defines the actual query, and the options parameter should be\r\nan object that provides extra information. The following properties on the directives\r\nobject may be included:\r\n\r\n- start - The offset index to start at in the result set\r\n- end - The offset index to end at in the result set\r\n- parameters - An array of values for parameterized queries\r\n\r\nThe function should generally return an array representing the result set of the query \r\n(unless the query creates a single aggregate object or value). Perstore is designed to leverage [http://github.com/persvr/rql](resource query language)\r\nfor querying, and included stores use RQL (although they may not implement every\r\nfeature in RQL), although stores can utilize alternate query languages. \r\n\r\n* add(object, directives) - Stores a new record. This acts similar to put, but should only be called\r\nwhen the record does not already exist. Stores do not need to implement this \r\nmethod, but may implement for ease of differentiating between creation of new \r\nrecords and updates. This should return the identifier of the newly create record. If an\r\nobject already exists with the given identity, this should throw an error. \r\n\r\n* construct(object, directives) - This constructs a new persistable object. This does not\r\nactually store the object, but returns an object with a save() method that\r\ncan be called to store the object when it is ready. This method does not apply to stores,\r\nonly models and facets.\r\n\r\n* subscribe(resource, callback) - Subscribes to changes in the given resource or set of \r\nresources. The callback is called whenever data is changed in the monitored resource(s).\r\n\r\n* transaction() - Starts a new transaction for the store. This should return\r\na transaction object with the following functions. Each of these functions are optional\r\nand only called if they exist:\r\n\r\n- commit() - This is called when a transaction is committed.\r\n- requestCommit() - This is called on all the databases/stores prior to committing the\r\ntransaction. If this succeeds (doesn't throw an error), the store should guarantee the\r\nsuccess of a subsequent commit() operation. This provides two phase commit \r\nsemantics. \r\n- abort() - This is called when a transaction is aborted.\r\n- suspend() - This is called when a transaction is suspended. This happens when an \r\nevent is finished, but a promise for the continuance of the action is still in progress. \r\nAfter being suspended, this transaction is no longer the active transaction.\r\n- resume() - This is called when a transaction is resumed. This happens when a promise\r\nresumes the execution of an action.\r\n\r\n(See Transactions section below for more information)\r\n\r\nPerstore is designed to allow easy construction of new data stores. A data store \r\nin Perstore is a JavaScript object with any or all of the functions defined above.\r\n\r\nQuerying\r\n========\r\n\r\nPerstore provides a query parsing and execution through [http://github.com/persvr/rql](resource query language) \r\n(RQL). RQL can be thought as basically a set of\r\nnestable named operators which each have a set of arguments. RQL is designed to\r\nhave an extremely simple, but extensible grammar that can be written in a URL friendly query string. A simple RQL\r\nquery with a single operator that indicates a search for any resources with a property of\r\n\"foo\" that has value of 3 could be written:\r\n\r\n eq(foo,3)\r\n\r\nRQL is a compatible superset of standard HTML form URL encoding. The following query\r\nis identical to the query (it is sugar for the query above):\r\n\r\n foo=3\r\n\r\nWe can use this query format to query stores and models. For example:\r\n\r\n MyModel.query(\"foo=3\").forEach(function(object){\r\n // for each object with a property of foo equal to 3\r\n });\r\n\r\nWe can also construct queries using chained operator calls in JavaScript. We could\r\nwrite this query:\r\n\r\n MyModel.query().eq(\"foo\",3).forEach(...);\r\n\r\nThe RQL grammar is based around standard URI delimiters. The standard rules for \r\nencoding strings with URL encoding (%xx) are observed. RQL also supersets FIQL. \r\nTherefore we can write a query that finds resources with a \"price\" property below\r\n10 with a \"lt\" operator using FIQL syntax:\r\n\r\n price=lt=10\r\n\r\nWhich is identical (and sugar for call operator syntax known as the normalized form):\r\n\r\n lt(price,10)\r\n\r\nOne can combine conditions with multiple operators with \"&\":\r\n\r\n foo=3&price=lt=10\r\n\r\nIs the same as:\r\n\r\n eq(foo,3)<(price,10)\r\n\r\nWhich is also the same as:\r\n\r\n and(eq(foo,3),lt(price,10))\r\n\r\nAnd thus can be used to query a store:\r\n\r\n\tMyModel.query(\"foo=3&price=lt=10\")...\r\n\r\nOr using chained JS calls to perform the same query:\r\n\r\n MyModel.query().eq(\"foo\",3).lt(\"price\",10)...\r\n\r\nThe | operator can be used to indicate an \"or\" operation. We can also use paranthesis\r\nto group expressions. For example:\r\n\r\n (foo=3|foo=bar)&price=lt=10\r\n \r\nWhich is the same as:\r\n\r\n and(or(eq(foo,3),eq(foo,bar)),lt(price,10))\r\n\r\nAnd to query a model/store:\r\n\r\n MyModel.query(\"(foo=3|foo=bar)&price=lt=10\")...\r\n \r\nAnd using chained JS calls: \r\n\r\n\tvar query = MyModel.query();\r\n\tquery.or(query.eq(\"foo\",3),query.eq(\"foo\",\"bar\")).lt(\"price\",10)...\r\n\r\nSometimes it makes sense to use the with statement (despite the fact that some \r\nthink it should never be used). This actually makes the syntax look very similar\r\nto the query string format. For example:\r\n\r\n\twith(MyModel.query()){\r\n\t\tor(eq(\"foo\",3),eq(\"foo\",\"bar\")).lt(\"price\",10)...\r\n\t}\r\n\r\nFor a more a complete reference guide to the RQL and the available query operators,\r\nsee [[http://github.com/persvr/rql]]. This also provides information on\r\nthe parsed query data structure which is important if you want to implement your\r\nown custom stores.\r\n\r\n# Modules\r\n\r\nThis section covers the modules that are included with Perstore.\r\n\r\n## transaction\r\n\r\n require(\"perstore/transaction\").transaction(doTransaction);\r\n\r\nTransactions provide a means for committing multiple changes to a database \r\natomically. The store API includes transaction semantics for communicating transactions\r\nto the underlying databases. Perstore provides transactional management for delegating\r\ntransaction operations to the appropriate stores and databases. To start a transaction,\r\ncall the transaction function on the stores module with a callback that will perform any\r\nof the actions of the transaction:\r\n\r\n require(\"perstore/transaction\").transaction(function(){\r\n \tModel.put(...);\r\n \tModel.delete(...);\r\n });\r\n \r\nThe callback function may return a promise if the transaction will involve actions that\r\nextend beyond the duration of the function call. When the promise is resolved the \r\ntransaction will be committed (or if the promise errors out, the transaction will be \r\naborted).\r\n\r\nPerstore includes a JSGI middleware component for wrapping requests in transactions.\r\nThis will make the life of the request be one transaction, committed when the response\r\nis ready to send (or aborted for an error).\r\n\r\n transactionApp = require(\"perstore/jsgi/transactional\").Transactional(nextApp);\r\n\r\n### Implementing Transactions\r\n\r\nIf you are writing your store that needs to be transaction aware, there are two \r\ndifferent options for implementing transaction handling. The simplest approach is to\r\nimplement the implement the transaction method on your store and then use the\r\nAutoTransaction store wrapper provided by the \"stores\" module:\r\n\r\n var AutoTransaction = require(\"perstore/transaction\").AutoTransaction;\r\n myTransactionalStore = AutoTransaction({\r\n transaction: function(){\r\n // prepare the transaction\r\n return {\r\n commit: function{\r\n // commit the transaction\r\n },\r\n // implement the rest of the handlers\r\n abort:...\r\n }\r\n }\r\n });\r\n\r\nThe AutoTransaction wrappers provides two important functions. First, if any of your\r\nstore methods are called outside of a global transaction, a transaction will automatically\r\nbe started before calling the method and committed afterwards. Second, if a global\r\ntransaction is in process, the transaction method will be called on the first access of\r\nthis store and be committed when the global transaction is committed.\r\n\r\nThe other approach to transaction handling is to provide a \"database\" object. This can\r\nbe useful for situations where transaction management needs to exist outside of \r\nindividual stores (and may cross stores). One can implement a \"database\" object that\r\nprovides the transaction method with the same API as the store's transaction method.\r\nThe database object can be registered with:\r\n\r\n require(\"perstore/transaction\").registerDatabase(transaction: function(){\r\n // prepare the transaction\r\n return {...}\r\n });\r\n \r\nThis transaction method will be called whenever a global transaction is started.\r\n\r\n## model\r\n\r\n\tvar Model = require(\"perstore/model\");\r\n\tModel(name, store, schema);\r\n\r\nThis module provides facitilities for creating data models. The most common function\r\nto use is the module's return value, the Model constructor. This takes a store and\r\na schema. The store is the underlying source of the persisted data for the model,\r\nand the schema can be used to define data constraints, the prototype, and relations.\r\n\r\nThe schema object follows the [JSON Schema specification](http://json-schema.org),\r\npermitting property definition objects to constrain different properties on the data model.\r\nFor example:\r\n\r\n\tModel(store, {\r\n\t\tproperties: {\r\n\t\t\t// we can use the explicit JSON Schema definition object, or the String constructor as a shortcut\r\n\t\t\tname: {type: \"string\"}, \r\n\t\t\tage: {\r\n\t\t\t\ttype:\"number\",\r\n\t\t\t\tminimum: 0,\r\n\t\t\t\tmaximum: 125\r\n\t\t\t}\r\n\t\t}\r\n\t});\r\n\r\nData models also follow the store API. The schema object can overwrite the default \r\nimplementation of the store methods to provide specific functionality. For example,\r\nwe could provide our own implementation of the put() method:\r\n\r\n\tModel(store, {\r\n\t\tput: function(object, directives){\r\n\t\t\t// our code, implement any logic in here\r\n\t\t\t\r\n\t\t\t// we can now call the store object to store the data \r\n\t\t\treturn store.put(object, directives);\r\n\t\t},\r\n\t\t...\r\n\r\nThe schema object can also include a prototype object. The prototype will be the \r\nthe base for all instances to inherit methods (and properties) from. \r\n \r\n## facet\r\n\r\n\trestrictedFacet = require(\"perstore/facet\").Restrictive(model, schema);\r\n\trestrictedFacet = require(\"perstore/facet\").Permissive(model, schema);\r\n\t\r\nFacets are type of model that wraps an existing model and adds additional constraints\r\nand/or functionality. Facets allow you to derive different entry points to data models\r\nwith different levels of access and capabilities. Facets can be used with the security\r\nmodel to vary access level by user or other entry variables.\r\n\r\nThe Restrictive facet restricts the model to a readonly data model by default. One\r\ncan override methods to create more specific levels of access. For example, here\r\nwe could define a facet that is readonly except when the object's status is currently in\r\ndraft:\r\n\r\n var facet = require(\"facet\").Restrictive(model, {\r\n put: function(object){ // allow create\r\n \tif(model.get(object.id).status == \"draft\"){\r\n \treturn model.put(object);\r\n }\r\n }\r\n });\r\n\r\nThe Permissive facet provides all the capabilities of the underlying data model by default.\r\nOne can then override methods to restrict access, or add JSON Schema constraints\r\nto constrain the ways that data can be changed through this facet.\r\n\t\r\n## errors\r\n\r\n\tthrow require(\"perstore/errors\").AccessError(reason);\r\n\tthrow require(\"perstore/errors\").MethodNotAllowedError(reason);\r\n\tthrow require(\"perstore/errors\").DatabaseError(reason);\r\n\tthrow require(\"perstore/errors\").PreconditionFailed(reason);\r\n\r\nThis module provides a set of error constructors for throwing data errors. These \r\ncan be used in conjunction with Pintura's error handling middleware to propagate\r\nerrors with known HTTP status codes.\r\n\r\n## stores\r\n\r\n\tstore = require(\"perstore/stores\").DefaultStore(options);\r\n\r\nThis creates a store using the default store for Perstore, which is a Replicated Persistent (perstore/store/memory)\r\nstore. This is the quickest way to create a new store, particularly if you getting a prototype\r\nup and running.\r\n\r\n## store (folder)\r\n\r\nThe modules in the store folder provide store implementations and store wrappers.\r\nThese provide access to various data sources and add functionality to these stores.\r\n\r\n## path\r\n\r\nThis module provides functionality for resolving path references within data objects. The\r\nmodule exports a resolver
function, that returns a resolve
\r\nthat can be used to resolve references in objects. To get a resolve
\r\nfunction, call resolver with the a data model (and optionally second argument, a getDataModel function\r\nthat can provide access to the other data models):\r\n\r\n\tvar resolve = require(\"perstore/path\").resolver(myModel);\r\n\r\nAnd then we can use the resolve
to resolve a path. If we want to \r\nresolve the \"foo\" property of the object with an id of 11, we could write:\r\n\r\n\tresolve(\"11/foo\");\r\n\r\nAnd if foo's property value was a reference to another object, this would also be automatically resolved.\r\n\r\n### mongodb\r\n\r\n\tstore = require(\"perstore/store/mongodb\").MongoDB({\r\n\t\tcollection: collection\r\n\t});\r\n\r\nThis is an object store that uses a MongoDB database for storage. MongoDB provides\r\na powerful backend for Perstore because it is specifically designed for JSON-style\r\nobject storage. This store has good querying capabilites, supporting a large set of \r\nthe RQL operators. This store requires installation\r\nof the mongodb package (npm install mongodb).\r\n\r\nThe MongoDB store looks to the local.json for configuration information, using either the\r\ndatabase.url property or the database.host, database.name, and database.port properties.\r\nFor example, our local.json could configuration the database:\r\n\r\n\t\"database\": {\r\n\t\t\"host\": \"localhost\",\r\n\t\t\"name\": \"wiki\",\r\n\t},\r\n\r\n(we omitted the port, which defaults to 27017)\r\n\r\nWe also must indicate which collection to use for the store. This is provided in the options\r\nparameter to the constructor.\r\n\r\nThis store is only available for NodeJS.\r\n\r\n### sql\r\n\r\n\tstore = require(\"perstore/store/mongodb\").SQLStore({\r\n\t\ttable: table,\r\n\t\tidColumn: idColumn\r\n\t});\r\n\r\n\r\nThis is store connects to an SQL backend and maps SQL rows to objects. RQL queries \r\nare converted to SQL, and a large set of the RQL queries are supported. On Node.js, this store requires installation\r\nof the mysql-native package (npm install mysql-native).\r\n\r\nThe SQLStore looks to the local.json for configuration information. In Node, it uses the \r\ndatabase.type, database.host, database.port, database.name, database.username, and database.password\r\nproperties to connect to the database. For example, our local.json could configuration the database:\r\n\r\n\t\"database\": {\r\n\t\t\"type\": \"mysql\",\r\n\t\t\"host\": \"localhost\",\r\n\t\t\"username\": \"root\",\r\n\t\t\"password\": \"password\",\r\n\t\t\"name\": \"wiki\",\r\n\t},\r\n\r\nThe type parameter indicates which SQL vendor dialect to use. Supported options are \r\n\"mysql\", \"sqlite\", \"derby\", \"hsqldb\", \"oracle\", \"postgres\", \"mssql\". \r\n\r\nIn Rhino, the \"connection\" property is used to configure the database, using a JDBC\r\nconnection string, and a driver property can be used to explicitly identifier the database\r\ndriver class to use (it will be determined from the type parameter otherwise).\r\n \r\nWe also must indicate which table and which column is the primary key to use for the store. This is provided in the options\r\nparameter to the constructor. The configuration parameter to the store can also\r\noverride the configuration information in local.json.\r\n\r\n### memory\r\n\r\nThis module provides an in-memory data store. This actually exports three different\r\nstore constructors for different storage capabilities:\r\n\r\n\tstore = require(\"perstore/store/memory\").Memory(options);\r\n\r\nThe Memory store keeps all data in memory (no persistence to disk). The options parameter\r\ncan include an optional \"log\" property indicating whether or not to keep a log of data revisions.\r\nThe \"log\" parameter defaults to true. \r\n\r\nThe options parameter may also include an optional \"index\" property that is a \r\nhash of the all the objects to initialize the store with, where the property names are the\r\nids and the property values are the objects in the store.\r\n\r\n\tstore = require(\"perstore/store/memory\").ReadOnly(options);\r\n\r\nThe ReadOnly store is equivalent to the Memory constructor except it generates a readonly store, and\r\ndoes not have any add, put, or delete methods.\r\n\r\n\tstore = require(\"perstore/store/memory\").Persistent(options);\r\n\r\nThe Persistent store is equivalent to the Memory constructor except it will persist\r\nthe data to a file. The data is persisted to a file in extended JSON format. The options\r\nparameter for the store supports an optional \"file\" parameter or \"path\" parameter to\r\nspecify the filename of the target file for persisting data, or the directory path to store\r\nfiles.\r\n\r\nThe Persistent store is the default store for Perstore.\r\n\r\n### redis\r\n\r\n\tstore = require(\"perstore/store/redis\").Redis({\r\n\t\tcollection: collection\r\n\t});\r\n\r\nThis is object store that uses a Redis database for storage. This requires the installation\r\nof the redis package.\r\n\r\n### remote\r\n\r\n\tstore = require(\"perstore/store/remote\").Remote(request, url);\r\n\r\nThis can connect to a remote HTTP/REST based JSON server to store and \r\nretrieve data. The optional request parameter is the function that will perform the \r\nremote requests, and defaults to an HTTP requester if no value is provided. The\r\nurl specifies the URL of target server.\r\n\r\n\r\nPerstore also includes several store wrappers that can be used to compose more \r\nsophisticated stores by adding functionality (also in the store directory), including cache,\r\naggregate, replicated, and inherited. The store implementations and store wrappers\r\nare described in more detail in the modules section below.\r\n\r\n### cache\r\n\r\n\tstore = require(\"perstore/store/cache\").Cache(masterStore, cacheStore, options);\r\n\r\nThis module adds caching support to a provided store. The main store is the first\r\nparameter, and data retrieved from that store is cached in the provided cacheStore.\r\nTypically the cacheStore would be an in-memory store, to provide quick access to\r\nfrequently accessed data. The options parameter provides several configuration options:\r\n\r\n* defaultExpiresTime - Default amount of time before an object in the cache expires in milliseconds, defaults to 2000.\r\n* cleanupInterval - Amount of time before cleaning up expired objects in the cache, in milliseconds, defaults to 1000.\r\n* cacheWrites - Determines whether or not to cache writes to the caching store (all writes go to the master store), defaults to true.\r\n\r\n### aggregate\r\n\r\n\tstore = require(\"perstore/store/aggregate\").Aggregate(stores, properties);\r\n\r\nThis store combines record data from multiple stores into a single object store. The\r\nstores argument should be an array of stores. When an object is requested, the request\r\nis made to each of the stores, and the returned objects are mixed together. When \r\na write is performed, the object can then be split up into the properties that are handled\r\nby each of the underlying stores. The properties argument specifies the properties\r\nfor each store. The properties argument should be an array (where each entry defines the \r\nproperties for the store with the corresponding index) of arrays of strings with the names\r\nof the properties for each store.\r\n\r\n### notifying\r\n\r\n\tnotifyingStore = require(\"perstore/store/notifying\").Notifying(sourceStore);\r\n\r\nThis store wrapper adds notification support to stores, allowing store consumers to\r\nlisten for data changes. We can listen for data changes by making a subscription and\r\nadding a listener:\r\n\r\n\tvar subscription = notifyingStore.subscribe(\"*\");\r\n\tsubscription.observe(listener);\r\n\t\r\nAnd you could later unsubscribe:\r\n\r\n\tsubscription.unsubscribe();\r\n\r\nor you can subscribe to a specific object by its id:\r\n\r\n\tvar subscription = notifyingStore.subscribe(id);\r\n\tsubscription.observe(listener);\r\n\r\n\r\n### replicated\r\n\r\n\tstore = require(\"perstore/store/replicated\").Replicated(sourceStore);\r\n\r\nThis store wrapper provides data replication across different processes. This is needed for memory\r\nstores in a multi-process applications where all processes need to be synchronized\r\naccess to data that is stored in separate memory spaces for each process.\r\n\r\n### inherited\r\n\r\n\tsuperStore = require(\"perstore/store/inherited\").Inherited(sourceStore);\r\n\tsubStore = require(\"perstore/store/inherited\").Inherited(sourceStore);\r\n\r\nInherited provides a super-sub type relationship between data stores. The Inherited constructor\r\nadds support for distinguishing different types in storage. The hierarchical relationships\r\nmust be defined at the model level with the schema \"extends\" property. \r\n\r\n## util (folder)\r\n\r\nThe util folder includes various utility modules used by Perstore.\r\n\r\n### json-ext\r\n\r\n\tjsonString = require(\"perstore/util/json-ext\").stringify(object);\r\n\tobject = require(\"perstore/util/json-ext\").parse(jsonString);\r\n\r\nThis provides support for JavaScript based object literals that extend basic JSON. This module\r\ncan serialize and parse JSON-style object literals with constructs including NaN, Infinity, \r\nundefined, and primitive function constructors (String, Number, etc.)\r\n\r\n### settings\r\n\r\n\tmySetting = require(\"perstore/util/settings\").mySetting;\r\n\t\r\nThis module parses the JSON in the local.json file found in the current working directory\r\nand puts all the properties on the module's export.\r\n\r\n### extend-error\r\n\r\nThis module provides an easy tool to create custom error constructors. To create a custom\r\nerror, provide an argument with the error type you want to extend from (Error or another more specific\r\nerror constructor), and then give it an error name. For example:\r\n\r\n\tCustomTypeError = require(\"perstore/util/extend-error\")(TypeError, \"CustomTypeError\");\r\n\r\n\r\n## jsgi\r\n\r\n### transactional\r\n\r\n transactionApp = require(\"perstore/jsgi/transactional\").Transactional(nextApp);\r\n\r\nThis module is a JSGI middleware module providing transaction wrapping around\r\na request/response cycle. See the Transaction section above for more information.\r\n\r\nLicensing\r\n--------\r\n\r\nPerstore is part of the Persevere project, and therefore is licensed under the\r\nAFL or BSD license. The Persevere project is administered under the Dojo foundation,\r\nand all contributions require a Dojo CLA.\r\n\r\nProject Links\r\n------------\r\n\r\nSee the main Persevere project for more information:\r\n\r\n### Homepage:\r\n\r\n* [http://persvr.org/](http://persvr.org/)\r\n\r\n### Source & Download:\r\n\r\n* [http://github.com/persvr/perstore/](http://github.com/persvr/perstore)\r\n\r\n### Mailing list:\r\n\r\n* [http://groups.google.com/group/persevere-framework](http://groups.google.com/group/persevere-framework)\r\n\r\n### IRC:\r\n\r\n* [\\#persevere on irc.freenode.net](http://webchat.freenode.net/?channels=persevere)\r\n","readmeFilename":"README.md","description":"Perstore is a cross-platform JavaScript object store interface for mapping persistent \r objects to various different storage mediums using an interface based on\r W3C's [IndexedDB object store API](http://www.w3.org/TR/IndexedDB/#object-store-sync)\r and analogous to the HTTP REST interface. Perstore\r includes JavaScript object-relational mapping for SQL databases, JSON file storage,\r and hopefully support for many other object/document style storage systems that\r provide more direct object storage. Perstore provides model classes that wrap data\r stores, and supports JSON Schema integrity enforcement, link management, and \r prototype construction. Perstore also provides faceted access to models for an\r object-capability based security model.","bugs":{"url":"https://github.com/kriszyp/tunguska/issues"},"_id":"perstore@0.3.3","dist":{"shasum":"bd5b60396225ba866d64e134455206b3ddd341ba","tarball":"https://registry.npmjs.org/perstore/-/perstore-0.3.3.tgz","integrity":"sha512-+D38EDFQzxOCzye1Jp5YnGSIplJzjO/W6zv3XpKnDQi0E6IDulXZbM0J11uDRHSJFxEUljSrBoSADc7Z1agnEQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIER3KyqLicu7tKgxpTQGCPJad2eW7Nop63hBHe39Cb4IAiEA/Gf1/bTtjrZVJ1ixsaAmaDRtUykXaxoK131UGdjS5VQ="}]},"_from":".","_npmVersion":"1.3.11","_npmUser":{"name":"dojofoundation","email":"kriszyp@gmail.com"}}},"readme":"Perstore is a cross-platform JavaScript object store interface for mapping persistent \r\nobjects to various different storage mediums using W3C's [IndexedDB object store API](http://www.w3.org/TR/IndexedDB/#object-store-sync). Perstore\r\nincludes JavaScript object-relational mapping for SQL databases, JSON file storage,\r\nand hopefully support for many other object/document style storage systems that\r\nprovide more direct object storage. Perstore provides model classes that wrap data\r\nstores, and supports JSON Schema integrity enforcement, link management, and \r\nprototype construction. Perstore also provides faceted access to models for an\r\nobject-capability based security model.\r\n\r\nSetup\r\n=====\r\n\r\nIt is recommended that you install Perstore such that it is available in require statements\r\nunder the \"perstore\" path. This can easily be done with a package mapping compliant module\r\nloader like [Nodules](http://github.com/kriszyp/nodules) by using a mapping in your \r\npackage.json:\r\n\r\n \"mappings\": {\r\n\t \"perstore\": \"http://github.com/kriszyp/perstore/zipball/master\"\r\n }\r\n\r\nAnd you need a local.json file in your current working directory for your application that\r\ndefines any database settings such as connection information. There is a [template\r\nfor local.json](http://github.com/kriszyp/perstore/blob/master/template.local.json).\r\n \r\nModel\r\n=====\r\n\r\nTypical usage of Perstore looks like:\r\n\r\n // first setup the object store, here we use SQL/ORM store\r\n var store = require(\"perstore/store/sql\").SQLStore({\r\n type: \"mysql\",\r\n table: \"my_table\",\r\n idColumn: \"id\"\r\n });\r\n \r\n // now we can setup a model that wraps the data store\r\n var MyModel = require(\"perstore/model\").Model(\"Example\", store, {\r\n \tproperties: {\r\n \t\t// we can define optionally define type constraints on properties\r\n \t\tfoo: String\r\n \t},\r\n \tprototype: {\r\n \t\t// we can define functions on the prototype of the model objects as well\r\n \t\tgetFoo: function(){\r\n \t\t\treturn this.foo;\r\n \t\t}\r\n \t}\r\n });\r\n // now we can interact with the store and it's objects\r\n var someObject = MyModel.get(someId); // retrieve a persisted object\r\n someObject.getFoo(); // returns the current value of foo\r\n someObject.foo = \"bar\"; // make a change\r\n someObject.save(); // and save it\r\n \r\n MyModel.delete(someOtherId); // delete an object\r\n \r\n var MyFacet = require(\"facet\").Restrictive(MyModel, {\r\n });\r\n\r\n\tMyFacet.delete(someId) -> will fail, as the facet has not allowed access to delete().\r\n\t\r\nA model is defined with the Model constructor in the \"MyModel\" module. A Model definition\r\nmay follow the JSON schema definition for contractual constraints (usually defining property\r\ntype constraints in the \"properties\" property and relations with the \"links\" property). \r\nproperty. It may also contain a prototype property which defines the prototype object\r\nfor all instances of the model. Methods can be defined on the prototype object, as well\r\nas directly on the model. REST methods such as get, put, and delete are implemented\r\ndirectly on the model, and can be overriden for specific functionality. Perstore roughly \r\nfollows the [class definition structure used by Persevere 1.0](http://docs.persvr.org/documentation/storage-model/json-schema)\r\n \r\nPerstore provides easy to use object persistence mechanism. Persisted model object\r\ninstances have two default methods and a property:\r\n\r\n- save() - Saves any changes that have been made to an object to the data store.\r\n- load() - If the object has not been fully loaded (sometime queries may return partial\r\nobject), the object will be fully loaded from the data store.\r\n- schema - This is a reference to the schema for this object. Schema objects are augmented\r\n(if it does not previously exist) with a getId method that can be used to retrieve the identity \r\nof an object:\r\n\r\n object.schema.getId(object) -> identity of object\r\n\r\n\r\nIn the initial example, object persistence is demonstrated with the \"someObject\"\r\nvariable. The object is loaded (via the get call to the model), modified, and saved\r\n(with the save() call).\r\n\r\nFacets provide secure, controlled access to models. The facet module comes provides\r\ntwo facet constructors: Permissive and Restrictive. A Permissive facet allows all actions\r\non the model by default. Methods can be defined/overriden in the Permissive definition\r\nto control or disable access to certain functionality. A Restrictive facet only allows read\r\naccess methods by default (get and query). One can define/override methods to allow\r\nexplicit access to other methods such as put or create. An example facet that only\r\nallows read access and creation of new objects:\r\n\r\n var facet = require(\"facet\").Restrictive(model, {\r\n create: function(object){ // allow create\r\n return model.create(object);\r\n }\r\n });\r\n\r\nModels wrap data stores, which provide the low level interaction with the database or \r\nstorage system. Perstore comes with several data stores including (in the store directory):\r\n\r\n- mongodb - This is object store that uses a MongoDB database for storage.\r\n- redis - This is object store that uses a Redis database for storage.\r\n- sql - An SQL-based object store. This stores and retrieves objects as rows in \r\ndatabases. Currently this only fully implemented in Rhino, but the sql data store can easily\r\nwrap an SQL database provider that simple provides an W3C SQL database style\r\nexecuteSql(sql) function.\r\n- memory - An in-memory data store. None of the data in this store will be persisted\r\n- js-file - Reads and stores all data in the store from a JSON (with JS extensions for \r\ndates and other non-standard JSON types) file.\r\n- remote - This can connect to a remote HTTP/REST based JSON server to store and \r\nretrieve data.\r\n\r\nPerstore also includes several store wrappers that can be used to compose more \r\nsophisticate stores by adding functionality (also in the store directory):\r\n\r\n- cache - Adds in-memory caching support to a provided store\r\n- aggregate - Combines record data from multiple stores into a single object store\r\n- replicated - Provides data replication across multiple stores\r\n- full-text - Adds full text indexing (currently only available in Rhino through Lucene)\r\n- inherited - Provides a super-sub type relationship between data stores\r\n\r\nThe following is store API for Perstore. The same API is used for data stores, store \r\nmodels, and facets. All of the functions are optional. If they do not exist, it indicates \r\nthat the store or model does not support or allow the said functionality. All of the \r\nfunctions may return a promise instead of \r\nthe actual return value if they require asynchronous processing to complete the \r\noperation. They are roughly listed in order of importance \r\n(get(id) is the most important function):\r\n\r\nget(id, directives) - Finds the persisted record with the given identifier from the store and returns \r\nan object representation (should always be a new object).\r\n\r\nput(object, directives) - Stores the given object in storage. The record may or may not \r\nalready exist. The optional second parameter \r\ndefines the primary identifier for storing the object. If the second parameter is omitted, the\r\nkey may be specified the primary identifier property. If that is not specified, the key may be\r\nauto-generated. The primary identifer for the object should be returned\r\n\r\ndelete(id, directives) - Deletes the record with the given identifier from the store.\r\n\r\nquery(queryString, directives) - This executes a query against the data store. The \r\nqueryString parameter defines the actual query, and the options parameter should be\r\nan object that provides extra information. The following properties on the options\r\nobject may be included:\r\n\r\n- start - The offset index to start at in the result set\r\n- end - The offset index to end at in the result set\r\n- parameters - An array of values for parameterized queries\r\n\r\nThe function should generally return an array representing the result set of the query \r\n(unless the query creates a single aggregate object or value). Perstore is designed to leverage [http://github.com/kriszyp/rql](resource query language)\r\nfor querying, and included stores use RQL, although stores can utilize alternate query languages. \r\n\r\nadd(object, directives) - Stores a new record. This acts similar to put, but should only be called\r\nwhen the record does not already exist. Stores do not need to implement this \r\nmethod, but may implement for ease of differentiating between creation of new \r\nrecords and updates. This should return the identifier of the newly create record. \r\n\r\nconstruct(object, directives) - This constructs a new persistable object. This does not\r\nactually store the object, but returns an object with a save() method that\r\ncan be called to store the object when it is ready. This method does not apply to stores,\r\nonly models and facets.\r\n\r\nsubscribe(resource, callback) - Subscribes to changes in the given resource or set of \r\nresources. The callback is called whenever data is changed in the monitored resource(s).\r\n\r\ntransaction() - Starts a new transaction for the store. This should return\r\na transaction object with the following functions. Each of these functions are optional\r\nand only called if they exist:\r\n\r\n- commit() - This is called when a transaction is committed.\r\n- requestCommit() - This is called on all the databases/stores prior to committing the\r\ntransaction. If this succeeds (doesn't throw an error), the store should guarantee the\r\nsuccess of a subsequent commit() operation. This provides two phase commit \r\nsemantics. \r\n- abort() - This is called when a transaction is aborted.\r\n- suspend() - This is called when a transaction is suspended. This happens when an \r\nevent is finished, but a promise for the continuance of the action is still in progress. \r\nAfter being suspended, this transaction is no longer the active transaction.\r\n- resume() - This is called when a transaction is resumed. This happens when a promise\r\nresumes the execution of an action.\r\n\r\n(See Transactions section below for more information)\r\n\r\nPerstore is designed to allow easy construction of new data stores. A data store \r\nin Perstore is a JavaScript object with any or all of the functions defined above.\r\n\r\nQuerying\r\n========\r\n\r\nPerstore provides a query parsing and execution through [http://github.com/kriszyp/rql](resource query language) \r\n(RQL). RQL can be thought as basically a set of\r\nnestable named operators which each have a set of arguments. RQL is designed to\r\nhave an extremely simple, but extensible grammar that can be written in a URL friendly query string. A simple RQL\r\nquery with a single operator that indicates a search for any resources with a property of\r\n\"foo\" that has value of 3 could be written:\r\n\r\n eq(foo,3)\r\n\r\nRQL is a compatible superset of standard HTML form URL encoding. The following query\r\nis identical to the query (it is sugar for the query above):\r\n\r\n foo=3\r\n\r\nWe can use this query format to query stores and models. For example:\r\n\r\n MyModel.query(\"foo=3\").forEach(function(object){\r\n // for each object with a property of foo equal to 3\r\n });\r\n\r\nWe can also construct queries using chained operator calls in JavaScript. We could\r\nwrite this query:\r\n\r\n MyModel.query().eq(\"foo\",3).forEach(...);\r\n\r\nThe RQL grammar is based around standard URI delimiters. The standard rules for \r\nencoding strings with URL encoding (%xx) are observed. RQL also supersets FIQL. \r\nTherefore we can write a query that finds resources with a \"price\" property below\r\n10 with a \"lt\" operator using FIQL syntax:\r\n\r\n price=lt=10\r\n\r\nWhich is identical (and sugar for call operator syntax known as the normalized form):\r\n\r\n lt(price,10)\r\n\r\nOne can combine conditions with multiple operators with \"&\":\r\n\r\n foo=3&price=lt=10\r\n\r\nIs the same as:\r\n\r\n eq(foo,3)<(price,10)\r\n\r\nWhich is also the same as:\r\n\r\n and(eq(foo,3),lt(price,10))\r\n\r\nAnd thus can be used to query a store:\r\n\r\n\tMyModel.query(\"foo=3&price=lt=10\")...\r\n\r\nOr using chained JS calls to perform the same query:\r\n\r\n MyModel.query().eq(\"foo\",3).lt(\"price\",10)...\r\n\r\nThe | operator can be used to indicate an \"or\" operation. We can also use paranthesis\r\nto group expressions. For example:\r\n\r\n (foo=3|foo=bar)&price=lt=10\r\n \r\nWhich is the same as:\r\n\r\n and(or(eq(foo,3),eq(foo,bar)),lt(price,10))\r\n\r\nAnd to query a model/store:\r\n\r\n MyModel.query(\"(foo=3|foo=bar)&price=lt=10\")...\r\n \r\nAnd using chained JS calls: \r\n\r\n\tvar query = MyModel.query();\r\n\tquery.or(query.eq(\"foo\",3),query.eq(\"foo\",\"bar\")).lt(\"price\",10)...\r\n\r\nSometimes it makes sense to use the with statement (despite the fact that some \r\nthink it should never be used). This actually makes the syntax look very similar\r\nto the query string format. For example:\r\n\r\n\twith(MyModel.query()){\r\n\t\tor(eq(\"foo\",3),eq(\"foo\",\"bar\")).lt(\"price\",10)...\r\n\t}\r\n\r\nFor a more a complete reference guide to the RQL and the available query operators,\r\nsee [[http://github.com/kriszyp/rql]]. This also provides information on\r\nthe parsed query data structure which is important if you want to implement your\r\nown custom stores.\r\n\r\nTransactions\r\n==========\r\n\r\nTransactions provide a means for committing multiple changes to a database \r\natomically. The store API includes transaction semantics for communicating transactions\r\nto the underlying databases. Perstore provides transactional management for delegating\r\ntransaction operations to the appropriate stores and databases. To start a transaction,\r\ncall the transaction function on the stores module with a callback that will perform any\r\nof the actions of the transaction:\r\n\r\n require(\"perstore/transaction\").transaction(function(){\r\n \tModel.put(...);\r\n \tModel.delete(...);\r\n });\r\n \r\nThe callback function may return a promise if the transaction will involve actions that\r\nextend beyond the duration of the function call. When the promise is resolved the \r\ntransaction will be committed (or if the promise errors out, the transaction will be \r\naborted).\r\n\r\nPerstore includes a JSGI middleware component for wrapping requests in transactions.\r\nThis will make the life of the request be one transaction, committed when the response\r\nis ready to send (or aborted for an error).\r\n\r\n transactionApp = require(\"perstore/jsgi/transactional\").Transactional(nextApp);\r\n\r\nImplementing Transactions\r\n------------------------\r\n\r\nIf you are writing your store that needs to be transaction aware, there are two \r\ndifferent options for implementing transaction handling. The simplest approach is to\r\nimplement the implement the transaction method on your store and then use the\r\nAutoTransaction store wrapper provided by the \"stores\" module:\r\n\r\n var AutoTransaction = require(\"perstore/transaction\").AutoTransaction;\r\n myTransactionalStore = AutoTransaction({\r\n transaction: function(){\r\n // prepare the transaction\r\n return {\r\n commit: function{\r\n // commit the transaction\r\n },\r\n // implement the rest of the handlers\r\n abort:...\r\n }\r\n }\r\n });\r\n\r\nThe AutoTransaction wrappers provides two important functions. First, if any of your\r\nstore methods are called outside of a global transaction, a transaction will automatically\r\nbe started before calling the method and committed afterwards. Second, if a global\r\ntransaction is in process, the transaction method will be called on the first access of\r\nthis store and be committed when the global transaction is committed.\r\n\r\nThe other approach to transaction handling is to provide a \"database\" object. This can\r\nbe useful for situations where transaction management needs to exist outside of \r\nindividual stores (and may cross stores). One can implement a \"database\" object that\r\nprovides the transaction method with the same API as the store's transaction method.\r\nThe database object can be registered with:\r\n\r\n require(\"perstore/transaction\").registerDatabase(transaction: function(){\r\n // prepare the transaction\r\n return {...}\r\n });\r\n \r\nThis transaction method will be called whenever a global transaction is started.\r\n \r\nLicensing\r\n--------\r\n\r\nPerstore is part of the Persevere project, and therefore is licensed under the\r\nAFL or BSD license. The Persevere project is administered under the Dojo foundation,\r\nand all contributions require a Dojo CLA.\r\n\r\nProject Links\r\n------------\r\n\r\nSee the main Persevere project for more information:\r\n\r\n### Homepage:\r\n\r\n* [http://persvr.org/](http://persvr.org/)\r\n\r\n### Source & Download:\r\n\r\n* [http://github.com/kriszyp/perstore/](http://github.com/kriszyp/perstore)\r\n\r\n### Mailing list:\r\n\r\n* [http://groups.google.com/group/persevere-framework](http://groups.google.com/group/persevere-framework)\r\n\r\n### IRC:\r\n\r\n* [\\#persevere on irc.freenode.net](http://webchat.freenode.net/?channels=persevere)\r\n","maintainers":[{"name":"dojofoundation","email":"kzyp@dojofoundation.org"}],"time":{"modified":"2022-06-23T19:05:54.549Z","created":"2011-11-16T17:18:19.219Z","0.3.0":"2011-11-16T17:18:20.548Z","0.3.1":"2012-04-19T14:28:55.398Z","0.3.2":"2012-09-19T21:49:54.399Z","0.3.3":"2013-09-25T20:04:45.257Z"},"author":{"name":"Kris Zyp"},"repository":{"type":"git","url":"http://github.com/kriszyp/tunguska"},"description":"Perstore is a cross-platform JavaScript object store interface for mapping persistent \r objects to various different storage mediums using an interface based on\r W3C's [IndexedDB object store API](http://www.w3.org/TR/IndexedDB/#object-store-sync)\r and analogous to the HTTP REST interface. Perstore\r includes JavaScript object-relational mapping for SQL databases, JSON file storage,\r and hopefully support for many other object/document style storage systems that\r provide more direct object storage. Perstore provides model classes that wrap data\r stores, and supports JSON Schema integrity enforcement, link management, and \r prototype construction. Perstore also provides faceted access to models for an\r object-capability based security model."}