data_source
v4.0.8
Published
Unified JS Data Source
Downloads
123
Readme
DataSource
This is a module for interfacing with data coming from any source in uniform way. A data source is a client side key-value store that exposes promised based async methods for working with data.
DataSource uses the Adapter pattern. By default the adapter uses the data sources in-memory key-value store as the source of truth and implements all of its methods(detailed below) with sensible defaults. If you need a custom implementation for things like getting data from a server via http or websockets or using localStorage, you would override the corresponding method in the adapter instance you provide to support reading / writing data to your custom location or dealing with custom queries or actions.
A simple example:
var userDataSource = new DataSource<User>(new UserAdapter());
userDataSource.setRecord('recordId', new User()).then((user : User) => {
user.someMethod();
return user;
}).then((user : User) => {
//do stuff
});
userDataSource.getRecord('recordId').then((user : User) => {
//do stuff
});
userDataSource.addRecord('recordId2', someUser);
Data Source API
Adapter Source Interface
Adapters don't have direct references to the data source they work with. Instead they use an instance a DataSourceInterface
.
This interface provides a synchronous api into the data source.
DataSourceInterface
get(id : string) : T
get a record by idadd(record : T) : T
add a recordset(id : string, record : T) : T
update / change / remove (if record is null)remove(id : string) : T
remoe a recordclear() : void
nuke the data source record storeid(record : T) : string
get an id for a given recordrecords() : Array<T>
get all the local records in the data source in an array. This is internally cached is relatively performant so calling this many times is fine.
DataSource Methods
on(eventName : string, callback : (record : T) => void) : void
DataSource is an event emitter that will emit the following eventsrecordAdded
--(record : T, id : string) => void
-- when new records are addedrecordChanged
--(record : T, oldRecord : T, id : string) => void
when existing records change (viasetRecord
, not when properties change)recordRemoved
--(record : T, id : string) => void
when records are removed
loadRecords() : Array<T>
-- Loads all records form the backing storeloadRecordsOnce() : Array<T>
IfloadRecords()
has not been called on the data source, it will callloadRecords()
on the adapter and return the results otherwise it will just return what is stored locally and will not execute the adapter'sloadRecords()
a second time. A use case for this method might be to load a bunch of records from the server, but be sure to only ever do it once since loading things from a server is slow.addRecord(record : T) : Promise<T>
Adds a record to the data source, returns a promise that resolves the record that was addedgetRecord(id : string) : Promise<T>
Gets a record and returns a promise resolving that record or null if no record was found.setRecord(id : string, record : T) : Promise<T>
writes an update into the data source. if no record exists for the given id, the record will be added. if a record is prexisting for that id, it will be updated with the new record value. ifrecord === null
that record will be removed.updateRecord(record : T) : Promise<T>
the same assetRecord
but computes the id of the record by callingadapter.getRecordId(record)
removeRecord(recordOrId : T|string) : Promise<T>
Takes a record to remove or an Id of a record to remove and removes it from the data source. Returns a promise that resolves the removed record or null if no record was removed.addRecordCollection(records : Array<T>|IRecordStore<T>) : Promise<T[]>
Adds every record in therecords
argument to the data source.getRecordCollection(ids : Array<string>) : Promise<T[]>
Gets all records in the data source that have an id in theids
argument.removeRecordCollection(records : Array<T>|IRecordStore<T>) : Promise<T[]>
Removes allrecords
from the data sourceupdateRecordCollection(records : Array<T>|IRecordStore<T>) : Promise<T[]>
Updates each record in therecords
argumentgetRecordPage(pageSize : number, pageNumber : number, optionalArgs : ...args) : Promise<T[]>
this is used for paging, you can supply anything you want in theoptionalArgs
parameter and that will be passed on to the adaptergetRecordCount() : Promise<number>
returns the total number of records in the data source, this is used in conjuction withgetRecordPage
to accurately show how many pages of records there might be on your server / whatever you are pagingquery(...args : any[]) : Promise<any>
This is a way for you to define functionality outside of the normal data source methods, for instance finding all users with the name 'Matt' is not something any of the other data source methods know how to handle. It is up to you to define the behavior of this function in your adapter.action(...args : any[]) : Promise<any>
Identical toquery
but sometimes makes more semantic senseclearLocalRecordStore() : void
Clears the entire local record set and emitsrecordRemoved
events for each recordcreateManagedCollection(options? : ICollectionOptions) : Collection
creates and manages a collection. Whenever a record is added / updated / removed from the data source that change will be automatically reflected in the collection that is returned. If anoptions
parameter is supplied it will be passed through to the collection.manageCollection(collection : Collection) : Collection
equivalent tocreateManagedCollection
but you supply the collection to be managed instead of DataSource creating one for youawaitRecord(id : string) : Promise<T>
Resolves when a record withid
is added to the data source, or immediately if it is already there. This will not issue a call togetRecord
for you.awaitRecords(ids : Array<string>) : Promise<T[]>
The same asawaitRecord
but will resolve when allids
are present in the data source or immediately if they are all there already.observeRecord(id : string, callback : (record : T) => void) : CancelFunction
this is a more performant way to listen for changes on a specific record. This is far preferable to listening torecordChanged
and checking if the id that changed is the id you are watchingobserveRecords(ids : Array<string>, callback : (record : T) => void) : CancelFunction
Same asobserveRecord
but for many records at once. The callback is invoked for each record change.reset() : void
resets the data source, removing all records and observers and event listeners. UnlikeclearLocalRecordStore()
this will not emitrecordRemoved
events
Adapter Methods To Override
initialize()
This function runs when the Adapter'sconfig
promise has resolved.loadRecords(localRecords : IRecordStore<T>)
By default returns all records stored locally in the DataSource. ThelocalRecords
parameter is an object keyed by Id that contains all the records currently in the data source.addRecord(id : string, localRecord : T) : T|Promise<T>
By default just adds the record to the data sourceremoveRecord(record : T, id : string) : T|Promise<T>
By default removed the record from the data sourcegetRecord(id : string, localRecord : T) : T|Promise<T>
Gets a record, by default returnslocalRecord
setRecord(id : string, newRecord : T, localRecord :T) : T|Promise<T>
updates a record, returnsnewRecord
by defaultaddRecordCollection(records : Array<T>|IRecordStore<T>) : T[]|Promise<T[]>
callsadapter.addRecord()
for each record in arraygetRecordCollection(ids : Array<string>) : T[]|Promise<T[]>
callsadapter.getRecord(id)
for each record in arrayremoveRecordCollection(collection : T[]|IRecordStore<T>) : T[]|Promise<T[]>
callsadapter.removeRecord()
for each record in arrayupdateRecordCollection(collection : T[]|IRecordStore<T>) : T[]|Promise<T[]>
callsadapter.setRecord()
from each record in arraygetRecordPage(pageSize : number, pageNumber : number, optionalArgs : any) : T[]|Promise<T[]>
by default returns a subsection of the local data source recordsgetRecordCount() : number|Promise<number>
getRecordId() : string
recordsEqual(a : T, b : T) : boolean
action(actionName : string, ...args : any[]) : any
query(queryName : string, ...args : any[]) : any
Collection
Collections are 'smart' arrays of things (doesnt have to be object types). They are sortable, filterable, pageable and groupable.
Interfaces
IRecordStore<T>
{[id : string, record :T }
Note that because of the adapter pattern use METHODS DEFINED ON THE DATA SOURCE ARE NOT THE SAME AS THE METHODS DEFINED IN THE ADAPTER.
Adapter methods often have different signatures than the correspondingly named method on the DataSource itself. For example,
when calling dataSource.loadRecords()
no parameters are expected, but when the data source invokes the adapter's version
of loadRecords
, it also passes along a copy of the local store.
Defining a method on the adapter DOES NOT expose it to the data source.