{"_id":"@ahutchings/redux-orm","_rev":"2-8f0790cda033c7c9839e11e3544ef00f","name":"@ahutchings/redux-orm","description":"Simple ORM to manage and query your state trees","dist-tags":{"latest":"0.9.5"},"versions":{"0.9.5-0":{"name":"@ahutchings/redux-orm","version":"0.9.5-0","description":"Simple ORM to manage and query your state trees","main":"lib/index.js","scripts":{"test":"jest --config=jest.conf.json --coverage","prepublish":"npm run build","build":"npm run clean && babel src --out-dir lib && webpack && webpack --mode=build && jsdoc src -d docs -c ./jsdoc.conf.json --verbose","pub":"npm run lint && npm run test && npm run build && npm version patch && npm publish && git push origin && gulp deploy && npm run clean","lint":"eslint src","deploydocs":"npm run build && gulp deploy","clean":"rimraf lib && rimraf dist && rimraf docs"},"keywords":["redux","orm"],"author":{"name":"Tommi Kaikkonen","email":"tommi.kaikkonen@aalto.fi"},"repository":{"type":"git","url":"git+https://github.com/tommikaikkonen/redux-orm.git"},"license":"MIT","devDependencies":{"babel-cli":"^6.8.0","babel-core":"^6.7.7","babel-eslint":"^6.0.4","babel-jest":"^20.0.1","babel-loader":"^6.2.5","babel-plugin-transform-es2015-classes":"6.18.0","babel-plugin-transform-runtime":"^6.8.0","babel-preset-es2015":"^6.6.0","babel-preset-stage-2":"^6.5.0","babel-register":"^6.8.0","codecov":"^2.2.0","cross-env":"^3.2.4","deep-freeze":"0.0.1","eslint":"^3.19.0","eslint-config-airbnb-base":"^11.2.0","eslint-plugin-import":"^2.2.0","eslint-plugin-jest":"^20.0.1","gulp":"^3.9.0","gulp-gh-pages":"^0.5.4","gulp-rename":"^1.2.2","jest":"^20.0.1","jsdoc":"^3.4.1","rimraf":"^2.6.1","typescript-babel-jest":"^1.0.3","webpack":"^1.13.2","yargs":"^5.0.0"},"dependencies":{"babel-runtime":"^6.6.1","immutable-ops":"^0.5.2","lodash":"^4.12.0","reselect":"^2.5.4"},"gitHead":"78a3b031238c9bf3ac7348d81beabfd304fe6403","bugs":{"url":"https://github.com/tommikaikkonen/redux-orm/issues"},"homepage":"https://github.com/tommikaikkonen/redux-orm#readme","_id":"@ahutchings/redux-orm@0.9.5-0","_npmVersion":"5.4.1","_nodeVersion":"8.4.0","_npmUser":{"name":"ahutchings","email":"andrew.hutchings@gmail.com"},"dist":{"integrity":"sha512-sMfj3G+vdoAlbze5LU6OkyAoc/S3mqvDp5Nvn3jFclPkZV0Dy6KoL04rLnLVh8bQyt8oDvCjLRwpL2p4MdFzQQ==","shasum":"19712f4332207167591401a2a0457ea766b26156","tarball":"https://registry.npmjs.org/@ahutchings/redux-orm/-/redux-orm-0.9.5-0.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDLAiQzT9SHUbzyAXcTZN1GuFW0zi7dF+UwmjTOIuZ9aQIgb+vuGZ1ZT5EkvMJ6hDBjv41yK6M2D8+5nvQHz09qdJI="}]},"maintainers":[{"name":"ahutchings","email":"andrew.hutchings@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/redux-orm-0.9.5-0.tgz_1505215518752_0.9842582105193287"}},"0.9.5":{"name":"@ahutchings/redux-orm","version":"0.9.5","description":"Simple ORM to manage and query your state trees","main":"lib/index.js","scripts":{"test":"jest --config=jest.conf.json --coverage","prepublish":"npm run build","build":"npm run clean && babel src --out-dir lib && webpack && webpack --mode=build","pub":"npm run lint && npm run test && npm run build && npm version patch && npm publish && git push origin && gulp deploy && npm run clean","lint":"eslint src","deploydocs":"npm run build && gulp deploy","clean":"rimraf lib && rimraf dist && rimraf docs"},"keywords":["redux","orm"],"author":{"name":"Tommi Kaikkonen","email":"tommi.kaikkonen@aalto.fi"},"repository":{"type":"git","url":"git+https://github.com/tommikaikkonen/redux-orm.git"},"license":"MIT","devDependencies":{"babel-cli":"^6.8.0","babel-core":"^6.7.7","babel-eslint":"^6.0.4","babel-jest":"^20.0.1","babel-loader":"^6.2.5","babel-plugin-transform-es2015-classes":"6.18.0","babel-plugin-transform-runtime":"^6.8.0","babel-preset-es2015":"^6.6.0","babel-preset-stage-2":"^6.5.0","babel-register":"^6.8.0","codecov":"^2.2.0","cross-env":"^3.2.4","deep-freeze":"0.0.1","eslint":"^3.19.0","eslint-config-airbnb-base":"^11.2.0","eslint-plugin-import":"^2.2.0","eslint-plugin-jest":"^20.0.1","gulp":"^3.9.0","gulp-gh-pages":"^0.5.4","gulp-rename":"^1.2.2","jest":"^20.0.1","jsdoc":"^3.4.1","rimraf":"^2.6.1","typescript-babel-jest":"^1.0.3","webpack":"^1.13.2","yargs":"^5.0.0"},"dependencies":{"babel-runtime":"^6.6.1","immutable-ops":"^0.5.2","lodash":"^4.12.0","reselect":"^2.5.4"},"gitHead":"e10de12cbef704627a76440b6e2386d834127bc1","bugs":{"url":"https://github.com/tommikaikkonen/redux-orm/issues"},"homepage":"https://github.com/tommikaikkonen/redux-orm#readme","_id":"@ahutchings/redux-orm@0.9.5","_npmVersion":"5.5.1","_nodeVersion":"8.7.0","_npmUser":{"name":"ahutchings","email":"andrew.hutchings@gmail.com"},"dist":{"integrity":"sha512-S0f647+QPyBSF1ur+Dh9Ja6Z5nlhk550jRNh0RNisvRNbAVWbS9Zv4vBhKbyiYDJOWOrqIwRtMedGc5e7qsVkw==","shasum":"4a397e08b1d9ade596e134aa91fa75d71f92ab14","tarball":"https://registry.npmjs.org/@ahutchings/redux-orm/-/redux-orm-0.9.5.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDfSKelGRiCfwFJ8wPLWR5rieYgRULtDmoaI24k2KyAlAIgOoju1ZjJ5Ejp3HE4Ri5vo3VdvdECE2K+pS+FCwJYYmo="}]},"maintainers":[{"name":"ahutchings","email":"andrew.hutchings@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/redux-orm-0.9.5.tgz_1508449812534_0.34887743601575494"}}},"readme":"redux-orm\n===============\n[![Build Status](https://img.shields.io/travis/tommikaikkonen/redux-orm.svg?style=flat-square)](https://travis-ci.org/tommikaikkonen/redux-orm)\n[![Coverage Status](https://img.shields.io/codecov/c/github/tommikaikkonen/redux-orm/master.svg?style=flat-square)](https://codecov.io/gh/tommikaikkonen/redux-orm/branch/master)\n[![NPM package](https://img.shields.io/npm/v/redux-orm.svg?style=flat-square)](https://www.npmjs.com/package/redux-orm)\n[![NPM downloads](https://img.shields.io/npm/dm/redux-orm.svg?style=flat-square)](https://www.npmjs.com/package/redux-orm)\n[![Gitter](https://badges.gitter.im/redux-orm/Lobby.svg)](https://gitter.im/redux-orm/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n\nA small, simple and immutable ORM to manage relational data in your Redux store.\n\nSee a [a guide to creating a simple app with Redux-ORM](https://github.com/tommikaikkonen/redux-orm-primer) (includes the source). Its README is not updated for 0.9 yet but the [code has a branch for it](https://github.com/tommikaikkonen/redux-orm-primer/tree/migrate_to_0_9).\n\n**The 0.9 which is in the release candidate stage, brings big breaking changes to the API. Please look at the [migration guide](https://github.com/tommikaikkonen/redux-orm/wiki/0.9-Migration-Guide) if you're migrating from earlier versions.**\n\nLooking for the 0.8 docs? Read the [old README.md in the repo](https://github.com/tommikaikkonen/redux-orm/tree/3c36fa804d2810b2aaaad89ff1d99534b847ea35). For the API reference, clone the repo, `npm install`, `make build` and open up `index.html` in your browser. Sorry for the inconvenience.\n\nAPI can be unstable until 1.0.0. Minor version bumps before 1.0.0 can and will introduce breaking changes. They will be noted in the [changelog](https://github.com/tommikaikkonen/redux-orm#changelog).\n\n## Extensions\n\n- [`redux-orm-proptypes`](https://github.com/tommikaikkonen/redux-orm-proptypes): React PropTypes validation and defaultProps mixin for Redux-ORM Models\n\n## Installation\n\n```bash\nnpm install redux-orm --save\n```\n\nOr with a script tag\n\n```html\n<script src=\"https://tommikaikkonen.github.io/redux-orm/dist/redux-orm.js\"></script>\n```\n\n- [Browser build following master](https://tommikaikkonen.github.io/redux-orm/dist/redux-orm.js)\n- [Browser build following master (minimized)](https://tommikaikkonen.github.io/redux-orm/dist/redux-orm.min.js)\n\n## Usage\n\n### Declare Your Models\n\nYou can declare your models with the ES6 class syntax, extending from `Model`. You need to declare all your non-relational fields on the Model, and declaring all data fields is recommended as the library doesn't have to redefine getters and setters when instantiating Models. `redux-orm` supports one-to-one and many-to-many relations in addition to foreign keys (`oneToOne`, `many` and `fk` imports respectively). Non-related properties can be accessed like in normal JavaScript objects.\n\n```javascript\n// models.js\nimport {fk, many, attr, Model} from 'redux-orm';\n\nclass Book extends Model {\n    toString() {\n        return `Book: ${this.name}`;\n    }\n    // Declare any static or instance methods you need.\n}\nBook.modelName = 'Book';\n\n// Declare your related fields.\nBook.fields = {\n    id: attr(), // non-relational field for any value; optional but highly recommended\n    name: attr(),\n    authors: many('Author', 'books'),\n    publisher: fk('Publisher', 'books'),\n};\n```\n\n### Register Models and Generate an Empty Database State\n\nDefining fields on a Model specifies the table structure in the database for that Model. In order to generate a description of the whole database's structure, we need a central place to register all Models we want to use.\n\nAn instance of the ORM class registers Models and handles generating a full schema from all the models and passing that information to the database. Often you'll want to have a file where you can import a single ORM instance across the app, like this:\n\n```javascript\n// orm.js\nimport { ORM } from 'redux-orm';\nimport { Book, Author, Publisher } from './models';\n\nconst orm = new ORM();\norm.register(Book, Author, Publisher);\n\nexport default orm;\n```\n\nYou could also define *and* register the models to an ORM instance in the same file, and export them all.\n\nNow that we've registered Models, we can generate an empty database state. Currently that's a plain, nested JavaScript object that is structured similarly to relational databases.\n\n```javascript\n// index.js\n\nimport orm from './orm';\n\nconst emptyDBState = orm.getEmptyState();\n```\n\n### Applying Updates to the Database\n\nWhen we have a database state, we can start an ORM session on that to apply updates. The ORM instance provides a `session` method that accepts a database state as it's sole argument, and returns a Session instance.\n\n```javascript\nconst session = orm.session(emptyDBState);\n```\n\nSession-specific classes of registered Models are available as properties of the session object.\n\n```javascript\nconst Book = session.Book;\n```\n\nModels provide an interface to query and update the database state.\n\n```javascript\nBook.withId(1).update({ name: 'Clean Code' });\nBook.all().filter(book => book.name === 'Clean Code').delete();\nBook.hasId(1)\n// false\n```\n\nThe initial database state is not mutated. A new database state with the updates applied can be found on the `state` property of the Session instance.\n\n```javascript\nconst updatedDBState = session.state;\n```\n\n\n## Redux Integration\n\nTo integrate Redux-ORM with Redux at the most basic level, you can define a reducer that instantiates a session from the database state held in the Redux atom, then when you've applied all of your updates, you can return the next state from the session.\n\n```javascript\nimport { orm } from './models';\nfunction ormReducer(dbState, action) {\n    const sess = orm.session(dbState);\n\n    // Session-specific Models are available\n    // as properties on the Session instance.\n    const { Book } = sess;\n\n    switch (action.type) {\n    case 'CREATE_BOOK':\n        Book.create(action.payload);\n        break;\n    case 'UPDATE_BOOK':\n        Book.withId(action.payload.id).update(action.payload);\n        break;\n    case 'REMOVE_BOOK':\n        Book.withId(action.payload.id).delete();\n        break;\n    case 'ADD_AUTHOR_TO_BOOK':\n        Book.withId(action.payload.bookId).authors.add(action.payload.author);\n        break;\n    case 'REMOVE_AUTHOR_FROM_BOOK':\n        Book.withId(action.payload.bookId).authors.remove(action.payload.authorId);\n        break;\n    case 'ASSIGN_PUBLISHER':\n        Book.withId(action.payload.bookId).publisher = action.payload.publisherId;\n        break;\n    }\n\n    // the state property of Session always points to the current database.\n    // Updates don't mutate the original state, so this reference is not\n    // equal to `dbState` that was an argument to this reducer.\n    return sess.state;\n}\n```\n\nPreviously Redux-ORM advocated for reducers specific to Models by attaching a static `reducer` function on the Model class. If you want to define your update logic on the Model classes, you can specify a `reducer` static method on your model which accepts the action as the first argument, the session-specific Model as the second, and the whole session as the third.\n\n```javascript\nclass Book extends Model {\n    static reducer(action, Book, session) {\n        switch (action.type) {\n        case 'CREATE_BOOK':\n            Book.create(action.payload);\n            break;\n        case 'UPDATE_BOOK':\n            Book.withId(action.payload.id).update(action.payload);\n            break;\n        case 'REMOVE_BOOK':\n            const book = Book.withId(action.payload);\n            book.delete();\n            break;\n        case 'ADD_AUTHOR_TO_BOOK':\n            Book.withId(action.payload.bookId).authors.add(action.payload.author);\n            break;\n        case 'REMOVE_AUTHOR_FROM_BOOK':\n            Book.withId(action.payload.bookId).authors.remove(action.payload.authorId);\n            break;\n        case 'ASSIGN_PUBLISHER':\n            Book.withId(action.payload.bookId).publisher = action.payload.publisherId;\n            break;\n        }\n        // Return value is ignored.\n        return undefined;\n    }\n\n    toString() {\n        return `Book: ${this.name}`;\n    }\n}\n```\n\nTo get a reducer for Redux that calls these `reducer` methods:\n\n```javascript\nimport { createReducer } from 'redux-orm';\nimport { orm } from './models';\n\nconst reducer = createReducer(orm);\n```\n\n`createReducer` is really simple, so I'll just paste the source here.\n\n```javascript\nfunction createReducer(orm, updater = defaultUpdater) {\n    return (state, action) => {\n        const session = orm.session(state || orm.getEmptyState());\n        updater(session, action);\n        return session.state;\n    };\n}\n\nfunction defaultUpdater(session, action) {\n    session.sessionBoundModels.forEach(modelClass => {\n        if (typeof modelClass.reducer === 'function') {\n            modelClass.reducer(action, modelClass, session);\n        }\n    });\n}\n```\n\nAs you can see, it just instantiates a new Session, loops through all the Models in the session, and calls the `reducer` method if it exists. Then it returns the new database state that has all the updates applied.\n\n### Use with React\n\nUse memoized selectors to make queries into the state. `redux-orm` uses smart memoization: the below selector accesses `Author` and `AuthorBooks` branches (`AuthorBooks` is a many-to-many branch generated from the model field declarations), and the selector will be recomputed only if those branches change. The accessed branches are resolved on the first run.\n\n```javascript\n// selectors.js\nimport schema from './schema';\nconst authorSelector = schema.createSelector(session => {\n    return session.Author.map(author => {\n\n        // Returns a reference to the raw object in the store,\n        // so it doesn't include any reverse or m2m fields.\n        const obj = author.ref;\n        // Object.keys(obj) === ['id', 'name']\n\n        return Object.assign({}, obj, {\n            books: author.books.withRefs.map(book => book.name),\n        });\n    });\n});\n\n// Will result in something like this when run:\n// [\n//   {\n//     id: 0,\n//     name: 'Tommi Kaikkonen',\n//     books: ['Introduction to redux-orm', 'Developing Redux applications'],\n//   },\n//   {\n//     id: 1,\n//     name: 'John Doe',\n//     books: ['John Doe: an Autobiography']\n//   }\n// ]\n```\n\nSelectors created with `createSelector` can be used as input to any additional `reselect` selectors you want to use. They are also great to use with `redux-thunk`: get the whole state with `getState()`, pass the ORM branch to the selector, and get your results. A good use case is serializing data to a custom format for a 3rd party API call.\n\nBecause selectors are memoized, you can use pure rendering in React for performance gains.\n\n```jsx\n// components.js\nimport PureComponent from 'react-pure-render/component';\nimport { authorSelector } from './selectors';\nimport { connect } from 'react-redux';\n\nclass App extends PureComponent {\n    render() {\n        const authors = this.props.authors.map(author => {\n            return (\n                <li key={author.id}>\n                    {author.name} has written {author.books.join(', ')}\n                </li>\n            );\n        });\n\n        return (\n            <ul>\n                {authors}\n            </ul>\n        );\n    }\n}\n\nfunction mapStateToProps(state) {\n    return {\n        authors: authorSelector(state.db),\n    };\n}\n\nexport default connect(mapStateToProps)(App);\n```\n\n## Understanding redux-orm\n\n### An ORM?\n\nWell, yeah. `redux-orm` deals with related data, structured similar to a relational database. The database in this case is a simple JavaScript object database.\n\n### Why?\n\nFor simple apps, writing reducers by hand is alright, but when the number of object types you have increases and you need to maintain relations between them, things get hairy. ImmutableJS goes a long way to reduce complexity in your reducers, but `redux-orm` is specialized for relational data.\n\n### Immutability\n\nSay we start a session from an initial database state situated in the Redux atom, update the name of a certain book.\n\nFirst, a new session:\n\n```javascript\nimport { orm } from './models';\n\nconst dbState = getState().db; // getState() returns the redux state.\nconst sess = orm.session(dbState);\n```\n\nThe session maintains a reference to a database state. We haven't\nupdated the database state, therefore it is still equal to the original\nstate.\n\n```javascript\nsess.state === dbState\n// true\n```\n\nLet's apply an update.\n\n```javascript\nconst book = sess.Book.withId(1)\n\nbook.name // 'Refactoring'\nbook.name = 'Clean Code'\nbook.name // 'Clean Code'\n\nsess.state === dbState\n// false.\n```\n\nThe update was applied, and because the session does not mutate the original state, it created a new one and swapped `sess.state` to point to the new one.\n\nLet's update the database state again through the ORM.\n\n```javascript\n\n// Save this reference so we can compare.\nconst updatedState = sess.state;\n\nbook.name = 'Patterns of Enterprise Application Architecture'\n\nsess.state === updatedState\n// true. If possible, future updates are applied with mutations. If you want\n// to avoid making mutations to a session state, take the session state\n// and start a new session with that state.\n```\n\nIf possible, future updates are applied with mutations. In this case, the database was already mutated, so the pointer doesn't need to change. If you want to avoid making mutations to a session state, take the session state and start a new session with that state.\n\n### Customizability\n\nJust like you can extend `Model`, you can do the same for `QuerySet` (customize methods on Model instance collections). You can also specify the whole database implementation yourself (documentation pending).\n\n### Caveats\n\nThe ORM abstraction will never be as performant compared to writing reducers by hand, and adds to the build size of your project (last I checked, minimizing the source files and gzipping yielded about 8 KB). If you have very simple data without relations, `redux-orm` may be overkill. The development convenience benefit is considerable though.\n\n## API\n\n### ORM\n\nSee the full documentation for ORM [here](http://tommikaikkonen.github.io/redux-orm/global.html#ORM)\n\nInstantiation\n\n```javascript\nconst orm = new ORM(); // no arguments needed.\n```\n\nInstance methods:\n\n- `register(...models: Array<Model>)`: registers Model classes to the `ORM` instance.\n- `session(state: any)`: begins a new `Session` with `state`.\n\n### Redux Integration\n\n- `createReducer(orm: ORM)`: returns a reducer function that can be plugged into Redux. The reducer will return the next state of the database given the provided action. You need to register your models before calling this.\n- `createSelector(orm: ORM, [...inputSelectors], selectorFunc)`: returns a memoized selector function for `selectorFunc`. `selectorFunc` receives `session` as the first argument, followed by any inputs from `inputSelectors`. Read the full documentation for details.\n\n### Model\n\nSee the full documentation for `Model` [here](http://tommikaikkonen.github.io/redux-orm/Model.html).\n\n**Instantiation**: Don't instantiate directly; use class method `create`.\n\n**Class Methods**:\n\n- `hasId(id)`: returns a boolean indicating if entity with id `id` exists in the state.\n- `withId(id)`: gets the Model instance with id `id`.\n- `get(matchObj)`: to get a Model instance based on matching properties in `matchObj`,\n- `create(props)`: to create a new Model instance with `props`. If you don't supply an id, the new `id` will be `Math.max(...allOtherIds) + 1`.\n- `upsert(props)`: to create a new Model instance with `props` or to update a existing Model with same `id` - by other words its **create or update** behaviour.\n\nYou will also have access to almost all [QuerySet instance methods](http://tommikaikkonen.github.io/redux-orm/QuerySet.html) from the class object for convenience.\n\n**Instance Attributes**:\n- `ref`: returns a direct reference to the plain JavaScript object representing the Model instance in the store.\n\n**Instance methods**:\n\n- `equals(otherModel)`: returns a boolean indicating equality with `otherModel`. Equality is determined by shallow comparison of both model's attributes.\n- `set(propertyName, value)`: updates `propertyName` to `value`. Returns `undefined`. Is equivalent to normal assignment.\n- `update(mergeObj)`: merges `mergeObj` with the Model instance properties. Returns `undefined`.\n- `delete()`: deletes the record for this Model instance in the database. Returns `undefined`.\n\n**Subclassing**:\n\nUse the ES6 syntax to subclass from `Model`. Any instance methods you declare will be available on Model instances. Any static methods you declare will be available on the Model class in Sessions.\n\nFor the related fields declarations, either set the `fields` property on the class or declare a static getter that returns the field declarations like this:\n\n**Declaring `fields`**:\n```javascript\nclass Book extends Model {\n    static get fields() {\n        return {\n            id: attr(),\n            name: attr(),\n            author: fk('Author'),\n        };\n    }\n}\n// alternative:\nBook.fields = {\n    id: attr(),\n    name: attr(),\n    author: fk('Author'),\n}\n```\n\nAll the fields `fk`, `oneToOne` and `many` take a single argument, the related model name. The fields will be available as properties on each `Model` instance. You can set related fields with the id value of the related instance, or the related instance itself. \n\nFor `fk`, you can access the reverse relation through `author.bookSet`, where the related name is `${modelName}Set`. Same goes for `many`. For `oneToOne`, the reverse relation can be accessed by just the model name the field was declared on: `author.book`.\n\nFor `many` field declarations, accessing the field on a Model instance will return a `QuerySet` with two additional methods: `add` and `remove`. They take 1 or more arguments, where the arguments are either Model instances or their id's. Calling these methods records updates that will be reflected in the next state.\n\nWhen declaring model classes, always remember to set the `modelName` property. It needs to be set explicitly, because running your code through a mangler would otherwise break functionality. The `modelName` will be used to resolve all related fields. \n\n**Declaring `modelName`**:\n```javascript\nclass Book extends Model {\n    static get modelName() {\n        return 'Book';\n    }\n}\n// alternative:\nBook.modelName = 'Book';\n```\n\n**Declaring `options`**\n\nIf you need to specify options to the redux-orm database, you can declare a static `options` property on the Model class with an object key. Currently you can specify the id attribute name:\n\n```javascript\n// This is the default value. \nBook.options = {\n    idAttribute: 'id',\n};\n```\n\n### QuerySet\n\nSee the full documentation for `QuerySet` [here](http://tommikaikkonen.github.io/redux-orm/QuerySet.html).\n\nYou can access all of these methods straight from a `Model` class, as if they were class methods on `Model`. In this case the functions will operate on a QuerySet that includes all the Model instances.\n\n**Instance methods**:\n\n- `toRefArray()`: returns the objects represented by the `QuerySet` as an array of plain JavaScript objects. The objects are direct references to the store.\n- `toModelArray()`: returns the objects represented by the `QuerySet` as an array of `Model` instances objects.\n- `count()`: returns the number of `Model` instances in the `QuerySet`.\n- `exists()`: return `true` if number of entities is more than 0, else `false`.\n- `filter(filterArg)`: returns a new `QuerySet` representing the records from the parent QuerySet that pass the filter. For `filterArg`, you can either pass an object that `redux-orm` tries to match to the entities, or a function that returns `true` if you want to have it in the new `QuerySet`, `false` if not. The function receives a model instance as its sole argument.\n- `exclude` returns a new `QuerySet` represeting entities in the parent QuerySet that do not pass the filter. Similarly to `filter`, you may pass an object for matching (all entities that match will not be in the new `QuerySet`) or a function. The function receives a model instance as its sole argument.\n- `all()` returns a new `QuerySet` with the same entities.\n- `at(index)` returns an `Model` instance at the supplied `index` in the `QuerySet`.\n- `first()` returns an `Model` instance at the `0` index.\n- `last()` returns an `Model` instance at the `querySet.count() - 1` index.\n- `delete()` deleted all entities represented by the `QuerySet`.\n- `update(mergeObj)` updates all entities represented by the `QuerySet` based on the supplied object. The object will be merged with each entity.\n\n### Session\n\nSee the full documentation for Session [here](http://tommikaikkonen.github.io/redux-orm/Session.html)\n\n**Instantiation**: you don't need to do this yourself. Use `orm.session`.\n\n**Instance properties**:\n\n- `state`: the current database state in the session.\n\nAdditionally, you can access all the registered Models in the schema for querying and updates as properties of this instance. For example, given a schema with `Book` and `Author` models,\n\n```javascript\nconst session = orm.session(state);\nsession.Book // Model class: Book\nsession.Author // Model class: Author\nsession.Book.create({id: 5, name: 'Refactoring', release_year: 1999});\n```\n\n## Changelog\n\nMinor changes before 1.0.0 can include breaking changes.\n\n### 0.9.4\nfix for filter/query [#99](https://github.com/tommikaikkonen/redux-orm/issues/99)\n\n### 0.9.2 - 0.9.3\nfix for many-many updates [#136](https://github.com/tommikaikkonen/redux-orm/issues/136)\n\n### 0.9.1\n- added 'upsert' method to Model (insert or update behaviour)\n- major updates for tests\n- CI integration\n\n### 0.9.0\n\nA lot. See [the migration guide](https://github.com/tommikaikkonen/redux-orm/wiki/0.9-Migration-Guide).\n\n### 0.8.4\n\nAdds UMD build to partially fix [#41](https://github.com/tommikaikkonen/redux-orm/issues/41). You can now use or try out `redux-orm` through a script tag:\n\n```html\n<script src=\"https://tommikaikkonen.github.io/redux-orm/dist/redux-orm.js\"></script>\n```\n\n`redux-orm.js` will point to the master version of the library; If you need to stick to a version, make a copy or build it yourself.\n\n### 0.8.3\n\nFixed bug that mutated the backend options in `Model` if you supplied custom ones, see [Issue 37](https://github.com/tommikaikkonen/redux-orm/issues/37). Thanks to [@diffcunha](https://github.com/diffcunha) for the [fix](https://github.com/tommikaikkonen/redux-orm/pull/38)!\n\n### 0.8.2\n\nFixed [regression in `Model.prototype.update`](https://github.com/tommikaikkonen/redux-orm/issues/23)\n\n### 0.8.1\n\nAdded `babel-runtime to dependencies`\n\n### 0.8.0\n\nAdds **batched mutations.** This is a big performance improvement. Previously adding 10,000 objects would take 15s, now it takes about 0.5s. Batched mutations are implemented using [`immutable-ops`](https://github.com/tommikaikkonen/immutable-ops) internally.\n\n**Breaking changes**:\n\n- Removed `indexById` option from Backend. This means that data will always be stored in both an array of id's and a map of `id => entity`, which was the default setting. If you didn't explicitly set `indexById` to `false`, you don't need to change anything.\n\n- Batched mutations brought some internal changes. If you had custom `Backend` or `Session` classes, or have overridden `Model.getNextState`, please check out the diff.\n\n### 0.7.0\n\n**Breaking changes**:\n\nModel classes that you access in reducers and selectors are now session-specific. Previously the user-defined Model class reference was used for sessions, with a private `session` property changing based on the most recently created session. Now Model classes are given a unique dummy subclass for each session. The subclass will be bound to that specific session. This allows multiple sessions to be used at the same time.\n\nYou most likely don't need to change anything. The documentation was written with this feature in mind from the start. As long as you've used the model class references given to you in reducers and selectors as arguments (not the reference to the model class you defined), you're fine.\n\n### 0.6.0\n\n**Breaking changes**:\n\n- When calling `QuerySet.filter` or `QuerySet.exclude` with an object argument, any values of that object that look like a `Model` instance (i.e. they have a `getId` property that is a function), will be turned into the id of that instance before performing the filtering or excluding.\n\nE.g.\n\n```javascript\nBook.filter({ author: Author.withId(0) });\n```\n\nIs equivalent to\n\n```javascript\nBook.filter({ author: 0 });\n```\n\n### 0.5.0\n\n**Breaking changes**:\n\n- Model instance method `equals(otherModel)` now checks if the two model's attributes are shallow equal. Previously, it checked if the id's and model classes are equal.\n- Session constructor now receives a Schema instance as its first argument, instead of an array of Model classes (this only affects you if you're manually instantiating Sessions with the `new` operator).\n\nOther changes:\n\n- Added `hasId` static method to the Model class. It tests for the existence of the supplied id in the model's state.\n- Added instance method `getNextState` to the Session class. This enables you to get the next state without running model-reducers. Useful if you're bootstrapping data, writing tests, or otherwise operating on the data outside reducers. You can pass an options object that currently accepts a `runReducers` key. It's value indicates if reducers should be run or not.\n- Improved API documentation.\n\n### 0.4.0\n\n- Fixed a bug that mutated props passed to Model constructors, which could be a reference from the state. I highly recommend updating from 0.3.1.\n- API cleanup, see breaking changes below.\n- Calling getNextState is no longer mandatory in your Model reducers. If your reducer returns `undefined`, `getNextState` will be called for you.\n\n**Breaking changes**:\n\n- Removed static methods `Model.setOrder()` and `Backend.order`. If you want ordered entities, use the QuerySet instance method `orderBy`.\n- Added helpful error messages when trying to add a duplicate many-to-many entry (Model.someManyRelated.add(...)), trying to remove an unexisting many-to-many entry (Model.exampleManyRelated.remove(...)), or creating a Model with duplicate many-to-many entry ids (Model.create(...)).\n- Removed ability to supply a mapping function to QuerySet instance method `update`. If you need to record updates dynamically based on each entity, iterate through the objects with `forEach` and record updates separately:\n\n```javascript\nconst authors = publisher.authors;\nauthors.forEach(author => {\n    const isAdult = author.age >= 18;\n    author.update({ isAdult });\n})\n```\n\nor use the ability to merge an object with all objects in a QuerySet. Since the update operation is batched for all objects in the QuerySet, it can be more performant with a large amount of entities:\n\n```javascript\nconst authors = publisher.authors;\nconst isAdult = author => author.age >= 18;\n\nconst adultAuthors = authors.filter(isAdult);\nadultAuthors.update({ isAdult: true });\n\nconst youngAuthors = authors.exclude(isAdult);\nyoungAuthors.update({ isAdult: false });\n```\n\n### 0.3.1\n\nA descriptive error is now thrown when a reverse field conflicts with another field declaration.\nFor example, the following schema:\n\n```javascript\nclass A extends Model {}\nA.modelName = 'A';\n\nclass B extends Model {}\nB.modelName = 'B';\nB.fields = {\n    field1: one('A'),\n    field2: one('A'),\n};\n```\n\nwould try to define the reverse field `b` on `A` twice, throwing an error with an undescriptive message.\n\n### 0.3.0\n\n**Breaking changes**:\n\n- `Model.withId(id)` now throws if object with id `id` does not exist in the database. \n\n### 0.2.0\n\nIncludes various bugfixes and improvements.\n\n**Breaking changes**:\n- Replaced `plain` and `models` instance attributes in `QuerySet` with `withRefs` and `withModels` respectively. The attributes return a new `QuerySet` instead of modifying the existing one. A `ref` alias is also added for `withRefs`, so you can do `Book.ref.at(2)`.\n- After calling `filter`, `exclude` or `orderBy` method on a `QuerySet` instance, the `withRefs` flag is always flipped off so that calling the same methods on the returned `QuerySet` would use model instances in the operations. Previously the flag value remained after calling those methods.\n- `.toPlain()` from `QuerySet` is renamed to `.toRefArray()` for clarity.\n- Added `.toModelArray()` method to `QuerySet`.\n- Removed `.objects()` method from `QuerySet`. Use `.toRefArray()` or `.toModelArray()` instead.\n- Removed `.toPlain()` method from `Model`, which returned a copy of the Model instance's property values. To replace that, `ref` instance getter was added. It returns a reference to the plain JavaScript object in the database. So you can do `Book.withId(0).ref`. If you need a copy, you can do `Object.assign({}, Book.withId(0).ref)`.\n- Removed `.fromEmpty()` instance method from `Schema`.\n- Removed `.setReducer()` instance method from `Schema`. You can just do `ModelClass.reducer = reducerFunc;`.\n\n\n## License\n\nMIT. See `LICENSE`\n","maintainers":[{"name":"ahutchings","email":"andrew.hutchings@gmail.com"}],"time":{"modified":"2022-04-04T12:14:35.203Z","created":"2017-09-12T11:25:20.435Z","0.9.5-0":"2017-09-12T11:25:20.435Z","0.9.5":"2017-10-19T21:50:14.173Z"},"homepage":"https://github.com/tommikaikkonen/redux-orm#readme","keywords":["redux","orm"],"repository":{"type":"git","url":"git+https://github.com/tommikaikkonen/redux-orm.git"},"author":{"name":"Tommi Kaikkonen","email":"tommi.kaikkonen@aalto.fi"},"bugs":{"url":"https://github.com/tommikaikkonen/redux-orm/issues"},"license":"MIT","readmeFilename":"README.md"}