# PouchType An type-based abstraction layer over PouchDB inspired by [Hood.ie](https://hood.ie/) and [Django](https://djangoproject.com) ## Extending the TypeHandler class PouchType works by extending the _TypeHandler_ class with methods to define how a document type should be handled. The resulting class is instantiated with a PouchDB instance and used to interact with documents of that type. All subclasses of _TypeHandler_ must override the `getUniqueID` method. This method should return a unique string for documents of this type. (NOTE: The document id will be prefixed with the type_string as well to avoid collisions across types.) ```js import { PouchDB } from 'pouchdb'; import { TypeHandler } from 'PouchType'; const PDB = PouchDB.plugin(find); // PouchType requires the find plugin. class ContactHandler extends TypeHandler { getUniqueID(doc) { return doc.email; } validate(doc) { super.validate(doc); if (typeof doc.email != 'string') { throw new Error('email property is required'); } else if (doc.email.length <= 2) { throw new Error('email must be longer than 2 characters'); } } } ``` ## TypeHandler management methods ### getUniqueID(doc) _This method must be overridden in subclasses._ Return a unique string that will be used to populate `doc._id` if it isn't already populated. ### hash(doc) Returns a hash string of the current document for comparison. By default this is "`doc._id`:`doc._rev`" and will work as long as the hash is only taken after any changes are saved. You may wish to override this to provide content-specific hashing. ### index(name, fields) Create a index to be used in a `filter` selector and sort options. Specify the `name` of the index and the `fields` as an array of strings of the document properties to include in the index. ### isType(doc) Check if the passed `doc` belongs to this handler. ### validate(doc) Check if the passed `doc` has valid data before it is written. Invalidation happens by raising an exception. For more fine-grained validation, refer to the [pouchdb-validation](https://github.com/pouchdb/pouchdb-validation) plugin or the [validate_doc_update](http://guide.couchdb.org/draft/validation.html) function. ## TypeHandler query methods ### get(id) Return the document referenced by `id` or `null` if the document does not exist. ### getOrCreate(doc, defaults={}) If the passed document doesn't have a `_id` property, populate it. Try to lookup a document with the `id`. If it exists, update it with the properties in `doc`. If it does not exist, add the properties in `defaults` to `props` and save the new document. ### filter(selector, options={}) Return an array of documents that match the criteria in `selector`. `options.index` can contain the `name` passed to `index()` if needed. All other option properties are passed through to the [PouchDB.find()](https://pouchdb.com/api.html#query_index) ### watch(selector, options={}) The parameters for `watch()` are identical to `filter()` but `watch()` returns a [computed](../frptools/README.md#computed) instance that will call subscribers whenever any data matching the selector changes. ## TypeHandler change methods ### remove(docOrId) `remove` accepts a document or an id string. Flag this document as `doc._deleted == true`. This will cause it to not show up in `get`, `filter` or `watch` results. (_Note_: documents are left in the database in this state to allow for deletion to be synced to other nodes. To truly remove documents, [compact your database](https://pouchdb.com/api.html#compaction).) ### save(doc) If the document does not have properties `_id` or `type`, populate them appropriately. Run `TypeHandler.validate` on the document. If validate doesn't throw any errors, then save the document to the database. It's `_rev` property will be updated to reflect the revision in the database. ### update(doc, props) Deeply assign `props` to the passed `doc` object and `save()` it. ### addAttachment(doc, key, blob) Attach the passed `blob` to the document referenced with the `key` string. ### removeAttachment(doc, key) Remove a previously attached blob at `key`. ### getAttachment(doc, key) Return a previously attached blob at `key` or `null` if none exists. ## Using Types ```js const db = PDB('type_example'); export const Contact = new ContactHandler(db, 'contact'); const doc = await Contact.getOrCreate({ name: 'John Doe', email: 'jd@example.com' }); ```