{"id":21669335,"url":"https://github.com/attack-monkey/store","last_synced_at":"2026-05-09T18:32:33.271Z","repository":{"id":91874073,"uuid":"134835738","full_name":"attack-monkey/store","owner":"attack-monkey","description":"Like normal javascript objects - but - with super powers","archived":false,"fork":false,"pushed_at":"2018-06-26T23:20:09.000Z","size":62,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-01-25T08:43:43.656Z","etag":null,"topics":["immutable","javascipt","json","query","store"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/attack-monkey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-25T09:36:14.000Z","updated_at":"2018-06-26T23:20:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"8c76318c-74b8-4b28-9d65-37f340aeb76d","html_url":"https://github.com/attack-monkey/store","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2Fstore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2Fstore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2Fstore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2Fstore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/attack-monkey","download_url":"https://codeload.github.com/attack-monkey/store/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244570080,"owners_count":20473978,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["immutable","javascipt","json","query","store"],"created_at":"2024-11-25T12:20:59.276Z","updated_at":"2026-05-09T18:32:33.262Z","avatar_url":"https://github.com/attack-monkey.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Store.js\n========\n\nStore is a local JSON store for javascript. It differs from a normal object in that it is dereferenced from any other object. Only specific methods can get, create, update, delete data. When `get` returns data, it is only a copy - keeping the original unchanged. Store also provides querying (sort, limit, filter), locking, and more...\n\n_Normal objects..._\n\n```javascript\n\nvar obj1 = {thing: 'apple'};\nvar obj2 = obj1;\nobj2.thing = 'banana';\nconsole.log(obj1.thing); // Oh no it's changed to banana!\n\n```\n\n_Store objects..._\n\n```javascript\n\nconst obj1 = new Store({thing: 'apple'});\nconst obj2 = obj1.get();\nobj2.thing = 'banana';\nconsole.log(obj1.get('thing')); // Still apple baby!\n\n```\n\n## Features\n\n- Holds a JSON object with no reference to other objects\n- Is protected and can only be retrieved with `.get()` and updated with methods such as `set`, `push`, `unshift`, `update`, and `apply`\n- `.get()` returns a copy of the object, keeping the original object unchanged\n- When nodes are added, any missing parent nodes are added automatically\n- When nodes are deleted, any redundent parent nodes are cleaned up automatically\n- A Store can be locked and unlocked to aid in data not being accidentally changed\n- Advanced querying with filters, limits, and multi-level sorting\n\n## Install\n\n### ES6 / Typescript\n\nUse either store.ts or store.js from /src\n\n```javascript\n\ninstall { Store } from './src'\n\n```\n\n\u003e Note: If not using ES6 style imports, use /src/index.js and modify the export style\n\n### Run this example project\n\nclone the repo\n\n$ `https://github.com/attack-monkey/store`\n\ninstall parcel.js globally. Required to run the project.\n\n$ `npm install -g parcel-bundler`\n\nRun the project which will automatically install typescript into the project\n\n$ `npm start`\n\nThis will run the project locally on localhost:1234 by default\n\n\n## Basics\n\n```javascript\n\n let store = new Store({});\n \n store.set('lvl1/lvl2', 'hello')\t// Adds or updates the node and adds any parents if missing\n store.set('lvl1/lvl2', undefined) \t// Deletes the node and cleans up any child-less parent nodes (undefined / null / [] / {}) all result in delete\n store.get();\t\t\t\t// gets the full contents of store\n store.get('lvl1');\t\t\t// gets the contents of store at a particular node\n store.lock();\t\t\t\t// Restricts any changes to the store\n store.unlock();\t\t\t// Removes the lock\n ```\n \n## PushArrays\n\nWhile you can get and set arrays, Store provides a more powerful solution in the form of pushArrays.\n\nTo create a pushArray just use .push() in place of set.\n\n```javascript\n\nstore.push('lvl1', ['a', 'b', 'c']);\n\n```\n\nIf you use push when there is already a pushArray present, then the new items are appended to the existing pushArray.\n\n```javascript\n\nstore.push('lvl1', ['d', 'e']);\n\n```\n\nYou can also push single values...\n\n```javascript\n\nstore.push('lvl1', 'f');\n\n```\n\n**To push items to the front of the pushArray use `.unshift()` instead of `.push()`**\n\npushArrays are stored as an array of rows. A row is just an object with an id and value. `id` is a unique sequential ID and `value` is the value of the array item.\n\n```javascript\n\n{\n\tlvl1: [\n\t\t{id: 1, value: 'a'},\n\t\t{id: 2, value: 'b'},\n\t\t{id: 3, value: 'c'},\n\t\t{id: 4, value: 'd'},\n\t\t{id: 5, value: 'e'},\n\t\t{id: 6, value: 'f'}\n\t]\n}\n\n```\n\nA pushArray can be retrieved in full with `store.get('lvl1')` which returns\n\n```javascript\n\n[\n\t{id: 1, value: 'a'},\n\t{id: 2, value: 'b'},\n\t{id: 3, value: 'c'},\n\t{id: 4, value: 'd'},\n\t{id: 5, value: 'e'},\n\t{id: 6, value: 'f'}\n]\n\n```\n\nA pushArray row can be retrieved directly by `$\u003cid\u003e` - eg.  \n\n`store.get('lvl1/$1')` which returns `{id: 1, value: 'a'}`.\n\n### Stripping meta-data from the pushArray result\n\nTo strip the meta-data from an individual pushArray row, just get the value \n\n`store.get('lvl1/$1/value')` which returns just the value 'a'.\n\nTo strip the meta data from a full pushArray result set, use  \n\n`store.get('lvl1', {})` - which returns `['a', 'b', 'c', 'd', 'e', 'f']`\n\nThe second argument in the above `.get()` is an a empty 'query options' object, which tells Store that it's querying a pushArray and expects an array (without meta-data) back.\n\n### Queries\n\nBy passing a 'query options' object with `.get()`, powerful queries are possible.  \nA 'query options' object tells Store that it's querying a pushArray and expects an array (without meta-data) back.\n\nYou can still specify to have the result with meta-data by passing \n`meta: true` ...\nFor example:\n\n`store.get('lvl1', {meta: true})` \n\n#### Filter\n\npushArrays can be filtered by passing in a filter function\nFor example, here we filter out any items that are not of type string...  \n\n`store.get('lvl1', {filter: row =\u003e typeof row.value === 'string'});`  \n\nA filter function passes each row into the filter and evaluates it to a boolean result.\nIf a filter function against a row equates to true, the row will be returned in the result set.\n\n#### Sort and Limit\n\npushArrays can be sorted and limited ... \n\n`store.get('lvl1', {sort: {by: 'value', dir: 'desc'}, limit: 3})` returns `['f', 'e', 'd']`  \n\nand multi value sorted...  \n\n`store.get('lvl1', {sort: [{by: 'value', dir: 'desc'}, {by: id', dir: 'asc'}], limit: 3})`  \nwhich sorts by value in descending order, then id in ascending order.\n\nand sorted by child nodes...  \n`store.get('lvl1', {sort: {by: 'value/category', dir: 'desc'}, limit: 3})`\n\n### Deleting pushArray rows\n\npushArray rows can be deleted with the normal set syntax...\n\n`store.set('lvl1/$1', undefined); // delete`\n\n### Updating pushArray rows\n\n**The safest way to update a pushArray is with `.update()`, however `.set()` can also be used...**\n\nUpdating with `.set()` - eg.\n\n`store.set('lvl1/$1/value', 'z'); // Update value of 'a' to 'z'`  \n\nor with `store.set('lvl1/$1', { id: 1, value: 'z'}); // Update value of 'a' to 'z'`  \n\n\u003e Note: a pushArray row's id should not be updated -  \n`store.set('lvl1/$1/id', 99) // BAD!!!!`  \n`store.set('lvl1/$1/', { id: 99, value: 'z'}) // BAD!!!!`\n\nThe safest way to update pushArrays is with `.update()` ... \n\n```javascript\n\nstore.update('lvl1', {id: 1, value: 'z'}); // Update value of 'a' to 'z'\n\n```\n\n`.update()` is also more powerful than using `.set()` because it allows multiple row updates at once...\n\n```javascript\n\nstore.update('lvl1', [{id: 1, value: 'z'}, {id: 3, value: 'y'}]);\n\n```\n\n### Apply\n\npushArrays can also have any array.prototype function applied to them with `.apply()`\n\n`store.apply('lvl1', pushArray =\u003e pushArray.pop()) // removes the last row of the pushArray`\n\n`newResult = store.apply('lvl1', pushArray =\u003e pushArray.find(row =\u003e row.id === 1)) // returns the pushArray row where id is 1`\n\n\u003e Note: that some array.prototype functions (such as pop and shift) mutate the pushArray - that is they make actual changes.\nOther array.prototype functions do not mutate, and instead can be used to generate a result.\n\n\u003e !!! Don't use `apply` + ( `unshift` or `push` ) as this will add items into the array without wrapping them with meta-data!  \neg.  \n\n`store.apply('lvl1', pushArray =\u003e pushArray.push(something)) // BAD!!`  \n\nInstead use `store.push('lvl1', something)` or `store.unshift('lvl1', something)`\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fattack-monkey%2Fstore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fattack-monkey%2Fstore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fattack-monkey%2Fstore/lists"}