{"_id":"@42devs/firebase-firestorm","name":"@42devs/firebase-firestorm","dist-tags":{"latest":"2.5.0"},"versions":{"2.5.0":{"name":"@42devs/firebase-firestorm","version":"2.5.0","description":"A firestore ORM for Typescript","main":"lib/index.js","private":false,"scripts":{"build":"tsc","test":"GOOGLE_APPLICATION_CREDENTIALS='service-account.json' nyc --reporter=lcov mocha -r ts-node/register test/**/*.spec.ts && cat ./coverage/lcov.info | codacy-coverage","test:dev":"GOOGLE_APPLICATION_CREDENTIALS='service-account.json' nyc mocha -r ts-node/register test/**/*.spec.ts","docs":"typedoc --excludeExternals --mode file --out docs src","lint":"eslint src/**/*.ts","commit":"npx git-cz","semantic-release":"semantic-release"},"publishConfig":{"access":"public"},"keywords":["firestorm","firestore","firebase","orm"],"author":{"name":"Nicolas Martinez","email":"nicolas@42devs.cl"},"repository":{"type":"git","url":"git+https://github.com/42devs/firebase-firestorm.git"},"license":"MIT","nyc":{"extension":[".ts"],"include":["src/**"],"exclude":["**/*.d.ts","**/*.spec.ts"],"reporter":["html"],"all":true},"remarkConfig":{"plugins":["preset-lint-markdown-style-guide"]},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"dependencies":{"firebase":"^9.10.0","firebase-admin":"^11.0.1","reflect-metadata":"^0.1.13"},"devDependencies":{"@types/chai":"^4.3.3","@types/chai-as-promised":"^7.1.5","@types/mocha":"^9.1.1","@typescript-eslint/eslint-plugin":"^5.38.1","@typescript-eslint/parser":"^5.38.1","chai":"^4.3.6","chai-as-promised":"^7.1.1","codacy-coverage":"^3.2.0","cz-conventional-changelog":"^3.3.0","dotenv":"^16.0.2","eslint":"^8.24.0","eslint-config-airbnb-base":"^15.0.0","eslint-config-airbnb-typescript":"^17.0.0","eslint-plugin-import":"^2.26.0","eslint-plugin-prettier":"^4.2.1","prettier":"^2.7.1","mocha":"^10.0.0","mocha-lcov-reporter":"^1.3.0","mock-cloud-firestore":"^0.12.0","nyc":"^15.1.0","remark-cli":"^11.0.0","remark-lint":"^9.1.1","remark-preset-lint-recommended":"^6.1.2","source-map-support":"^0.5.21","ts-node":"^10.9.1","typedoc":"^0.23.15","typescript":"^4.8.3"},"types":"./lib/index.d.ts","gitHead":"94ff9767dce05cd4cad286242f38928f375d7003","bugs":{"url":"https://github.com/42devs/firebase-firestorm/issues"},"homepage":"https://github.com/42devs/firebase-firestorm#readme","_id":"@42devs/firebase-firestorm@2.5.0","_nodeVersion":"18.9.1","_npmVersion":"8.19.1","dist":{"integrity":"sha512-sB20qbWYTctDRxlgt/xVCJSd7vxiDJmeRXq4qi+h4noF+0W2wlKmHwJe7IdoQEZdK5ggULnblhUnjfD2aoMdmA==","shasum":"06a61f375cb8d9c8e01fbaf10a91440dca758663","tarball":"https://registry.npmjs.org/@42devs/firebase-firestorm/-/firebase-firestorm-2.5.0.tgz","fileCount":66,"unpackedSize":804671,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCcW8LmdZid/IvGG0NaMqIU1a+9jUMPf94SodqGjC6gUgIhAO2WYOLbEGbtbOxdbnnQJWMEIqDQNdGMybSdYU413yRW"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjMpT+ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoCuhAAlMaMmggj/1Ra/c4Emwvsz19nswl6g8E6GiPT2tCCUBk4Rpd3\r\nps69FXCLNTD/cVklnSwTEBVE9TKWFvCkpDNIvwvowusopewYCw1PZk76bOwo\r\niXU7RFez3AYN6fHdUbVO4B4MFujtyttv1eOsb79NH8TFlGwwV64BveGwIIn6\r\ngbzEECfVqwrzNE3zhFh7/MJkFtg6jND6xctSWmeM2rgNbV/znLZMoX0nE3ZE\r\nvxrEpRpuJ7S1uCII0k7965BWKYpZTFtTSUxCnWUds3XVDQFlWDznqgjgnAwX\r\ngg+nnIK+0zzUW1UkOuqRO7EOufXek9k5RRYiHeGPiQRDJQtiN/TUugKclPAi\r\nGK/tmkq6MwgaefMawaZlrNp/yrxnUrzOPIzMsb52KwnJAqiGBUo1czIdvh12\r\nrxMxyzCPfSqQuikDxNv0KaNOhFtmqtVVnqZX3gLajR15qQoypwVveWFk87dT\r\nrVJ2GOv/ftTfvdkozx90U7+qX/WC28lhFbw6Syf/YPv0SW8kG5P7WDFOTBq/\r\ntAsuF3tPCb4jy4MLTlNNODg7eBnUAzDNyt8uLvRgJhOCQBmAsy1/MRlC/tUM\r\naaJ9QAPxby34Ws7xa3kj1CvseVXcXlBozwWiFN/RhJJVJkema00/FEB6WQox\r\nG8x6NNNtl5Tn7z1EVgbHJX2+oxeaFQ9s3h0=\r\n=+t2h\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"themakunga","email":"nmartinezv@icloud.com"},"directories":{},"maintainers":[{"name":"themakunga","email":"nmartinezv@icloud.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/firebase-firestorm_2.5.0_1664259325828_0.8181863752400396"},"_hasShrinkwrap":true}},"time":{"created":"2022-09-27T06:15:25.766Z","2.5.0":"2022-09-27T06:15:26.055Z","modified":"2022-09-27T06:15:26.228Z"},"maintainers":[{"name":"themakunga","email":"nmartinezv@icloud.com"}],"description":"A firestore ORM for Typescript","homepage":"https://github.com/42devs/firebase-firestorm#readme","keywords":["firestorm","firestore","firebase","orm"],"repository":{"type":"git","url":"git+https://github.com/42devs/firebase-firestorm.git"},"author":{"name":"Nicolas Martinez","email":"nicolas@42devs.cl"},"bugs":{"url":"https://github.com/42devs/firebase-firestorm/issues"},"license":"MIT","readme":"# Firebase Firestorm for Typescript\n\n[![Build Status](https://travis-ci.org/42devs/firebase-firestorm.svg?branch=master)](https://travis-ci.org/42devs/firebase-firestorm)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/0055aad0e1244ebea87b08af2eed7906)](https://www.codacy.com/app/42devs/firebase-firestorm?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=42devs/firebase-firestorm&amp;utm_campaign=Badge_Grade)\n[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/0055aad0e1244ebea87b08af2eed7906)](https://www.codacy.com/app/42devs/firebase-firestorm?utm_source=github.com&utm_medium=referral&utm_content=42devs/firebase-firestorm&utm_campaign=Badge_Coverage)\n\nFirestorm is an [ORM](https://en.wikipedia.org/wiki/Object-relational_mapping)\nfor [firestore](https://firebase.google.com/docs/firestore) which can be used\nwith Typescript.\n\n**This library currently only supports the [client Firebase SDK](https://github.com/firebase/firebase-js-sdk).**\n\n## Contents\n\n-   [Requirements](#requirements)\n\n-   [Installation](#installation)\n\n-   [Usage](#usage)\n\n    -   [Getting Started](#getting-started)\n    -   [Custom Data Types](#custom-data-types)\n    -   [Initialization Options](#initialization-options)\n\n-   [Important Gotcha's](#important-gotchas)\n\n-   [Limitations](#limitations)\n\n-   [Development](#development)\n\n    -   [Setup](#setup)\n    -   [Testing](#testing)\n\n-   [Contributing](#contributing)\n\n-   [License](#license)\n\n## Requirements\n\nFirestorm relies on using Typescript's \n[experimental decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)\nfor defining your models. Please ensure you have the following in your `tsconfig.json`\n(ES5 is minimum target):\n\n````json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES5\",\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true,\n  }\n}\n````\n\n## Installation\n\n```bash\n$ npm install firebase-firestorm\n```\n\n## Usage\n\n### Getting Started\n\nIn this section, we will walk you through an example of how a basic blogging\ndatabase might look using posts, comments and authors.\n\n#### 1. Initialize firestorm\n\nCall `firestorm.initialize(firestore, options?)` as soon as you initialize\nyour firestore app. See [intialization options](###-initialization-options)\nfor more information about intiailizing firestorm.\n\n````typescript\nimport * as firestorm from 'firebase-firestorm';\n...\nconst firestore = firebase.initializeApp(...).firestore();\nfirestorm.initialize(firestore, /* options */);\n...\n````\n\n#### 2. Defining root collections\n\nHere we have a class representing a `posts` collection. Entity classes are\ntypically non-pluralized as they represent a single document from that\ncollection. To define a root collection you must:\n\n-   Extend from the `Entity` class.\n-   Annotate your class with `@rootCollection(opts: ICollectionConfig)`.\n-   Declare a series of fields, annotated with `@field(opts: IFieldConfig)`.\n\n```typescript\nimport { Entity, rootCollection, field } from 'firebase-firestorm';\n\n@rootCollection({\n  name: 'posts',\n})\nexport default class Post extends Entity {\n  @field({ name: 'title' })\n  title!: string;\n\n  @field({ name: 'content' })\n  content!: string;\n}\n```\n\n#### 3. Defining subcollections\n\n> Each of your models, whether they represent a root collection or\n> subcollection must extend from the `Entity` class provided.\n\nNow we want documents in the `posts` collection to have a subcollection \nof `comments`. First, we need to create a class for the comments. Notice\nhow we do not annotate the class with `@rootCollection`.\n\n```typescript\nimport { Entity, rootCollection, field } from 'firebase-firestorm';\n\nexport default class Comment extends Entity {\n  @field({ name: 'content' })\n  content!: string;\n\n  @field({ name: 'by' })\n  by!: string;\n}\n```\n\nBack in the `Post` class, we can add `Comment` as a subcollection using the `@subCollection(opts: ISubcollectionConfig)` decorator.\n\n```typescript\nimport { Entity, ICollection, rootCollection, field } from 'firebase-firestorm';\nimport Comment from './Comment';\n\n@rootCollection({\n  name: 'posts',\n})\nexport default class Post extends Entity {\n  @subCollection({\n    name: 'comments',\n    entity: Comment, // we must define the entity class due to limitations in Typescript's reflection capabilities. Progress should be made on this issue in future releases.\n  })\n  comments!: ICollection<Comment>;\n  ...\n}\n```\n\n#### 4. Defining document references\n\nFinally we want documents in the `posts` collection to reference an author in\nan `authors` collection (another root collection). First, we define the `Author` entity:\n\n```typescript\nimport { Entity, rootCollection, field } from 'firebase-firestorm';\n\n@rootCollection({\n  name: 'authors',\n})\nexport default class Author extends Entity {\n  @field({ name: 'name' })\n  name!: string;\n}\n```\n\nThen we can add an `Author` reference to the `Post` entity using the `@documentRef(opts: IDocumentRefConfig)` decorator:\n\n```typescript\nimport { Entity, ICollection, IDocumentRef, rootCollection, field } from 'firebase-firestorm';\nimport Author from './Author';\n\n@rootCollection({\n  name: 'posts',\n})\nexport default class Post extends Entity {\n  @documentRef({\n    name: 'author',\n    entity: Author, // we must define the entity class due to limitations in Typescript's reflection capabilities. Progress should be made on this issue in future releases.\n  })\n  author!: IDocumentRef<Author>;\n  ...\n}\n```\n\n#### 5. Querying/updating data\n\nNow we've built our model, we're ready to start querying. Calling\n`Collection(entity : IEntity)` will return a list of methods use can\nuse to manipulate the data.\n\n##### Getting a document\n\n```typescript\nconst post = Collection(Post).get('post-1').then((post : Post) => {\n  console.log(post);\n});\n```\n\n##### Getting a subcollection\n\nIn our example `Comment` is a subcollection of `Post`. You can get\nsubcollections from a retrieved document, or a document reference.\n\n````typescript\n// Comment subcollection from document.\nconst post = Collection(Post).get('post-1').then((post : Post) => {\n  const commentCollection = post.collection(Comment);\n});\n\n// Comment subcollection from document ref.\nconst postRef = Collection(Post).doc('post-1');\nconst commentCollection = postRef.collection(Comment);\n// Finds all comments from commentCollection.\nconst commentsSnap = await commentCollection.find();\n\n````\n\n##### Querying data\n\nCalling `query()` on a collection will allow you to build queries in a [similar fashion to the standard Firestore SDK](https://firebase.google.com/docs/firestore/query-data/queries). You can build a query by chaining together methods, and finally calling the `get()` method to fetch the result. Omitting filters after the `query()` method will return all results from a collection.\n\n```typescript\n// Build the query.\nconst query = Collection(Post)\n  .query()\n  .where('title', '==', 'Example Title');\n\n// Fetch and manipulate the result.\nquery.get().then((snapshot) => {\n  const post = snapshot.docs;\n  ...\n});\n```\n\n##### Creating documents\n\n```typescript\nconst post = new Post();\npost.id = 'post-1'; // id is optional, if it is not defined it will be generated by firestore.\npost.title = 'Untitled';\nlet savedPost : Post;\nCollection(Post).create(post).then((_savedPost : Post) => {\n  savedPost = _savedPost;\n});\n```\n\n##### Updating documents\n\n```typescript\nconst post = new Post();\npost.id = 'post-1'; // id is required.\npost.title = 'Untitled';\nlet savedPost : Post;\nCollection(Post).update(post).then((_savedPost: Post) => {\n  savedPost = _savedPost;\n});\n```\n\n##### Removing documents\n\n```typescript\nCollection(Post).remove('post-id').then(...);\n```\n\n#### 5. Realtime Updates\n\nYou can set up listeners for changes on either a single document, or a group of documents for a query. This is done a [similar way to the standard Firebase SDK](https://firebase.google.com/docs/firestore/query-data/listen).\n\n##### Listening to document updates\n\nYou can attach a listener to a single document reference by using the `onSnapshot(callback)` method.\n\n````typescript\nCollection(Post).doc('post-id').onSnapshot(\n  (snapshot): DocumentSnapshot<Post> => {\n    const post: Post = snapshot.doc;\n  }\n);\n...\n````\n\nThe callback function will executed once with the initial snapshot payload, and then for any subsequent updates to that document.\n\n##### Listening to a collection (or query)\n\nYou can attach a listener to a group of documents in a collection by using the `onSnapshot(callback)` method on a collection query.\n\n````typescript\nCollection(Post).query().onSnapshot(\n  (snapshot): QuerySnapshot<Post> => {\n    const posts: Post[] = snapshot.docs;\n  }\n);\n\n// or\n\nCollection(Post)\n  .query()\n  .where('title', '==', 'Example Title')\n  .onSnapshot(\n    (snapshot): QuerySnapshot<Post> => {\n      const posts: Post[] = snapshot.docs;\n    }\n  );\n````\nThe callback function will executed once with the initial snapshot payload, and then for any subsequent updates to that query. As per the Firebase SDK, you call see the [document changes in each snapshot](https://firebase.google.com/docs/firestore/query-data/listen#view_changes_between_snapshots) using the `snapshot.docChanges()` method.\n\n\n\n#### 6. Formatting data\n\nAn instance of entity maybe contain properties such as\nsubcollections which you do not wish to include if, for example,\nyou are building a REST API. Calling the `toData()` method on\nan instance of an entity will produce a plain JSON object\ncontaining just primitive data, nested JSON objects, and\ndocument reference which have already been retrieved using\nthe `.get()` method. For example:\n\n```typescript\nimport { Collection } from 'firebase-firestorm';\nimport Author from './Author';\nimport Post from './Post';\n\nCollection(Post).get('post-1').then((post: Post) => {\n  console.log(post.toData());\n  /*\n  Output:\n  {\n    id: ...,\n    title: ...,\n    content: ...\n  }\n  */\n post.author.get().then((author: Author) => {\n   console.log(post.toData());\n   /*\n    Output:\n    {\n      id: ...,\n      title: ...,\n      content: ...,\n      author: {\n        id: ...,\n        name: ...\n      }\n    }\n   */\n });\n});\n```\n\n### Custom Data Types\n\n#### Arrays\n\nFirestore documents can contain arrays of strings, numbers, objects,\netc. Defining arrays in Firestorm is as simple as assigning properties\nas array types in your `Entity` files. For example:\n\n```typescript\nclass Example extends Entity {\n  @field({ name: 'example_property_1' })\n  property1!: string[];\n\n  @field({ name: 'example_property_2' })\n  property2!: IDocumentRef<AnotherEntity>[];\n}\n```\n\n#### Nested Data\n\nFirestore documents can contains nested objects (or maps). For a nested\nobject, you need to create a new class to represent that object, and add\na property with that class in your `Entity`, wrapped with the `@map` decorator.\n\n```typescript\nclass Example extends Entity {\n  @map({ name: 'nested_object' })\n  nestedObject!: Nested;\n}\n\nclass Nested {\n  @field({ name: 'nested_property' })\n  nestedProperty!: string;\n}\n```\n\nAnd then to use this entity:\n\n```typescript\nconst nested = new Nested();\nnested.nestedProperty = 'test';\nconst example = new Example();\nexample.nestedObject = nested;\n```\n\n**Important**: If your is nested data is an array you must provide the 'entity'\noption in the configuration.\n\n```typescript\nclass Nested {\n  @map({ name: 'nested_array', entity: Nested })\n  nestedObject: Nested[];\n}\n```\n\n#### Geopoints\n\nGeopoints store locational data and can be used as fields. We have a wrapper\nclass for firestore's GeoPoint which basically serves the same functionality.\n\n```typescript\nclass Example extends Entity {\n  @geoPoint({\n    name: 'geopoint_property',\n  })\n  geopoint!: IGeoPoint;\n} \n```\n\nAnd then to assign a GeoPoint:\n\n```typescript\nconst example = new Example();\nexample.geopoint = new Geopoint(latitude, longitude);\n```\n\n#### Timestamps\n\nYou can represent date & time data in your `Entity` files. Like geopoints,\nour timestamp representation is essentially a wrapper of firestore's. You\ncan set the options for the field to `updateOnWrite` which uses the server\ntimestamp when creating or updating documents, or `updateOnCreate` or `updateOnUpdate`.\n\n```typescript\nclass Example extends Entity {\n  @timestamp({\n    name: 'timestamp_property',\n    updateOnWrite: true,\n  })\n  timestamp!: ITimestamp;\n}\n```\n\n### Initialization Options\n\n`firestorm.intialize({ ...opts : IFireormConfig })` can be called\nwith the following options:\n\n| Option            | Description                                                                                                                                                                                                               | Type                       |\n| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |\n| `fieldConversion` | Providing this option will convert `Entity` propertity names into firestore collection names so you don't need to provide the `name` option in `@field()` decorators. To view available values please check out the docs. | `enum FieldConversionType` |\n\n## Important Gotcha's\n\n-   All files for root collections, subcollections and nested maps\nmust have a unique class name due to the way the metadata storage\nhooks everything up. We're currently looking for a way to resolve\nthis issue.\n\n-   Make sure fields such as geopoints, timestamps and document\nreference's have the `I` infront of the type, e.g. `IDocumentRef`,\n`ITimestamp`, `IGeoPoint`.\n\n## Limitations\n\n-   Transactions and batched writes are currently unsupported.\n\nIf you would like to help resolve these issues, feel free\nto make a a [pull request](#pull-requests).\n\n## Development\n\n### Setup\n\n1.  Clone the repo.\n2.  Install dependencies.\n\n```bash\ncd firebase-firestorm \nnpm install\n```\n\n### Testing\n\nThe testing script looks for `*.spec.ts` files in the `src`\nand `test` directory.\n\n```bash\nnpm test\n```\n\n## Contributing\n\n### Found a bug?\n\nPlease report any bugs you have found submitting an issue to our Github\nrepository, after ensuring the issue doesn't already exist. Alternatively,\nyou can make a pull request with a fix.\n\n### Pull Requests\n\nIf you would like to help add or a feature or fix a bug, you can do so\nby making a pull request. The project uses\n[Conventional Commits](https://www.conventionalcommits.org), so please\nmake sure you follow the spec when making PRs. You must also\ninclude relevant tests.\n\n## License\n\n[MIT](license.md)\n","readmeFilename":"README.md"}