Options
All
  • Public
  • Public/Protected
  • All
Menu

SlothDB

styled with prettier Greenkeeper badge Travis Coveralls

A typescript ORM that uses annotation and classes to describe the database

Features

  • Built using annotations
  • Simple field support (update and read doc values)
  • URI fields - string fields which value depends on other fields
  • Versatile PouchDB support
  • Views and index support
  • Relation support : oneToMany, manyToOne and cascading removal

Usage

Describing the document schema

Simply use an interface to describe the document schema, with at least an _id string field

Describing the entity class

The entity class needs to extend BaseEntity and requires the SlothEntity annotation (passing the database name).

@SlothEntity('students')
class StudentEnt extends BaseEntity<IStudent> {

Describing the fields

Add your document fields to the entity class and decorate them using SlothField. The assigned value will be used as a default value.

@SlothField()
age: number = 18

Describing your URIs

It is common practice to generate string URIs from the other document values and use it as an _id or on other indices for easier sorting and relationship description (especially oneToMany). The SlothURI decorator takes at least two arguments: the first one is the root, which is a constant string value. Using the database name when not describing relation is recommended. For example students/john-doe has the students root, but does not describe any relationship. If your document belongs to a parent document then a root that includes all documents types would be recommended, for example university would cover students, marks and courses. The other values are field names, included in you document, to be used to build the URI in the following order. Each specified field will then be stringified and slugified using toString() and limax. For example:

@SlothURI('students', 'surname', 'name')
_id: string = ''

Please note we are assigning a default value to the _id field that will get ignored.

This is the equivalent of a students/:surname/:name DocURI.

PouchDB Factory

A PouchFactory is a simple function that returns a PouchDB instance for a given database name. Every function in SlothDatabase except withRoot requires as an argument a PouchFactory. Entities are attached a PouchFactory in the constructor, so the entity functions (save(), remove(), etc) does not require a factory. A simple factory would be (name: string) => new PouchDB(name)

Database operations

const author1 = Author.create(factory, {...})

await author.save()

author.age = 42

await author.save()

await author.remove()

Relationships

SlothDB supports for now one type of relationship: belongsTo/oneToMany (which is the same relationship, but with a different perspective).

The annotation SlothRel can be used on the field that describes a belongsTo relationship, that-is-to-say the field value is a string representing the parent document _id field. The SlothField decorator is not usable with this annotation. If the target field is included in SlothURI, then the string value of this field (which is the _id of the parent document) will have its root removed in order to include it in the URI. The value is not slugified using limax, so / are not escaped. For example students/mit/john-doe will become mit/john-doe and a mark URI for this student would become marks/mit/john-doe/chemistry/2018-04-20 whereas the original URI has only 3 parts (student, course, date).

To describe a belongsTo relationship you can use SlothRel with a belongsTo object:

@SlothRel({belongsTo: () => Student})
student_id: string = ''

The belongsTo value is just a simple function that returns the parent SlothDatabase instance, to avoid circular dependency conflicts.

If the cascade option is not present or true, removing all child document of a single parent will also remove the parent.

The annotation SlothRel can also be used on a non-document field, with the hasMany function, which returns the SlothDatabase instance of the child entity. The target field is a function that returns a child instance. This function should null, the annotation will replace it with an impl:

@SlothRel({ hasMany: () => Album })
albums: () => Album

The SlothRel uses the withRoot function of SlothDatabase which return a SlothDatabase that prefixes the startkey argument of the allDocs calls with the current document _id hence the id needs to be described using the same root and the first key of the child's _id must be the parent id field.

Views and indexes

The SlothView annotation describes a CouchDB map function. It takes as an argument a function (doc, emit) => void, the view name (default to by_<field name>) and the optional design document identifier (default to views). Please note that this function does not modify any behavior of the target, so the decorated field requires another decorator (like SlothField or SlothURI) and the choice of the decorated field is purely semantic and decorating another field will only change the view name. Depending on the typescript target, you might want to use es5 functions (avoid fat-arrow functions).

The SlothIndex is a function that applies the SlothView decorator with emit(doc['${key}'].toString()) as a function to create a basic index on the decorated field.

The SlothDatabase class takes as a third generic argument extending a string that describes the possible view values. The queryDocs function then takes as an argument the string constrained by the generic parameter. It is then recommended to use an enum to identify views:

enum AuthorView {
  byName = 'views/by_name'
  byAge = 'views/by_age'
}

...

const Author = new SlothDatabase<IAuthor, AuthorEntity, AuthorView>(AuthorEntity)

const seniorAuthors = await Author.queryDocs(factory, AuthorView.byAge, 60, 130)

Full example

interface IAuthor {
  _id: string,
  name: string
}

@SlothEntity('authors')
class AuthorEntity extends BaseEntity<IAuthor> {
  @SlothURI('library', 'author')
  _id: string = ''

  @SlothField()
  name: string = 'Unknown'
}

export const Author =  new SlothDatabase<IAuthor, AuthorEntity>(AuthorEntity)

interface IBook {
  _id: string,
  name: string,
  author: string
}

export enum BookViews {
  ByName = 'views/by_name'
}

@SlothEntity('books')
class BookEntity extend BaseEntity<IBook> {
  @SlothURI('library', 'author', 'name')
  _id: string = ''

  @SlothIndex()
  @SlothField()
  name: string = 'Unknown'

  @SlothRel({belongsTo: Author})
  author: string = 'library/unknown'
}

export const Book = new SlothDatabase<IBook, BookEntity, BookViews>(BookEntity)

Then to use

const jrrTolkien = Author.create(factory, {name: 'JRR Tolkien'})

jrrTolkien._id === 'library/jrr-tolkien'
jrrTolkien.name === 'JRR Tolkien'

await jrrTolkien.exists() === false
await jrrTolkien.save()
await jrrTolkien.exists() === true

const lotr = Book.create(factory, {name: 'The Lord Of The Rings', author: jrrTolkien._id})

lotr._id === 'library/jrr-tolkien/the-lord-of-the-rings'

const golding = await Author.put(factory, {name: 'William Golding'})

await golding.exists() === true

await Book.put(factory, {name: 'The Lord of The Flies', author: golding._id})

const booksStartingWithLord = await Author.queryDocs(factory, BookViews.ByName, 'The Lord of The')
booksStartingWithLord.length === 2

NPM scripts

  • npm t: Run test suite
  • npm start: Run npm run build in watch mode
  • npm run test:watch: Run test suite in interactive watch mode
  • npm run test:prod: Run linting and generate coverage
  • npm run build: Generate bundles and typings, create docs
  • npm run lint: Lints code
  • npm run commit: Commit using conventional commit style (husky will tell you to use it if you haven't :wink:)

Index

Type aliases

BelongsToDescriptor

BelongsToDescriptor: object

Describes a manyToOne or oneToOne relation where the entity specified here is the parent and the entity owner is the child

Type declaration

  • belongsTo: function

    Specify a database factory, a simple function that returns a database This is useful for circular dependency

    type

    {SlothDatabase} the parent database factory

  • Optional cascade?: undefined | true | false

    Specify that no parent should have no children, so that whenever deleting a child entity the parent is automatically deleted as well if it's an only child

    type

    {boolean}

ChangeAction

ChangeAction: object | object | object

HasManyDescriptor

HasManyDescriptor: object

Describes a oneToMany relation where the entity specified here is the child entity, and the entity owner is the parent

Type declaration

  • Optional cascade?: undefined | true | false

    Specifies that whenever removing the parent entity, the children should get removed as well

    Defaults to true, and recommend keeping it this way

    type

    {boolean}

  • hasMany: function

    Specify a database factory, a simple function that returns a database This is useful for circular dependency

    type

    {() => SlothDatabase} the child database factory

PouchFactory

PouchFactory: function

Type declaration

    • (name: string): Database<S>
    • Parameters

      • name: string

      Returns Database<S>

RelationDescriptor

An relation descriptor, either hasMany or belongsTo

see

SlothRel

Subscriber

Subscriber: function

A function that listens for changes actions, can be a redux dispatch

Type declaration

Variables

Const debug

debug: IDebugger = Debug('slothdb')

Const slug

slug: any = require('limax')

Functions

SlothEntity

  • SlothEntity<S>(name: string): (Anonymous function)
  • This decorator is used to mark classes that will be an entity, a document This function, by extending the constructor and defining this.sloth property effectively allows the usage of other property decorators

    Type parameters

    • S: object

      The database schema

    Parameters

    • name: string

      The database name for this entity

    Returns (Anonymous function)

SlothField

  • SlothField<T>(docKeyName?: undefined | string): (Anonymous function)
  • SlothField decorator is used to mark a specific class property as a document key. This introduces a few behaviors:

    • setting the value in the constructor (or directly alongside declaration) will set its default value
    • mutating the value will update it in updatedProps
    • accessing the value will first look into updatedProps, then props and then default values

    Type parameters

    • T

      the value type

    Parameters

    • Optional docKeyName: undefined | string

      specifies the document key name, default to prop key name

    Returns (Anonymous function)

SlothIndex

  • SlothIndex<S, V>(viewId?: V, docId?: undefined | string): (Anonymous function)
  • Creates an index for a field. It's a view function that simply emits the document key

    see

    SlothDatabase.queryDocs

    export
    template

    S

    Type parameters

    • S

    • V: string

    Parameters

    • Optional viewId: V
    • Optional docId: undefined | string

    Returns (Anonymous function)

    the decorator to apply on the field

SlothRel

  • SlothRel is used to indicate that a specific string property corresponds to another entity identifier. The possible relations are:

    • belongsTo: one or several entities belongs to a parent entity
    • hasMany: one entity has several other entities; the relation is stored the _id
    see

    RelationDescriptor

    Parameters

    Returns (Anonymous function)

SlothURI

  • SlothURI<S>(prefix: string, ...propsKeys: keyof S[]): (Anonymous function)
  • The SlothURI decorator describes a class parameter that has no intrisic value but which value depends on the other properties described as a path.

    The path has a root value, which is a constant and should be either the database name pluralized, or a namespace. For example in library management system, the root could be either library or books. It is recommended to use a namespace for relational databases and the database name for orphans.

    The path components, following the root, should be slugified properties of the entity. If the path needs to include another entity identifier, as often it needs to be in relational database, then the root of the other entity id should be omitted, but path separator (/) should NOT be escaped;, even in URLs. The path components are described using their property names.

    Type parameters

    • S

      the document schema

    Parameters

    • prefix: string

      the URI root

    • Rest ...propsKeys: keyof S[]

      key names to pick from the document

    Returns (Anonymous function)

SlothView

  • SlothView<S, V>(fn: function, viewId?: V, docId?: string): (Anonymous function)
  • Creates a view for a field. This function does not modify the behavior of the current field, hence requires another decorator such as SlothURI or SlothField. The view will be created by the SlothDatabase

    export
    template

    S

    Type parameters

    • S

    • V: string

    Parameters

    • fn: function

      the view function, as arrow or es5 function

        • (doc: S, emit: Function): void
        • Parameters

          • doc: S
          • emit: Function

          Returns void

    • Optional viewId: V
    • Default value docId: string = "views"

    Returns (Anonymous function)

    the decorator to apply on the field

belongsToMapper

  • belongsToMapper<S>(target: any, keyName: string): (Anonymous function)
  • Type parameters

    • S: object

    Parameters

    • target: any
    • keyName: string

    Returns (Anonymous function)

Private getProtoData

  • getProtoData(obj: any, createIfNotFound?: boolean): ProtoData
  • Extract the ProtoData from a class prototype, possibly creating it if needed

    see

    ProtoData

    Parameters

    • obj: any

      the object to extract data from

    • Default value createIfNotFound: boolean = false

      create the protoData if it is undefined

    Returns ProtoData

Private getSlothData

  • Extract sloth data from an entity instance, throwing an exception if it can't be found

    Type parameters

    • S

      the entity schema

    Parameters

    • obj: object

      the class instance to extract from

    Returns SlothData<S>

mapPropsOrDocToDocument

  • mapPropsOrDocToDocument(__namedParameters: object, data: any): any

Legend

  • Module
  • Object literal
  • Variable
  • Function
  • Function with type parameter
  • Index signature
  • Type alias
  • Enumeration
  • Enumeration member
  • Property
  • Method
  • Interface
  • Interface with type parameter
  • Constructor
  • Property
  • Method
  • Index signature
  • Class
  • Class with type parameter
  • Constructor
  • Property
  • Method
  • Accessor
  • Index signature
  • Inherited constructor
  • Inherited property
  • Inherited method
  • Inherited accessor
  • Protected property
  • Protected method
  • Protected accessor
  • Private property
  • Private method
  • Private accessor
  • Static property
  • Static method

Generated using TypeDoc