{"maintainers":[{"name":"anonymous","email":"jane@cpan.org"}],"keywords":["riak","synchronous","simple","promises","q","orm","object","relational","model","sendak"],"dist-tags":{"latest":"0.1.8"},"author":{"name":"Jane Arc","email":"jane@cpan.org","url":"http://github.com/janearc"},"description":"An object storage layer for Riak","readme":"RM, an ORM\\* for Riak\n====\n\nSo in the course of building [Sendak](https://github.com/18F/Sendak) for\n[18F](https://18f.gsa.gov/), I wanted to use an ORM. I found that ORMs\nwere very complicated. I found that node itself was kind of poorly-suited\nto the way that ORMs worked. I also found that ORMs (for Javascript)\ngenerally did not provide the functionality I wanted (for example\nkeeping state in the database).\n\nAs I sat down to write my own ORM, I realised that the biggest part of it,\ncode-wise, was going to actually be the SQL layer. As it happens, writing\nSQL parsers, SQL generators, stored procedures, and so forth, while\nmaintaining an agnostic stance towards choice of database (even without this),\nthe task is nothing less than odious, and results in huge code-sprawl, when\nall I wanted was a way to create some simple objects and store them in a\nplace that bunches of things could get to (accordingly, a json file was not\nsufficient), and I didn't want to have to worry about the \"database layer\";\nI wanted objects &mdash; data structures &mdash; that I could read and write\nwithout having data logic in my code.\n\nThere are lots of document-store and key-value store \"databases\" out there.\nFor various reasons, I chose Riak to put this on top of. No more need for\nSQL, native storage of JSON, and it seemed like a win.\n\nRather than use the rather ponderous and somewhat inscrutable [riak-js](http://riakjs.com/),\nI wrote a very tiny library, [riak-dc](https://github.com/janearc/riak-dc), which is\nthe barest of wrappers around node's own [http](http://nodejs.org/api/http.html).\n\nAccordingly, you will find that this library is very tiny, takes up very\nlittle space in terms of lines-of-code, is end-to-end javascript & json, and\nmeets the above requirements:\n\n* No stupid SQL tricks\n* JSON object storage\n* Schema stored in the database\n* Exceedingly simple API\n* No pyramid of fail\n\n\\* note: RM is not actually \"relational.\"\n\nHow to use RM\n====\n\nBasically, `npm install rm` should do the trick and install dependencies.\nUnit tests are mocked, but you will need a Riak somewhere to talk to. `riak-dc`\nassumes that you are using `http://localhost:8098/riak`, and if you are, RM\nrequires no configuration. If not, be sure to initialise `riak-dc` before\nusing RM.\n\n#### Key concepts:\n\nRM stores a 'schema' in Riak, from which it derives prototypes of each of the\nobject types stored in the RM. The schema is not actually \"bound\" to\nanything, as such, and serves only as a template from which to build new\nobjects.\n\nThese objects are stored in a Riak bucket according to their prototype (so all\nthe 'automobile' objects are stored in `riak/automobile/{serial}`).\n\nObjects are \"anonymous\" until they are stored in Riak, which gives them a\nunique serial (for SQL people, you might call this a 'primary key').\n\nObjects also contain no metadata about what they are. So you must keep track\nof which type of object you have. RM is flexible enough that if you wanted to\nincorporate a `typeof` attribute, you could do this, but you would have to\nkeep track of that yourself.\n\nThere is no strict checking for whether an object you are storing actually\nconforms to the schema.\n\n#### Exported functions:\n\nUnless otherwise specified, all references to returned values are actually\npromises (using `q`, rather than the value itself). So \"returns a hash\" means\n\"returns a promise to a hash.\"\n\n* `add_object( type, object )`\n\nTakes two arguments, the type of object being added and an anonymous object to\nbe added. Note that if this object is already in Riak, an Error will be\nreturned. For existing objects, use `update_object`.\n\n* `del_object( type, object )`\n\nTakes two arguments, the type of object to be deleted from Riak and the object\nitself. This object must have a serial, or an exception will be thrown.\n\n* `get_objects( type )`\n\nTakes one argument, the type of objects requested. This returns *all* the\nobjects of that type in Riak. This is actually a very fast operation in Riak\nat most practical scales.\n\nBecause Riak allows the storage of zero-byte tuples, it is possible to store\nan object in Riak which is defined but null. In the event this happens, you\nwill receive an Error instead of the object (rather than not returning or\nreturning the empty list or similar).\n\n* `get_schema( )`\n\nReturns a hash of what the objects look like in Riak. This includes metadata\nand should not be used to \"create new objects\" (see `new_object`). Takes no\narguments.\n\n* `new_object( type )`\n\nTakes object type as sole argument, and returns a new object with relevant\nattributes from the schema. This will not be stored until `add_object` is\ncalled.\n\n* `object_types( )`\n\nTakes no arguments and returns a list of object types defined in the schema.\n\n* `update_object( type, object )`\n\nProvided a type and object, RM will attempt to find the object in Riak,\n*delete* that object, and re-insert, providing you with a new copy of your\nobject with appropriate serial. Note that deleted objects are\n[tricky](http://docs.basho.com/riak/latest/ops/advanced/deletion/#Tombstones)\nin Riak, so be sparing about the this operation (delete & insert).\n\n#### The basic design pattern\n\n```\nvar rm     = require( 'rm' )\n\t, types   = rm.object_types()\n\t, schema  = rm.get_schema()\n\t, banana  = rm.new_object( 'fruit' );\n\nbanana['color'] = 'green';\n\nvar pbanana = rm.add_object( banana ).then( function (b) {\n\t// 'pbanana' infers 'promise to a banana'\n\t//\n\t// the banana object now has a serial and can be referenced in Riak.\n\tbanana = b;\n\n\t// Time elapses...\n\n\tbanana['color'] = 'yellow';\n\n\tvar promise = rm.update_object( 'fruit', banana );\n\n\tpromise.then( function (b) {\n\t\t// What will you do with your now-yellow banana?\n\t\t//\n\t\tbanana = b;\n\n\t\t// Time elapses...\n\n\t\t// This will not return anything meaningful, although an error will be\n\t\t// returned if the serial for this banana is not found.\n\t\t//\n\t\trm.del_object( 'fruit', banana ).then( function (e) {\n\t\t\tif (typeof e == 'error') {\n\t\t\t\tconsole.log( e )\n\t\t\t}\n\t\t} );\n\t} );\n\n} );\n```\n\nWhat's in the box\n====\n\nThere are two tools in the `bin` directory, `rm.js` and `backupdb.js`.\n\n* `rm.js` is a simple command-line tool to interface with RM. For\nexample, `--get-schema` will return the schema as it appears in Riak, and you\ncan use `--add-object --bucket bucketname --tuple base_64_encoded_object` to\nadd elements to the database. And so on.\n\n* `backupdb.js` because Riak is not a relational database, we don't have\nanything analogous to\n[`pg_dumpall`](http://www.postgresql.org/docs/9.3/static/app-pg-dumpall.html),\nand no real formal language in which to dump the database. But it is still\nimportant to have backups in a modern, production environment. So\n`backupdb.js` is a sort of minimum-effort \"store all the things in the\ndatabase on the disk somewhere.\" It can print to stdout for unixy pipey kinds\nof things, take a filename, or an s3 bucket (you will need credentials for\nthis, obviously).\n\nIf you need to effectively \"truncate\" the database, there's a tool in the\n[riak-dc package](https://github.com/janearc/riak-dc/blob/master/bin/init-riak.js)\nthat will remove everything from the Riak ring. Careful with that axe, Eugene.\n\nFuture plans\n====\n\nIf you look over the schema in `examples/`, you will notice I have left a\ncouple fields reserved, and have stubs for relational properties. At some\npoint RM may actually be relational, but it serves my purpose for now.\nAdditionally, Riak supports Javascript, so it should be possible to add\nconstraints to columns (that is, attributes of objects) such as \"only allow\nthis to be a url\" and similar.\n\nDon't mess with those fields.\n\nI'm not going to break compatibility for a long time, though. So, in the event\nthose things are added, it should be transparent.\n\nAuthor\n====\n\n[@janearc](https://github.com/janearc), jane@cpan.org\n","repository":{"type":"git","url":"git+https://github.com/janearc/rm.git"},"users":{},"bugs":{"url":"https://github.com/janearc/rm/issues"},"license":"CC0-1.0","versions":{"0.3.0":{"name":"rm","version":"0.3.0","description":"An object storage layer for Riak","main":"lib/rrm.js","directories":{"test":"test"},"scripts":{"test":"mocha"},"repository":{"type":"git","url":"https://github.com/janearc/rm.git"},"keywords":["riak","synchronous","simple","promises","q","orm","object","relational","model","sendak"],"author":{"name":"Jane Arc","email":"jane@cpan.org","url":"http://github.com/janearc"},"license":"CC0-1.0","bugs":{"url":"https://github.com/janearc/rm/issues"},"dependencies":{"riak-dc":">=0.2.5","mocha":"*","nock":"*","log4js":"*","deep-grep":">=0.3.5","chai":"*","q":"*","chai-as-promised":"*","sendak-usage":">=0.0.6","moment":">=2.0.0"},"homepage":"https://github.com/janearc/rm","gitHead":"ef40f5b7b32786adfad086d200e26dffb77fc85b","_id":"rm@0.3.0","_shasum":"728e4669c1ff78fbc1d56b1dc1e52090b18fd221","_from":".","_npmVersion":"2.0.0-alpha-5","_npmUser":{"name":"anonymous","email":"jane@cpan.org"},"maintainers":[{"name":"anonymous","email":"jane@cpan.org"}],"dist":{"shasum":"728e4669c1ff78fbc1d56b1dc1e52090b18fd221","tarball":"http://repository.ncinga.com/nexus/content/groups/npm-all/rm/-/rm-0.3.0.tgz","integrity":"sha512-GI7guT/PV/vWQZeoaAcJnGFqU4LM0/5DA4yZdmRpCwFOiUWDkGmRs/knQqWGtXrMH59VTiNR9L8TQg+bP4gDSQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDbmt0fxCOH0FbvNOpj1Uc1iU+gIVN4a1Tk7TEmLePXAwIgUzlixXg88FBHzTS6QcNhslCGyKdsaiqo7XT50WBSUns="}]}},"0.1.4":{"name":"rm","description":"An object storage layer for Riak","version":"0.1.4","main":"lib/rm.js","directories":{"test":"test"},"scripts":{"test":"mocha"},"repository":{"type":"git","url":"https://github.com/janearc/rm.git"},"keywords":["riak","synchronous","simple","promises","q","orm","object","relational","model","sendak"],"author":{"name":"Jane Arc","email":"jane@cpan.org","url":"http://github.com/janearc"},"license":"CC0-1.0","bugs":{"url":"https://github.com/janearc/rm/issues"},"dependencies":{"riak-dc":">=0.3.0","mocha":"*","nock":"*","log4js":"*","deep-grep":">=0.4.0","chai":"*","q":"*","chai-as-promised":"*","sendak-usage":">=0.0.6","moment":">=2.0.0"},"homepage":"https://github.com/janearc/rm","gitHead":"e8f490f3bee425e0fff6a5df03be10e585be52c4","_id":"rm@0.1.4","_shasum":"e8fd43cf3e46f8bf8ab69e136bf7baf70452d68c","_from":".","_npmVersion":"2.0.0-alpha-5","_npmUser":{"name":"anonymous","email":"jane@cpan.org"},"maintainers":[{"name":"anonymous","email":"jane@cpan.org"}],"dist":{"shasum":"e8fd43cf3e46f8bf8ab69e136bf7baf70452d68c","tarball":"http://repository.ncinga.com/nexus/content/groups/npm-all/rm/-/rm-0.1.4.tgz","integrity":"sha512-bS9hvZKIrimhfgoFU5G7dNuJE4/XVphCOIlv2PjW0niJKPPBNRfQB1wo3nHKws8XSEQW3Qi39PmK1BHmPktl+w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCvOn1seq3mReDwdpbFJGvqjnAeIOm2599yUqgXYnpsrAIhAKL1asw9NAUBB3VeoCsQWNH0u02PnTpKU5apLS1RXT01"}]}},"0.1.5":{"name":"rm","description":"An object storage layer for Riak","version":"0.1.5","main":"lib/rm.js","directories":{"test":"test"},"scripts":{"test":"mocha"},"repository":{"type":"git","url":"https://github.com/janearc/rm.git"},"keywords":["riak","synchronous","simple","promises","q","orm","object","relational","model","sendak"],"author":{"name":"Jane Arc","email":"jane@cpan.org","url":"http://github.com/janearc"},"license":"CC0-1.0","bugs":{"url":"https://github.com/janearc/rm/issues"},"dependencies":{"riak-dc":">=0.3.0","mocha":"*","nock":"*","log4js":"*","deep-grep":">=0.4.0","chai":"*","q":"*","chai-as-promised":"*","sendak-usage":">=0.0.6","moment":">=2.0.0"},"homepage":"https://github.com/janearc/rm","gitHead":"25ced7fcdde34e956df1454e71a227a52562fa5e","_id":"rm@0.1.5","_shasum":"3d4752f431485e9cd1768f5ef46e9ac85ce44531","_from":".","_npmVersion":"2.0.0-alpha-5","_npmUser":{"name":"anonymous","email":"jane@cpan.org"},"maintainers":[{"name":"anonymous","email":"jane@cpan.org"}],"dist":{"shasum":"3d4752f431485e9cd1768f5ef46e9ac85ce44531","tarball":"http://repository.ncinga.com/nexus/content/groups/npm-all/rm/-/rm-0.1.5.tgz","integrity":"sha512-4XR4xnGkVsv36gcs5zPJHhvH5ftKh2cgyaQgITgENvAYpsusc+iC9YXahkXHEyFZ4qvxWU35+FQ+OXpbI+uI8A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICKAgoac4sbuwRdnyd1MtQfNm+QTHtZtc/fHo01d+iXUAiEAmGzZ36Fa7PY626hRw+ekU6CnGSMb/9BoPXwsZF/tQqM="}]}},"0.1.6":{"name":"rm","description":"An object storage layer for Riak","version":"0.1.6","main":"lib/rm.js","directories":{"test":"test"},"scripts":{"test":"mocha"},"repository":{"type":"git","url":"https://github.com/janearc/rm.git"},"keywords":["riak","synchronous","simple","promises","q","orm","object","relational","model","sendak"],"author":{"name":"Jane Arc","email":"jane@cpan.org","url":"http://github.com/janearc"},"license":"CC0-1.0","bugs":{"url":"https://github.com/janearc/rm/issues"},"dependencies":{"riak-dc":">=0.3.1","mocha":"*","nock":"*","log4js":"*","deep-grep":">=0.4.0","chai":"*","q":"*","chai-as-promised":"*","sendak-usage":">=0.0.6","moment":">=2.0.0"},"homepage":"https://github.com/janearc/rm","gitHead":"5b2afa83a4ec42ede5bd1e50db88617dc81889e6","_id":"rm@0.1.6","_shasum":"f361b75c62064d589409239af39a370753c2d87e","_from":".","_npmVersion":"2.0.0-alpha-5","_npmUser":{"name":"anonymous","email":"jane@cpan.org"},"maintainers":[{"name":"anonymous","email":"jane@cpan.org"}],"dist":{"shasum":"f361b75c62064d589409239af39a370753c2d87e","tarball":"http://repository.ncinga.com/nexus/content/groups/npm-all/rm/-/rm-0.1.6.tgz","integrity":"sha512-sAKZEE/dKQTGrGXdT6hBb5Si757ZPK6sOxpQ9ZZyYeY/xrNXBrpdz8rVmZHVukL0h3a7I6S6pwoeOJuNtUp/ew==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIErDNJ24g2fOgDkWYAQG/VKrxdbJD3jtZVAT/1/l7EhQAiEAjXJaJVahNxTP7WQ22f2bqywAU7783z+0+LXKT4KBFtg="}]}},"0.1.7":{"name":"rm","description":"An object storage layer for Riak","version":"0.1.7","main":"lib/rm.js","directories":{"test":"test"},"scripts":{"test":"mocha"},"repository":{"type":"git","url":"git+https://github.com/janearc/rm.git"},"keywords":["riak","synchronous","simple","promises","q","orm","object","relational","model","sendak"],"author":{"name":"Jane Arc","email":"jane@cpan.org","url":"http://github.com/janearc"},"license":"CC0-1.0","bugs":{"url":"https://github.com/janearc/rm/issues"},"dependencies":{"riak-dc":">=0.3.1","mocha":"*","nock":"*","log4js":"*","deep-grep":">=0.4.0","chai":"*","q":"*","chai-as-promised":"*","sendak-usage":">=0.0.6","moment":">=2.0.0"},"homepage":"https://github.com/janearc/rm","gitHead":"c25034cc6d56694fd6485e9486588a5f381d4269","_id":"rm@0.1.7","_shasum":"5912485900d2a49a62aeb4b9e45e0c332d9a5906","_from":".","_npmVersion":"3.10.9","_nodeVersion":"7.2.1","_npmUser":{"name":"anonymous","email":"jane.arc@pobox.com"},"dist":{"shasum":"5912485900d2a49a62aeb4b9e45e0c332d9a5906","tarball":"http://repository.ncinga.com/nexus/content/groups/npm-all/rm/-/rm-0.1.7.tgz","integrity":"sha512-hEIoub3ObIW8XyYfEz0a40vo2TZE+lbRxbGARPQN2ygbwgDLtLAXjpV6S1OvJ6/MuAQBJYkfGxmScjwYyM2J1A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBT6Pd1JiIugaq/1W0dZathGPKsSAEPRxjsVOrp2q72pAiEArO//S2UsoHYb5K9tWXykDvfwhod0/LVu/Y7S/2r2S3M="}]},"maintainers":[{"name":"anonymous","email":"jane@cpan.org"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/rm-0.1.7.tgz_1481418589555_0.02139367675408721"}},"0.1.8":{"name":"rm","description":"An object storage layer for Riak","version":"0.1.8","main":"lib/rm.js","directories":{"test":"test"},"scripts":{"test":"mocha"},"repository":{"type":"git","url":"git+https://github.com/janearc/rm.git"},"keywords":["riak","synchronous","simple","promises","q","orm","object","relational","model","sendak"],"author":{"name":"Jane Arc","email":"jane@cpan.org","url":"http://github.com/janearc"},"license":"CC0-1.0","bugs":{"url":"https://github.com/janearc/rm/issues"},"dependencies":{"riak-dc":">=0.3.1","mocha":"*","nock":"*","log4js":"*","deep-grep":">=0.4.0","chai":"*","q":"*","chai-as-promised":"*","sendak-usage":">=0.0.6","moment":">=2.0.0"},"homepage":"https://github.com/janearc/rm","gitHead":"0c4e53fa2d1a4e7214de9899676600922477b070","_id":"rm@0.1.8","_shasum":"06d2fadbf661390f697d73b05e0be8c239bfbc7e","_from":".","_npmVersion":"3.10.9","_nodeVersion":"7.2.1","_npmUser":{"name":"anonymous","email":"jane.arc@pobox.com"},"dist":{"shasum":"06d2fadbf661390f697d73b05e0be8c239bfbc7e","tarball":"http://repository.ncinga.com/nexus/content/groups/npm-all/rm/-/rm-0.1.8.tgz","integrity":"sha512-5nCVLbXx/Qio6tDxQX8mGI1Ugrh9TQqurQx/eEqHLU8fIi+80P56IrmFD+KrJ2g4FPuQWskD6Q2674BuHPt4Bg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICSGrR1oK/gLs+s+oxabKZZhc9N+eG97dBPb6k8pf7IYAiBQ1DodLNS4DT5E3OrM+eEQ3Fq1YjzDEiBrcz04xsepvw=="}]},"maintainers":[{"name":"anonymous","email":"jane@cpan.org"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/rm-0.1.8.tgz_1481418724547_0.5313993473537266"}}},"name":"rm","time":{"modified":"2022-06-26T13:31:38.922Z","created":"2015-02-19T22:39:33.857Z","0.3.0":"2015-02-19T22:39:33.857Z","0.1.4":"2015-02-24T21:52:30.724Z","0.1.5":"2015-02-24T22:05:02.659Z","0.1.6":"2015-03-17T18:32:48.235Z","0.1.7":"2016-12-11T01:09:49.790Z","0.1.8":"2016-12-11T01:12:06.387Z"},"readmeFilename":"README.md","homepage":"https://github.com/janearc/rm"}