fire-entity
Advanced tools
Comparing version 0.5.0 to 0.6.0
{ | ||
"name": "fire-entity", | ||
"version": "0.5.0", | ||
"version": "0.6.0", | ||
"description": "Allows for storing and retrieving documents in a standardized format from Firestore.", | ||
"main": "./dist/index.js", | ||
"typings": "./dist/index.d.ts", | ||
"main": "./lib/index.js", | ||
"typings": "./lib/index.d.ts", | ||
"scripts": { | ||
@@ -8,0 +8,0 @@ "build": "tsc", |
@@ -0,15 +1,44 @@ | ||
/** | ||
* An interface representing all properties, which are retrieved from Firebase meta data. | ||
*/ | ||
export interface EntitySystemProps { | ||
/** | ||
* The Firebase UID of this entity. | ||
*/ | ||
id: string; | ||
/** | ||
* The name the collection containing this entity. | ||
*/ | ||
type: string; | ||
/** | ||
* The path to this entity within the database. | ||
*/ | ||
path: string; | ||
/** | ||
* The path to this entities parent within the database. | ||
*/ | ||
parentPath?: string; | ||
} | ||
/** | ||
* An interface, which adds properties set by this library to the Firebase meta data. | ||
*/ | ||
export interface Entity extends EntitySystemProps { | ||
/** | ||
* When this entity was last updated. | ||
*/ | ||
lastUpdated: Date; | ||
/** | ||
* The UID of the Firebase user, who originally inserted this document. | ||
*/ | ||
owner?: string; | ||
} | ||
/** | ||
* An interface representing the necessary information for inserting an entity usign this library. | ||
*/ | ||
export interface EntityInsert { | ||
type: string; | ||
parentPath?: string; | ||
owner?: string; | ||
} | ||
@@ -21,3 +50,15 @@ | ||
'path', | ||
'parentPath' | ||
]; | ||
'parentPath', | ||
'owner', | ||
]; | ||
export function prepareTransaction(entityData: {[key: string]: any}): {} { | ||
entityData = { | ||
...entityData, | ||
lastUpdated: new Date(), | ||
}; | ||
for (const attr of EntityAttributes) { | ||
delete entityData[attr]; | ||
} | ||
return entityData; | ||
} |
@@ -1,2 +0,2 @@ | ||
export * from './entity'; | ||
export * from './store'; | ||
export {Entity, EntityInsert} from './entity'; | ||
export * from './firestore'; |
151
src/store.ts
@@ -1,106 +0,67 @@ | ||
import * as firebase from 'firebase/app'; | ||
import 'firebase/firestore'; | ||
import {Observable, Subject} from 'rxjs'; | ||
import {Observable} from 'rxjs'; | ||
import {Entity, EntityInsert, EntityAttributes} from './entity'; | ||
import {convertFirestoreTimestamps} from './util'; | ||
import {EntityInsert, Entity} from './entity'; | ||
import {QueryParam} from './firestore/query'; | ||
export type CollectionSelector = (path: string) => firebase.firestore.CollectionReference; | ||
export type DocumentSelector = (path: string) => firebase.firestore.DocumentReference; | ||
export interface QueryParam { | ||
prop: string; | ||
op: firebase.firestore.WhereFilterOp; | ||
val: any; | ||
/** | ||
* Configuration options for entity stores. | ||
*/ | ||
export interface EntityStoreConfig { | ||
/** | ||
* If set to true, entity stores will set the owner field of inserted entities to the | ||
* user UID of the currently signed in user. | ||
*/ | ||
setOwner: boolean; | ||
} | ||
function extractEntity<T extends Entity>(snap: firebase.firestore.QueryDocumentSnapshot): T { | ||
const data = snap.data() as T; | ||
/** | ||
* Generic interface for entity storage backends. | ||
* Implemented by {@link EntityFireStore}. | ||
*/ | ||
export interface EntityStore { | ||
/** | ||
* Retrieves all entities from the provided path. | ||
* @param path Path to the queried collection. | ||
*/ | ||
selectAll<T extends Entity>(path: string): Promise<T[]>; | ||
const id = snap.id; | ||
const type = snap.ref.parent.id; | ||
const path = snap.ref.path; | ||
const parentPath = snap.ref.parent.parent ? snap.ref.parent.parent.path : undefined; | ||
/** | ||
* Retrieves all entities from the provided path, which match all given filters. | ||
* @param path Path to the queried collection. | ||
* @param filters Filters to apply to the queried collection. | ||
*/ | ||
selectWhere<T extends Entity>(path: string, filters: QueryParam[]): Promise<T[]>; | ||
convertFirestoreTimestamps(data); | ||
/** | ||
* Listens for changes at the provided path and returns all entities when a change occurs. | ||
* @param path Path to the queried collection. | ||
*/ | ||
listenAll<T extends Entity>(path: string): Observable<T[]>; | ||
return {...data, id, type, path, parentPath}; | ||
} | ||
/** | ||
* Listens for changes at the provided path and returns all matching entities when a change occurs. | ||
* @param path Path to the queried collection. | ||
* @param filters Filters to apply to the queried collection. | ||
*/ | ||
listenWhere<T extends Entity>(path: string, filters: QueryParam[]): Observable<T[]>; | ||
function getCollectionPath<T extends Entity, E extends EntityInsert>(entity: T | E): string { | ||
return !entity.parentPath ? entity.type : `${entity.parentPath}/${entity.type}`; | ||
} | ||
/** | ||
* Inserts the given entity into the store. | ||
* @param insert The entity to be inserted. | ||
*/ | ||
insert<T extends EntityInsert>(insert: T): Promise<void>; | ||
function buildQuery(collectionRef: firebase.firestore.CollectionReference, filters: QueryParam[]): firebase.firestore.Query { | ||
let query: firebase.firestore.Query = collectionRef as any; | ||
for (const f of filters) { | ||
query = query.where(f.prop, f.op, f.val); | ||
} | ||
return query; | ||
} | ||
/** | ||
* Deletes the given entity from the store. | ||
* An entity with the same ID must exists inside the store. | ||
* @param entity The entity to be deleted. | ||
*/ | ||
delete<T extends Entity>(entity: T): Promise<void>; | ||
function createSnapshotObservable<T extends Entity>(coll: firebase.firestore.CollectionReference | firebase.firestore.Query): Observable<T[]> { | ||
const ret = new Subject<T[]>(); | ||
coll.onSnapshot( | ||
(snapshot: firebase.firestore.QuerySnapshot) => { | ||
const entities = snapshot.docs.map(doc => extractEntity<T>(doc)); | ||
ret.next(entities); | ||
}, | ||
(error: Error) => ret.error(error), | ||
() => ret.complete(), | ||
); | ||
return ret; | ||
} | ||
function prepareDocumentData(data: {[key: string]: any}): {} { | ||
data = { | ||
...data, | ||
lastUpdated: new Date(), | ||
}; | ||
for (const attr of EntityAttributes) { | ||
delete data[attr]; | ||
} | ||
return data; | ||
} | ||
export abstract class EntityStore { | ||
constructor(private collection: CollectionSelector, private doc: DocumentSelector) {} | ||
public async insert<T extends EntityInsert>(insert: T): Promise<void> { | ||
const {type, parentPath, ...data} = insert; | ||
const collectionPath = getCollectionPath(insert); | ||
const preparedData = prepareDocumentData(data); | ||
await this.collection(collectionPath).add(preparedData); | ||
return undefined; | ||
} | ||
public async selectAll<T extends Entity>(path: string): Promise<T[]> { | ||
const snap = await this.collection(path).get(); | ||
return snap.docs.map(doc => extractEntity<T>(doc)); | ||
} | ||
public async selectWhere<T extends Entity>(path: string, filters: QueryParam[]): Promise<T[]> { | ||
let query = buildQuery(this.collection(path), filters); | ||
const snap = await query.get(); | ||
return snap.docs.map(doc => extractEntity<T>(doc)); | ||
} | ||
public listenAll<T extends Entity>(path: string): Observable<T[]> { | ||
return createSnapshotObservable(this.collection(path)); | ||
} | ||
public listenWhere<T extends Entity>(path: string, filters: QueryParam[]): Observable<T[]> { | ||
let query = buildQuery(this.collection(path), filters); | ||
return createSnapshotObservable(query); | ||
} | ||
public delete<T extends Entity>(entity: T): Promise<void> { | ||
return this.doc(entity.path).delete(); | ||
} | ||
public update<T extends Entity>(entity: T): Promise<void> { | ||
const path = entity.path; | ||
const data = prepareDocumentData(entity); | ||
return this.doc(path).update(data); | ||
} | ||
/** | ||
* Updates the given entity in the store. | ||
* An entity with the same ID must exists inside the store. | ||
* @param entity The entity to be updated. | ||
*/ | ||
update<T extends Entity>(entity: T): Promise<void>; | ||
} |
@@ -7,3 +7,3 @@ { | ||
"declaration": true, | ||
"outDir": "dist", | ||
"outDir": "lib", | ||
"strict": true, | ||
@@ -10,0 +10,0 @@ "removeComments": true, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
24033
32
436
1
88
1