# Generic Store

The Generic Store is the global object that holds a Model Definition. The only purpose of the Generic Store is to store Database instance so that we can use it in other places. Please refer to Database to see why we need this global object in the first place.

# Instance Constructor

# Generic Store

  • constructor( templatePath, modelDefinition, options = {} ) ⇒ GenericStore

Creates a new generic store.

const post = new GenericStore(
  '/post/*',
  postModelDefinition
);

# Generic Store Constructor Options

# templatePath

  • type: string

Work in Progress (06/02/2020)

This section is still a work in progress. It will be updated soon.

# modelDefinition

  • type: Object (ModelDefinition)

Work in Progress (06/02/2020)

This section is still a work in progress. It will be updated soon.

# options

  • type: Object

Work in Progress (06/02/2020)

This section is still a work in progress. It will be updated soon.

Option Type Description
uidMethod string See UIDMethod
defaultDeleteMode string deleteMode.SOFT or deleteMode.HARD (default), see deleteMode
additionalProps array<string> Additional properties
enableTypeValidation boolean Enable validation based on (bolt) types
autoUnsubscribe boolean Automatically unsubscribe from everything a component subscribed to? (triggered on beforeDestroy)
  • TODO: Explain enableTypeValidation
  • TODO: Explain autoUnsubscribe
const post = new GenericStore(
  '/post/*',
  postModelDefinition,
  {
    uidMethod: UIDMethod.TIMESTAMP,
    defaultDeleteMode: deleteMode.HARD,
  }
);

# Instance Properties

# name

  • name ⇒ String

Returns store name. This is automatically set based on the export name in the model config.js.

# templatePath

  • templatePath ⇒ String

Returns template path, e.g. /user/{userId}/example/*.

# modelDefinition

  • modelDefinition ⇒ ModelDefinition

Returns model definition.

# isAbstract

  • isAbstract ⇒ Boolean

Returns if the store was defined as abstract store. Abstract stores provide abstraction by allowing you to define stores, that don't write or read data from the database.

# isSuffixed

  • isSuffixed ⇒ Boolean

Returns if the store is suffixed, which means that the id is not last item in the template path.

let example1 = new GenericStore('/user/*')
let example2 = new GenericStore('/user/*/settings')

example1.isSuffixed // > false
example2.isSuffixed // > true

# isReadonly

  • isReadonly ⇒ Boolean

Returns if the store is a read-only store (all 'write methods' are removed from the Generic Store instance).

# definedProps

  • definedProps ⇒ Object<string: string>

Returns an object of defined properties.

example.with({ x: 'a', y: 'b' }).definedProps
// > { x: 'a', y: 'b' }

# additionalProps

  • additionalProps ⇒ Array<string>

Returns an array of additional path properties. Additional properties can be used to define properties that are not part of the templatePath. See constructor.

const contact = new GenericStore(
  "/user/{myUserId}/contacts/*",
  contactModelDefinition,
  { additionalProps: ['otherUserId'] }
);
// Now myUserId and otherUserId can be used as path property
example.with({ myUserId: 'a', otherUserId: 'b' }).definedProps

# uidMethod

  • uidMethod ⇒ UIDMethod

Returns the unique id method, which defined how id's for new entries are generated. See UIDMethod.

# defaultDeleteMode

  • defaultDeleteMode ⇒ DeleteMode

Returns the default delete mode. See DeleteMode.

# path

  • get path() ⇒ string

Returns a substituted path based on the template string and defined path properties. Automatically sets user Id if not defined.

# parentRef

  • get parentRef() ⇒ Reference

Returns Firebase Database Reference to collection that contains all items.

# rootRef

  • get rootRef() ⇒ Reference

Return Firebase Database Reference to root of database.

# childRef

  • childRef( id: string ) ⇒ Reference

Returns Firebase Realtime Database Reference to child with given id.

# schemaFields

  • get schemaFields() ⇒ array< field: object >

Returns all fields defined in the schema as array.

# schemaAllFields

  • get schemaAllFields() ⇒ array<string>

Returns all fields names that are defined in the schema.

# schemaRequiredFields

  • get schemaRequiredFields() ⇒ array<string>

Returns all required fields names defined in the schema.

# schemaOptionalFields

  • get schemaOptionalFields() ⇒ array<string>

Returns all optional fields names defined in the schema.

# subscriptions

  • get subscriptions() ⇒ array<Subscrition>

Returns all subscriptions that were created by this store.

# rules

  • get rules() ⇒ string

Return custom validation rules that can be used with Element UI. See: Element UI Docs.

# Instance Methods

# define

  • define( object<string:string> ) ⇒ void

Defines path properties for a store instance.

const task_session_list = new GenericStore(
  '/project/{projectId}/user/{userId}/tasks/{taskId}/*',
  TaskSessionTypeDefinition
);

task_session_list.define({
  project: 'KrZPg8N6THOisFz_T992Zg',
  userId:  'l1X8FPc7YtbftlC31frciInV3PU2'
})

// projectId and userId now always defined

# with

  • with( object<string:string> ) ⇒ GenericStore

Defines path properties and returns a new store instance which now refers to a sub path:

// template path: /project/{x}/post/{y}/comment/*
example.with({ x: 'a', y: 'b' }).add({ ... })
// A new entry is added to /project/a/post/b/comment/-Lw_jEwrxiM6d2fS0n2m

# previewPath

  • previewPath( [id: string] ) ⇒ String

Generate a path preview for a given it:

// template path: /project/{x}/post/{y}/comment/*
example.with({ x: 'a', y: 'b' }).previewPath('c')
//> /project/a/post/b/comment/c
example.with({ x: 'a', y: 'b' }).previewPath()
//> /project/a/post/b/comment/{id}

# setName

  • setName( string ) ⇒ void

Set stores name

# generateId

  • generateId() ⇒ string

Generates a new unique identifier based on the selected method in the constructor.

# reset

  • reset( level: numeric ) ⇒ void

Resets the template path to it's initial state, without substitutions.

# Instance Methods (Writing)

# add

  • add( overwrite_data <, new_id: string> <, options: object> ) ⇒ Promise<id: string>

Adds a new item to the database. Returns a promise, which will then resolve to the id of the newly created item. overwrite_data is passed to the model definition has a create function. If new_id is provided it will be used as the id for the new entry. The UIDMethod is ignored. Valid options are:

Option Type Description
directWrite boolean Don't pass overwrite_data to the create function of the model definition, but instead write the data directly to the database.
$models.example.add({ title: 'Name' })
// or
$models.example.add({ title: 'Name' }).then(id => { ... })

# update

  • update(id: string, data: object<string: any>) ⇒ Promise

Update one or many fields. First argument is the id of the entry (the * in the templatePath). Second argument is the data the should be updated. It is possible to futher nest data with '/':

// Update single fields
$models.example.update(id, { key: 'value' })
$models.user_settings.update({ 'address/zipcode': 12345 })
// Update multiple fields
$models.example.update(id, { key1: value1, key2: value2 })

# remove

  • remove(id: string <, soft_delete: DeleteMode> ) ⇒ Promise
  • remove(ids: array<string> <, soft_delete: DeleteMode> ) ⇒ Promise

Deletes one or many an entry at the data location

  • id - id the item or arrary of ids of items that should be deleted
  • soft_delete - optional: Overwrite default behaviour for delete mode
$models.example.remove(id)
$models.example.remove(id, true) // Soft delete
$models.example.remove([id1, id2, id3], true) // Delete list of entries

# reorder

  • reorder(sortidxList: object<string: string> <, options = {}>) ⇒ Promise
  • reorder(sortidxList: array<string> <, options = {}>) ⇒ Promise

Change the order of items. This is achieved through a special field called sortidx.

  • sortidxList - Batch should be an array or array of objects
$models.example.reorder([ id1, id2, ... ])
$models.example.reorder([{ id: id1, sortidx: 1 }, { id: id2 sortidx: 2 }, ...])

Passing an object as first argument is especially useful, when passing an existing collection of items.

// TODO
// ...
$models.example.reorder(updated_commitment_list)

# restore

  • restore( id ) ⇒ Promise

Restores a deleted entry at the data location (the deleted field is set to false).

$models.example.restore('-Lw_jEwrxiM6d2fS0n2m')

# copy

  • copy(id, contextA, contextB) ⇒ Promise

Copy data between nodes (same as move, but keeps original and generates new id)

  • id (string) - id of source object
  • contextA (object) - props of the source path
  • contextB (object) - props of the destination path
// copy a task from /user/A/task/234 to /user/B/task/234
$models.task.copy('234',
  { userId: 'A' },
  { userId: 'B' }
);
// copy a comment from /user/A/task/234/comment/789 to /user/B/task/234/comment/789
$models.comment.copy(789,
  { userId: 'A', taskId: 234 },
  { userId: 'B', taskId: 234 }
);

# move

  • move(id, contextA, contextB, { keepOriginal = false, keepId = true } = {}) ⇒ Promise

Move data between nodes

  • id: {string} - Id of the object that should be moved
  • contextA: {object} - props of the source path
  • contextB: {object} - props of the destination path
  • options: Options
Option Type Description
keepOriginal boolean Keep original? (copy)
keepId boolean Keep original id or generate a new id?
$models.example.move(234,
  { userId: 'A' },
  { userId: 'B' }
)
// or
$models.example.move(id,
  { userId: 'A', taskId: 234 },
  { userId: 'B', taskId: 234 },
  { keepOriginal: true, keepId: false }
)

# transaction

  • transaction( id: string, prop: string, transaction: string, value: numeric ) ⇒ Promise

Performs a transaction on the realtime database.

  • id: {string} - Id of the object that should be moved
  • prop: {string} - props of the source path
  • transaction: {string|function} - Predefined transaction are inc and dec. Alternatively a callback can be passed.
  • value: If inc or dec are used this defines by which amount a field is incremented or decremented. Default value is 1.
$models.example.transaction( <childId>, <prop>, <transaction> )
$models.example.transaction( id, 'coins', coins => coins * 2 )
$models.example.transaction( id, 'coins', 'inc', 100 )
$models.example.transaction( id, 'coins', 'inc' ) // default: increment by 1

# new

  • new() ⇒ GenericModel

Create empty model from schema (without calling create function)

# newFromTemplate

  • newFromTemplate( data: object<string:any> <, optional_data<string:any>> ) ⇒ GenericModel

Create empty model from create function

# newFromData

  • newFromData( data: object<string:any> <, make_dirty:boolean> ) ⇒ GenericModel

# empty

  • empty( data: object<string:any> <, optional_data<string:any>> ) ⇒ object<string:any>

Create empty payload from schema.create(). This method WILL only create an Object, not a GenericModel. In most cases, you want to use newFromTemplate instead

# Instance Methods (Reading)

# subscribeList

  • subscribeList( <idList: array<string>> <, option:object>) ⇒ GenericList

Work in Progress (06/02/2020)

This section is still a work in progress. It will be updated soon.

return $models.example.subscribeList();
return $models.example.subscribeList([ id1, id2, id3 ]);

# subscribeNode

  • subscribeNode( <id: string> <, option:object>) ⇒ GenericModel

Work in Progress (06/02/2020)

This section is still a work in progress. It will be updated soon.

return $models.example.subscribeNode( id );
  • noSync = Return from cache

# subscribeQuery

  • subscribeQuery( <query:QueryDefinition> <, option:object>) ⇒ GenericList
subscribeQuery(query, options = {})
Option Type Description
key string '*' or undefined
value any
limit numeric
startAt string
endAt string
this.$models.example.subscribeQuery({
  key: 'createdAt',
  startAt: 123456789,
  limit: 100
});

# fetchList

  • fetchList( <option:object> ) ⇒ GenericList
fetchList({
  noReactiveGetter = false,
  // customRef = null,
  queryParams = null,
} = {})

# fetchNode

  • fetchNode( <id:string>, <option:object> ) ⇒ GenericModel
fetchNode(id, { noReactiveGetter = false } = {})

# fetchQuery

  • fetchQuery( <query:QueryDefinition> <, option:object> ) ⇒ GenericList
fetchQuery(query, options)

# getList

  • getList( <idList:array<string>> <, option:object>) ⇒ GenericList
getList( idList, { noReactiveGetter = false } = {} )

# getNode

  • getNode( <id:string> <, option:object>) ⇒ GenericModel
getNode( id, { noReactiveGetter = false } = {} )

# getData

  • getData( <id:string> <, option:object>) ⇒ Object<string:any>

Get raw state from registry.

  • getData() -> get reference to list of data
  • getData(child_id) -> get reference to an item in the list
getData(id = null, safe = false)
let list = $models.example.getData()
let obj = $models.example.getData('234')

# exists

  • exists( <id:string> ) ⇒ boolean

Work in Progress (06/02/2020)

This section is still a work in progress. It will be updated soon.

exists(id = null)

# getRegistryState

  • getRegistryState() => object

Work in Progress (06/02/2020)

This section is still a work in progress. It will be updated soon.

# getAllSyncedPaths

  • getAllSyncedPaths() => object<string:string>

Work in Progress (06/02/2020)

This section is still a work in progress. It will be updated soon.

# Static Methods

# setDefault

  • set setDefault( key: string, value: any )

Sets default options for new stores.

GenericStore.setDefault( 'allowEmptySchema', false );

Available options are:

const defaultStoreOptions = {
  isAbstract:           false,
  uidMethod:            UIDMethod.PUSHID,
  additionalProps:      [],
  defaultDeleteMode:    DeleteMode.HARD,
  enableTypeValidation: true,
  autoUnsubscribe:      true,
  isReadonly:           false,
  allowEmptySchema:     true,
};

# defaultUserId

  • set defaultUserId( value: string )

Sets the default user Id. If set, any {uid} or {userId} will automatically get substituted with the default user Id.

GenericStore.defaultUserId = 'Qz3p2fpvTyeje5As3WDfgQtTCEK2';
  • get defaultUserId() ⇒ string

Returns the default UserId for all stores

A good time to set the user id is after the user has been authenticated:

firebase.auth().onAuthStateChanged((user) => {
  if (user) {
    // User authenticated and is signed in
    GenericStore.defaultUserId = user.uid;
  } else {
    // User was signed in and now signed out
    GenericStore.resetState();
  }
});
  • resetState() ⇒ void

Reset stores. Should be called when the user logs out, in order to remove any stored user information from the state.