refdata-storage v6.2.1
Storage
Dynamic entity storage
Features
- Versioning
- Avro-style schema enforcement
- Observable change events
- Configurable adapters
Installation
npm install refdata-storageConfiguration
There are several ways a storage instance can be constructed. It is also possible to have multiple storage instances simultaneously within your application. Here are the main configuration setups with their respective use-cases.
Fully static setup
The storage instance always boots up from exactly the same externally controlled state. Ideal for test automation or as a source of static read-only reference data.
import createStorage from '@navarik/storage'
const storage = createStorage({
schema: [ ...list of pre-defined schemas... ],
data: [ ...list of pre-defined data objects (including their metadata portions)... ]
})
storage.init()Note, that with this setup it is still possible to create schemas or entities, however these changes will not survive the application restart since the storage will be re-initialized from the static configuration each time storage.init() is called.
Static schema setup
Empty storage instance with pre-defined schemas. Entity persistance guarantee depends entirely on the provided entity changelog adapter. This setup most closely resembles classical RDBMS in the fact that schema changes would require code re-deployment and data changes would not.
import createStorage from '@navarik/storage'
const storage = createStorage({
schema: [ ...list of pre-defined schemas... ],
log: {
schema: 'default',
entity: myChangelogAdapterInstance
}
})
storage.init()Fully dynamic setup
Both, entity and schema persistance guarantee depends entirely on the given changelog adapter. The instance starts completely empty. Useful for multi-tenant services or user-controlled structured data storages.
import createStorage from '@navarik/storage'
const storage = createStorage({
log: myChangelogAdapterInstance
})
storage.init()Usage
import createStorage from '@navarik/storage'
const storage = createStorage()
storage.init()
async function main() {
const schema = await storage.createSchema({
name: 'test',
fields: [
{ name: 'name', type: 'string' },
{ name: 'says', type: 'string' }
]
})
const entity = await storage.create('test', { name: 'doge', says: 'wow!' })
console.log(entity)
}
main()API
Factory & Configuration
Storage library's only export is factory function that is designed to generate storage instances based on provided configuration. Here are the configuratino options:
schema: Array<Object> - provide static schemata in a form of an array of Avro-compatible schema definition JS objects.
entity: Array<Object> - provide static entities in a form of an array of JS objects.
log: 'default'|ChangeLogAdapter - global override for the change-log adapter
log.schema: 'default'|ChangeLogAdapter - override for the schema change-log adapter
log.entity: 'default'|ChangeLogAdapter - override for the entity change-log adapter
index: 'default'|SearchIndexAdapter - global override for the local state's search index.schema: 'default'|SearchIndexAdapter - override for the schema search index adapter
index.entity: 'default'|SearchIndexAdapter - override for the entity search index adapter
Instance API
init(): Promise<void> - initialize storage instance, read change-logs, re-generate search index. Usually this method is called once before any other API functions could be accessed.
isConnected(): boolean - returns true if all the adapters are connected and operational, false otherwize. Default in-memory adapters are always connected.
Schema management
getSchema: (name: string, [version: integer]): Promise<Schema> - returns schema for a given type name, undefined if no schema is found. Returns a specific version of the schema if version argument is provided, uses the latest version by default.
findSchema(filter: Object, [options: Object]): Promise<Array<Schema>> - looks for schemas that match provided filter. Supported search options: limit, offset. Returns empty array if there is no schemas matching the filter.
schemaNames(): Array<string> - returns a list of all registered entity types.
createSchema(body: Object): Promise<Schema> - registers new schema
updateSchema(name: string, body: Object): Promise<Schema> - updates existing schema
Entity management
get(id: string, [version: number, options = {}]): Promise<Entity> - fetches a single entity by its unique ID. Fetches a particular version if version argument is provided, otherwise uses the latest known version. Supported options: view ('brief' or 'canonical').
find(filter: Object, options: Object): Promise<Array<Entity>> - search for entities that match given filter. Supported search options: limit, offset, view ('brief' or 'canonical').
findContent(text: string, options: Object): Promise<Array<Entity>> - search for all the entities that have at least one field where the value includes given text. Supported options: view ('brief' or 'canonical').
count(filter: Object): Promise<number> - count the number of entities satisfying the given filter.
create(type: string, body: Object, options: Object): Promise<Entity> - create a new entity of a given type. Supported options: view ('brief' or 'canonical').
create(type: string, body: Array<Object>, options: Object): Promise<Array<Entity>> - bulk-create new entities of a given type. Supported options: view ('brief' or 'canonical').
update(id: string, body: Object, options: Object): Promise<Entity> - update existing entity. Supported options: view ('brief' or 'canonical').
validate(type: string, body: Object): string - validates given object against the schema of a given type and returns a string of discovered errors. Returns empty string.
isValid(type: string, body: Object): boolean - validates given object against the schema of a given type and returnd 'true' if the object is valid and 'false' otherwise.
observe(handler: (Entity) => void, [filter: Object]): void - give the system a callback to envoke on each entity change event. Optionally sets the filter allowing to trigger the callback only for matching entities.