{"id":24973378,"url":"https://github.com/maxgaurav/indexeddb-orm","last_synced_at":"2025-04-11T08:44:08.573Z","repository":{"id":17762147,"uuid":"82657235","full_name":"maxgaurav/indexeddb-orm","owner":"maxgaurav","description":"Indexed DB ORM","archived":false,"fork":false,"pushed_at":"2022-06-17T04:48:47.000Z","size":704,"stargazers_count":59,"open_issues_count":4,"forks_count":12,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-30T04:02:46.922Z","etag":null,"topics":["builder","database","indexed-db","indexeddb","indexeddb-api","indexeddb-wrapper","javascript","javascript-library","nested-attributes","orm","promise","query-builder","transaction","webworker"],"latest_commit_sha":null,"homepage":"https://maxgaurav.github.io/indexeddb-orm","language":"TypeScript","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/maxgaurav.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-21T08:50:48.000Z","updated_at":"2025-02-20T19:37:04.000Z","dependencies_parsed_at":"2022-08-10T09:02:25.184Z","dependency_job_id":null,"html_url":"https://github.com/maxgaurav/indexeddb-orm","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgaurav%2Findexeddb-orm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgaurav%2Findexeddb-orm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgaurav%2Findexeddb-orm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgaurav%2Findexeddb-orm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxgaurav","download_url":"https://codeload.github.com/maxgaurav/indexeddb-orm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248362654,"owners_count":21091171,"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":["builder","database","indexed-db","indexeddb","indexeddb-api","indexeddb-wrapper","javascript","javascript-library","nested-attributes","orm","promise","query-builder","transaction","webworker"],"created_at":"2025-02-03T18:59:01.504Z","updated_at":"2025-04-11T08:44:08.545Z","avatar_url":"https://github.com/maxgaurav.png","language":"TypeScript","readme":"# IndexedDB ORM\n\nAn indexedDB wrapper for accessing indexedDB as a promise base api implementation.\n\n[![npm](https://img.shields.io/npm/dm/indexeddb-orm.svg)](https://www.npmjs.com/package/indexeddb-orm)\n[![npm](https://img.shields.io/npm/v/indexeddb-orm.svg)](https://www.npmjs.com/package/indexeddb-orm)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## Older Version\nFor older version please go to branch [2.1.0](https://github.com/maxgaurav/indexeddb-orm/tree/orm-2.1.0)\n\n## Website\n[maxgaurav.github.io/indexeddb-orm](https://maxgaurav.github.io/indexeddb-orm)\n\nExamples coming soon to the website.\n\n## Changes/Updates/Deprecation\nRead [ChangeLog](https://github.com/maxgaurav/indexeddb-orm/blob/master/CHANGELOG.md)\n\n## Table of Contents\n\n* [Features](#features)\n* [Installation](#installation)\n* [Usage](#usage)\n* [ORM](#orm)\n* [Query Building](#query-building)\n    * [Insertion of data](#insertion-of-data)\n        * [Create](#create)\n        * [Create Multiple](#create-multiple)\n    * [Searching of the data](#searching-of-the-data)\n        * [Find](#find)\n        * [FindOFail](#findorfail)\n        * [FindORCreate](#findorcreate)\n        * [First](#first)\n        * [FirstOrFail](#firstorfail)\n        * [FirstOrCreate](#firstorcreate)\n        * [FindIndex](#first)\n        * [FindIndexOrFail](#firstorfail)\n        * [FindIndexOrCreate](#firstorcreate)\n        * [FindAllIndex](#findallindex)\n        * [All](#all)\n    * [Index Searching](#index-searching)\n        * [whereIndex](#whereindex)\n        * [whereIndexIn](#whereindexin)\n        * [whereMultiIndexIn](#wheremultiindexin)\n        * [whereIndexGte](#whereindexgte)\n        * [whereIndexGt](#whereindexgt)\n        * [whereIndexLte](#whereindexlte)\n        * [whereIndexLt](#whereindexlt)\n        * [whereIndexBetween](#whereindexbetween)\n    * [Non Index Searching](#non-index-searching)\n        * [where](#where)\n        * [Nested Attributes](#nested-attributes)\n        * [whereIn](#wherein)\n        * [whereInArray](#whereinarray)\n        * [gte](#gte)\n        * [gt](#gt)\n        * [lte](#lte)\n        * [lt](#lt)\n        * [between](#between)\n    * [Relations](#relations)\n        * [Has One](#has-one)\n        * [Has Many](#has-many)\n        * [Has Many Multi Entry](#has-many-multi-entry)\n        * [Has Many Through Multi Entry](#has-many-through-multi-entry)\n        * [Custom Relation Builder](#custom-relation-builder)\n        * [Nested Relations](#nested-relations)\n    * [Updating of Records](#updating-of-records)\n        * [save](#save)\n        * [saveIndex](#save-index)\n        * [saveAllIndex](#save-all-index)\n        * [update](#update)\n    * [Deletion in table](#deletions-in-table)\n        * [delete](#delete)\n        * [destroy](#destroy)\n        * [deleteIndex](#deleteindex)\n    * [Transactional Actions](#transactional-actions)\n    * [Aggregations](#aggregations)\n        * [Count](#count)\n        * [Average](#average)\n        * [Reduce](#Reduce)\n    * [Syncing](#syncing)\n        * [sync](#sync)\n        * [syncIndex](#sync-index)\n        * [syncAllIndex](#sync-all-index)\n    \n\n## Features\n* Create structure of database with indexes and version\n* Get model instances and query builder for both indexed columns and non indexed columns\n* Create relation between multiple tables \n* Create custom ORM class to be used over default Model instances to provide custom relations\n\n## Installation\n```\nnpm install indexeddb-orm --save\nyarn add indexeddb-orm\n```\n\n## Usage\n* An setting parameter needs to be created for database structure handling. Models will be populated using the table names provided.\n* Use the idb function and pass base configuration with database structure.\n```javascript\n\nimport {Connector} from './dist/es2015/connection/connector.js';\n\nconst settings = {\n    name : 'nameOfDatabase',\n    version : 1, //version of database\n    migrations : [{\n        name : 'users', //name of table\n        primary : 'id', //auto increment field (default id)\n        columns : [{\n            name : 'email', //other indexes in the database\n            attributes : { //other keyPath configurations for the index\n                unique : true\n            }\n        },{\n            name : 'userContacts',\n            columns : [{\n                name : 'phone',\n                attributes : {\n                    multiEntry: true\n                }\n            },{\n                name : 'contactId', //name of the index\n                index : 'medical.contactId' //if provided then indexing value will be this\n            },{\n                name : 'userId'\n            }]\n        }]\n    }]\n};\n\n\n// if using normal script\nconst idb = idb(settings);\n\n// if using module scripts\nconst db = new Connector(settings);\n```\n\n## ORM\n\nYou can create you own custom class extending the **Model** class allowing you to create scoped queries, custom relations\nwithin the class and much more. Following is an example on how to use and create orm classes.\n\n```javascript\nimport {Model} from './dist/es2015/models/model.js';\n\nclass UserProfiles extends Model{\n  static TableName = 'userProfile';\n  \n  user = () =\u003e {\n    return this.hasOne(Users, 'id', 'userId')\n  }\n}\n\nclass Users extends Model {\n  static TableName = 'users';\n  \n  userProfile = () =\u003e {\n      // the third and fourth parameter are optional;\n      // by default the function name would be used as parent models attribute.\n      return this.hasOne(UserProfiles, 'userId', '_id', 'userProfile')\n        .where('name', 'newName').with([...]).withCustom(['user']); \n  }\n}\n\nconst settings = {\n    name : 'nameOfDatabase',\n    version : 1, //version of database\n    migrations : [{\n        name : 'users', //name of table\n        primary : 'id', //auto increment field (default id)\n        ormClass: Users,\n        columns : [{\n            name : 'email', //other indexes in the database\n            attributes : { //other keyPath configurations for the index\n                unique : true\n            }\n        },{\n          name : 'userProfiles', //name of table\n          primary : 'id', //auto increment field (default id)\n          ormClass: UserProfiles,\n          columns : [{\n              name : 'userId', //other indexes in the database\n          },{\n            name : 'userContacts',\n            columns : [{\n                name : 'phone',\n                attributes : {\n                    multiEntry: true\n                }\n            },{\n                name : 'contactId', //name of the index\n                index : 'medical.contactId' //if provided then indexing value will be this\n            },{\n                name : 'userId'\n            }]\n        }]\n    }]\n};\n```\n\n## Query Building\n\n### Insertion of data\n\n#### Create\n* Inserting content to database using create.\n* Inserting content will automatically add a updatedAt and createdAt entry with timestamp\n```javascript\n\ndb.connect(async (models) =\u003e {\n    const record = await models.users.create({\n        email : 'test@test.com'\n    });\n}) \n```\n\n\n#### Create Multiple\n* Allows insertion of multiple content in a table\n\n```javascript\ndb.connect(async (models) =\u003e {\n   const results = await models.usersContacts.createMultiple([{\n        userId : 1,\n        firstName : 'TestFirst',\n        lastName : 'TestLast',\n        medical : {\n            contactId : 10,\n            hospitalId : 11\n        }\n    },{\n          userId : 2,\n          firstName : 'Test2First',\n          lastName : 'Test2Last',\n          medical : {\n              contactId : 20,\n              hospitalId : 111\n          },\n          phone : ['111111111', '22222222222']\n    }]);\n}) \n```\n\n### Searching of the data\n\n#### Find\n* Can search for direct id value using the find operation and will return result if exists else will return null\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const record = models.users.find(1);\n});\n```\n\n#### FindOrFail \n* Will search for direct id(primary key) value and will return value or throw **NotFound** error.\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const record = await models.users.findOrFail(1);\n});\n```\n\n#### FindOrCreate\n* Will find the value at primary key and if no record is found then will create a new record and return it.\n\n```javascript\nconst data = {};\ndb.connect().then(async (models) =\u003e {\n    const record = await models.users.firstOrCreate(data);\n});\n```\n\n#### First\n* Will search for first occurrence in the table and return the value else return null\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const record = await models.users.first();\n});\n```\n#### FirstOrFail \n* Will search for first occurrence in the table and return the value else throws **NotFound** error\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const record = await models.users.firstOrFail();\n});\n```\n\n#### FirstOrCreate\n* Will search for first occurrence in the table and return the value else creates new record\n\n```javascript\nconst data = {};\ndb.connect().then(async (models) =\u003e {\n    const record = await models.users.firstOrCreate(data);\n});\n```\n\n#### FindIndex \n* Will return the first matching value of the index else will return null\n\n```javascript\nconst value = 'something';\ndb.connect().then(async (models) =\u003e {\n    const record = await models.users.findIndex('indexName', value);\n});\n```\n\n#### FindIndexOrFail \n* Will search for first occurrence in the table and return the value else throws **NotFound** error.\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const record = await models.users.first();\n});\n```\n\n#### FindIndexOrCreate\n* Will search for first occurrence in the table and return the value else will create a new entry in database and return it.\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const record = await models.users.first();\n});\n```\n\n#### FindAllIndex\n* Will search for all matching indexes and return array of results. If no result is found then an empty array is returned.\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const record = await models.users.findAllIndex('indexName', 'value');\n});\n```\n\n#### All\n* Will search for all matching occurrence in the table and return the value else return blank array\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const records = await models.users.all();\n});\n```\n\n### Index Searching\n* Direct search on indexes are possible but only one index search builder is allowed. This is due to limitation of indexedDB itself.\n* If you attempt to write another index query then the previous one will be overridden\n\n#### whereIndex\nDirect search on index. First parameter as the index name and second parameter as the index value\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.whereIndex('email','test@test.com').first();\n    \n    const contacts = await models.userContacts.whereIndex('userId',1).all();\n});\n```\n\n#### whereIndexIn\nMultiple search of index in the given range of values provided as array\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.whereIndexIn('email',['test@test.com','test1@test.com']);\n    \n    const contacts = await models.userContacts.whereIndexIn('userId',[2,54,1,5]).all();\n});\n```\n\n#### whereMultiIndexIn\nSearching of index which whose index type is multi entry thus allowing searching of array content  \n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.whereIndexIn('email',['test@test.com','test1@test.com']);\n    \n    const contacts = await models.userContacts.whereMultiIndexIn('phone',['12345','233343',13455,52222]).all();\n});\n```\n\n#### whereIndexGte\nSearch of index values against the point greater or equal to the given value. It is case sensitive\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.whereIndexGte('email','test@test.com').first();\n    \n    const contacts = await models.userContacts.whereIndexGte('userId',20).all();\n});\n```\n\n#### whereIndexGt\nSearch of index values against the point greater only to the given value. It is case sensitive.\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.whereIndexGt('email','test@test.com').first();\n    \n    const contacts = await models.userContacts.whereIndexGt('userId',20).all();\n});\n```\n\n#### whereIndexLte\nSearch of index values against the point less than or equal to the given value. It is case sensitive\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.whereIndexLte('email','test@test.com').first();\n    \n    const contacts = await models.userContacts.whereIndexLte('userId',20).all();\n});\n```\n\n#### whereIndexLt\nSearch of index values against the point less than only to the given value. It is case sensitive.\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.whereIndexLt('email','test@test.com').first();\n    \n    const contacts = await models.userContacts.whereIndexLt('userId',20).all();\n});\n```\n\n#### whereIndexBetween\nSearch of index values betweent the given lower and upper bound values. It is case sensitive for string values.\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.whereIndexBetween('email','test@test.com', 'zest@test.com').first();\n    \n    const contacts = await models.userContacts.whereIndexBetween('userId',20, 52).all();\n});\n```\n\n### Non Index Searching\nThere will be some columns where indexes are not there you can combine index search queries with non index search queries\nand build an adequate query to filter the data. Since only single indexed query can be fired once you can use these query builder option to fire other point searches on remaining indexes. Non index searches are performance heavy operation so be careful of such searches. If needed then make non indexed columns as indexed.\n\n\n#### where\nAdd a simple where clause to the query builder before or after the indexed builder to add condition. You can add multiple of these in succession.\n\n```javascript\n\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.where('isAdmin', true).whereIndexBetween('email','test@test.com', 'zest@test.com').where('isAdmin', false).first();\n    \n    const contacts = await models.userContacts.whereIndexBetween('userId',20, 52).where('id', 10).all();\n});\n```\n\n#### Nested Attributes\nTo search for a value under a nested attribute you can pass a dot notation value to the query builder column name.\n\n```javascript\n\ndb.connect().then(async (models) =\u003e {\n  \n    const contacts = await models.userContacts.whereIndexBetween('userId',20, 52).where('medical.contactId', 10).all();\n});\n```\n\n\n#### whereIn\nTo search for result in a multiple search values for column then pass array as an value for the search\n\n```javascript\n\ndb.connect().then(async (models) =\u003e {\n  \n    const contacts = await models.userContacts.whereIn('userId',[20, 52]).where('medical.contactId', 10).all();\n});\n```\n\n#### whereInArray\nTo search for result in a multiple search values for column which contains array of values then pass array as an value for the search\n\n```javascript\n\ndb.connect().then(async (models) =\u003e {\n  \n    const contacts = await models.userContacts.whereIn('phones',[20, 52]).where('medical.contactId', 10).all();\n});\n```\n\n#### gte\nSearch of values against the point greater or equal to the given value. It is case sensitive\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.gte('email','test@test.com').first();\n    \n    const contacts = await models.userContacts.gte('userId',20).all();\n});\n```\n\n#### gt\nSearch of values against the point greater only to the given value. It is case sensitive.\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.gt('email','test@test.com').first();\n    \n    const contacts = await models.userContacts.gt('userId',20).all();\n});\n```\n\n#### lte\nSearch of values against the point less than or equal to the given value. It is case sensitive\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.lte('email','test@test.com').first();\n    \n    const contacts = await models.userContacts.lte('userId',20).all();\n});\n```\n\n#### lt\nSearch of values against the point less than only to the given value. It is case sensitive.\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.lt('email','test@test.com').first();\n    \n    const contacts = await models.userContacts.lt('userId',20).all();\n});\n```\n#### between\nSearch of index values between the given lower and upper bound values. It is case sensitive for string values.\n\n```javascript\ndb.connect().then(async (models) =\u003e {\n    const user = await models.users.between('email','test@test.com', 'zest@test.com').first();\n    \n    const contacts = await models.userContacts.between('userId',20, 52).all();\n});\n```\n\n### Relations\nData from different tables can be fetched with association with current table using relations. The system supports following relations\n\n * Has One\n * Has Many\n * Has Many Multi-Entry\n * Has Many Through Multi-Entry\n \nThe relation builder is used to add a relation to the model for it to fetch. The first value is the name of model, followed\nby the relation type, then the local key of relation model, then local key of calling model and finally a callback to filter the values of relation model further which contains builder reference of relation model. The builder reference can also be used to fetch nested relations with same strategy.  \n\n\n#### Adding Normal Relations\nRelations can be added through function call **with** by passing array of relations. The with function can be called multiple times.\nIf duplicate models are found then previous one is replaced by new one. If you want to have multiple relations on same model then create a\ncustom ORM instance and then create your custom relations. \n\n```javascript\nmodels.userProfiles.with([{\n    model: models.users, // You can also pass object store name as string but its strongly recommended to use model instance\n    type: RelationTypes.HasOne, \n    foreignKey: 'id', \n    localKey: 'userId',\n    attributeName: 'overriddenRelationName' // if relation needs to be attached as a different property\n  }, ...])\n```\n \n#### Has One\n\nThe has one relation maps a single column of primary model containing the id reference of other table/object store directly. The matching relation will be single object instance mapped to table name property. If no matching relation is found then the item will be empty.\n\nExample a user instance having one user contact. The user contact fetching the user model using relation.\n\n```javascript\nimport {RelationTypes} from './dist/es2015/models/model.interface.js';\n\nconst profiles = await models.userProfiles.with([{\n        model: models.users, \n        type: RelationTypes.HasOne, \n        localKey: 'id', // the local key is optional  and should be provided if mapping is not directly to primary key\n        foreignKey: 'userId'\n      }])\n      .all();\n\n/**\n* each profile object will contain a matching users object as users property\n*/\n```\n\n#### Has Many\nThe has many relation maps single column of primary model containing the id reference of other table/object store with\nwith matching id. \n\nExample a user having multiple contacts. The user model query with all contacts associated.\n\n\n```javascript\nimport {RelationTypes} from './dist/es2015/models/model.interface.js';\n\nconst users = await models.users.whereIndexIn('id',[1,2,10,11])\n    .where('isAdmin', true)\n    .with([{model: model.userProfiles , type: RelationTypes.HasMany, foreignKey: 'userId'}])\n    .all();\n/**\n * each results object will have an userContacts property with matching result with users table\n**/\n```\n\n#### Has Many Multi Entry\n\nThe has many multi entry relation works just like has many but the primary model column value is an array set as\n multi-entry index.\n \nExample a address table/object store having relation to multiple users using userIds as array with mutli entry index.\n\n```javascript\nimport {RelationTypes} from './dist/es2015/models/model.interface.js';\n\nconst addresses = await models.addresss.with([{\n      model: model.users, \n      type: RelationTypes.HasManyMultiEntry, \n      localKey: 'id', \n      foreignKey: 'userIds'\n    }]).all();\n\n/**\n * each address object will have an users property which will be an array of matching users.\n */\n``` \n\n#### Has Many Through Multi Entry\n\nThe has many through multi entry relation is used when the parent model which is setting the relation has the index as multi entry.\nThis is reverse of has manu multi entry where child has index as multi.\n \nExample a address table/object store having relation to multiple users using userIds as array with mutli entry index.\n\n```javascript\nimport {RelationTypes} from './dist/es2015/models/model.interface.js';\n\nconst addresses = await models.addresss.with([{\n      model: model.users, \n      type: RelationTypes.HasManyThroughMultiEntry, \n      localKey: 'id', \n      foreignKey: 'userIds'\n    }]).all();\n\n/**\n * each address object will have an users property which will be an array of matching users.\n*/\n``` \n\n#### Custom Relation Builder\n* Using the **withCustom** you can load custom relations defined in the ORM class.\n\n\n```javascript\nimport {Model} from './dist/es2015/models/model.js';\n\nclass UserProfile extends Model {\n  static TableName = 'userProfiles'; \n}\n\nclass User extends Model {\n  static TableName = 'users';\n  \n  userProfile = ()=\u003e {\n    return this.hasOne(UserProfile, 'userId');\n  }\n}\n\nconst users = await models.users.whereIndexIn('id',[1,2,10,11])\n    .where('isAdmin', true)\n    .withCustom(['userProfile'])\n    .all();\n\n/**\n * each results object will have an userProfile property with matching result with users table\n**/ \n```\n\n#### Nested Relations\n* You can also call for nested relation to nth level using the secondry query builder of the relation\n\n```javascript\nimport {RelationTypes} from './dist/es2015/models/model.interface.js';\n\nconst users = await models.users.whereIndexIn('id',[1,2,10,11])\n    .where('isAdmin', true)\n    .with([{\n      model: models.userContacts, \n      type: RelationTypes.HasMany, \n      localKey: 'id', \n      foreignKey: 'userId', \n      func: (builder) =\u003e {\n        //refined search for relation\n        return builder.whereIn('id', [1,2,3])\n            .where('medical.contactId', 10)\n            .relation('contacts', models.users.RELATIONS.hasOne,'contactId', 'id');\n      }\n    }])\n    .all();\n\n/**\n * each results object will have an userContacts property with matching result with users table\n**/ \n```\n\n### Updating of records\n\n#### Save\n\nThis will update the data at the given primary id of the table with content provided. The whole content will not be replaced \nbut only the properties provided by default. To prevent deep merging you can optionally pass third parameter as false.\n\nPrimary key ,updatedAt and createdAt values will be ignored even if provided\n \n```javascript\n\nmodels.users.save(1,  {\n    isAdmin : false\n});\n```\n\n#### Save Index\n\nThis will update the data at the given index of the table with content provided for first matching index. The whole content will not be replaced \nbut only the properties provided by default. To prevent deep merging you can optionally pass third parameter as false.\n\nPrimary key ,updatedAt and createdAt values will be ignored even if provided\n \n```javascript\n\nmodels.users.saveIndex('indexName', 1,  {\n    isAdmin : false\n});\n```\n\n#### Save All  Index\n\nThis will update the data at the given index of the table with content provided for all matching index. The whole content will not be replaced \nbut only the properties provided by default. To prevent deep merging you can optionally pass third parameter as false.\n\nPrimary key ,updatedAt and createdAt values will be ignored even if provided\n \n```javascript\n\nmodels.users.saveIndex('indexName', 1,  {\n    isAdmin : false\n});\n```\n\n#### update\n\nThis will update the data with matching values according to the query builder given of the table with content provided. The whole content will not be replaced by default. To prevent deep merging you can optionally pass third parameter as false.\n \nPrimary key ,updatedAt and createdAt values will be ignored even if provided\n \n```javascript\n\nmodels.users.whereIndex('email', 'test@test.com').where('isAdmin', true).update({\n    isAdmin : false\n});\n```\n\n### Deletions in table\n\n\n#### delete\n\nThis will delete the data at the given primary id of the table.\n \n```javascript\n\nmodels.users.delete(3);\n```\n\n#### destroy\n\nThis will delete all the matching records according to the query created\n \n```javascript\n\nmodels.users.whereIndex('email', 'test@test.com').where('isAdmin', true).destroy();\n```\n\n#### deleteIndex\n\nThis will delete all the matching records on the index only. You can optionally pass the third param to indicate that the\nindex is a multi-entry index so that the search is correct.\n \n```javascript\n\nmodels.users.deleteIndex('email', 'test@test.com');\n```\n\n### Transactional Actions\nSometimes it is needed to work in a single transaction and commit the content once or fail throughout. For this purpose one\ncan use the transaction functionality in the system.\n\nOpen a transaction in any of the model and it will return entire list of models in transaction mode. Transaction mode is required to be set.\n\nCalling **transaction.abort()** will cause the transaction to fail.\n\n\n#### Usage\n```javascript\nimport {Connector} from './dist/es2015/connection/connector.js';\nimport {TransactionModes} from './dist/es2015/models/model.interface.js';\n\nlet db = new Connector(config);\n\n\n// Creating transaction through database\ndb.connect().then(async (models) =\u003e {\n  const {transaction, transactionModels} = db.openTransaction(TransactionModes.Write);\n  \n  transactionModels.users.create({email: 'email@email.com'});\n  transaction.abort();\n});\n   \n// Creating transaction through models\ndb.connect().then(async (models) =\u003e {\n const {transaction, transactionModels} = models.users.openTransaction(TransactionModes.Write);\n \n transactionModels.users.create({email: 'email@email.com'});\n transaction.abort();\n}); \n```\n\n### Aggregations\n\n#### Count\n\nThe count will return total number of records in the table against the result obtained by query builer object\n\n\n```javascript\n\nconst count = await models.users.whereIndex('email', 'test@test.com').where('isAdmin', true).count();\n```\n\n#### Average\n\nAggregate of the result at the given column will be provided. If the column contains non numeric value then it will be treated as a ZERO value \n\n\n```javascript\n\nconst average = await models.users.whereIndex('email', 'test@test.com').where('isAdmin', true).average('id')\nconst nestedAverage = await models.users.whereIndex('userId', 10).where('firstName', 'Test').average('medical.contactId');\n```\n\n#### Reduce\n\nReduce process can be fired using the reduce function passed. If needed an default value can be passed as a second parameter \n\n\n```javascript\nconst result = await models.users.whereIndex('email', 'test@test.com').where('isAdmin', true).reduce((result, carry) =\u003e carry + result.id, 0);\n\n/**\n * result with total number of records in the table \n**/\n\n```\n\n### Syncing\nSync actions allow syncing of new data and returns the updated record back. It is best choice to use when you want to map a record through an API or other service.\n\nAll Syncing actions can update the **syncOn** column if **SyncColumn** in migration of table schema is set to true. You can override the default column name using **SyncColumnName** attribute.\ncolumn name using **\n\n#### Sync\nThe **sync** action syncs at the primary key. By default it deep merges the data passed on but by providing the third parameter\nas false you can completely replace the data.\n\n```javascript\nconst updatedDataReceivedFromApi = {};\nawait models.users.sync(10, updatedDataReceivedFromApi);\n```\n\n#### sync\nThe **sync** action syncs at the primary key. By default it deep merges the data passed on but by providing the third parameter\nas false you can completely replace the data.\n\n```javascript\nconst updatedDataReceivedFromApi = {};\nawait models.users.sync(10, updatedDataReceivedFromApi);\n```\n\n#### syncIndex\nThe **syncIndex** action syncs at the index value at first matching record. By default it deep merges the data passed on but by providing the third parameter\nas false you can completely replace the data.\n\n```javascript\nconst updatedDataReceivedFromApi = {};\nawait models.users.syncIndex('indexName', 10, updatedDataReceivedFromApi);\n```\n\n#### syncAllIndex\nThe **syncIndex** action syncs at the index value for all matching record. By default it deep merges the data passed on but by providing the third parameter\nas false you can completely replace the data.\n\n```javascript\nconst updatedDataReceivedFromApi = {};\nawait models.users.syncAllIndex('indexName', 10, updatedDataReceivedFromApi);\n```\n\n## License\n[MIT License](https://github.com/maxgaurav/indexeddb-orm/blob/master/LICENSE.txt) ","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxgaurav%2Findexeddb-orm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxgaurav%2Findexeddb-orm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxgaurav%2Findexeddb-orm/lists"}