Skip to content

Commit

Permalink
feat: added OnCallUpdateModel
Browse files Browse the repository at this point in the history
- added OnCallUpdateModel that is used to handle the onCall entrypoint for all models
  • Loading branch information
dereekb committed Jun 2, 2022
1 parent 7d12d0a commit 3b60a06
Show file tree
Hide file tree
Showing 39 changed files with 397 additions and 126 deletions.
13 changes: 6 additions & 7 deletions apps/demo-api/src/app/app.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { updateProfileKey, updateGuestbookEntryKey, profileSetUsernameKey } from '@dereekb/demo-firebase';
import { NestAppPromiseGetter, nestServerInstance } from '@dereekb/firebase-server';
import { demoUpdateModel } from './function/model/update.function';
import { profileSetUsernameKey } from '@dereekb/demo-firebase';
import { NestAppPromiseGetter, nestServerInstance, UPDATE_MODEL_APP_FUNCTION_KEY } from '@dereekb/firebase-server';
import { DemoApiAppModule } from './app.module';
import { profileSetUsername, initUserOnCreate } from './function';
import { updateGuestbookEntry } from './function/guestbook';
import { updateProfile } from './function/profile/profile.update';

export const { initNestServer } = nestServerInstance({
moduleClass: DemoApiAppModule,
Expand All @@ -21,12 +20,12 @@ export function allAppFunctions(nest: NestAppPromiseGetter) {
// Events
// Auth
initUserOnCreate: initUserOnCreate(nest),
// Model
[UPDATE_MODEL_APP_FUNCTION_KEY]: demoUpdateModel(nest),
// ---
// API Calls
// Profile
[profileSetUsernameKey]: profileSetUsername(nest),
[updateProfileKey]: updateProfile(nest),
[profileSetUsernameKey]: profileSetUsername(nest)
// Guestbook
[updateGuestbookEntryKey]: updateGuestbookEntry(nest)
};
}
8 changes: 6 additions & 2 deletions apps/demo-api/src/app/function/function.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { INestApplicationContext } from '@nestjs/common';
import { DemoFirebaseContextAppContext, demoFirebaseModelServices, DemoFirestoreCollections } from '@dereekb/demo-firebase';
import { onCallWithNestApplicationFactory, onCallWithNestContextFactory, taskQueueFunctionHandlerWithNestContextFactory, cloudEventHandlerWithNestContextFactory, blockingFunctionHandlerWithNestContextFactory, onEventWithNestContextFactory, AbstractFirebaseNestContext } from '@dereekb/firebase-server';
import { DemoFirebaseContextAppContext, demoFirebaseModelServices, DemoFirebaseModelTypes, DemoFirestoreCollections } from '@dereekb/demo-firebase';
import { onCallWithNestApplicationFactory, onCallWithNestContextFactory, taskQueueFunctionHandlerWithNestContextFactory, cloudEventHandlerWithNestContextFactory, blockingFunctionHandlerWithNestContextFactory, onEventWithNestContextFactory, AbstractFirebaseNestContext, OnCallUpdateModelFunction, OnCallUpdateModelParams, OnCallUpdateModelMap } from '@dereekb/firebase-server';
import { ProfileServerActions, GuestbookServerActions, DemoApiAuthService } from '../common';

export class DemoApiNestContext extends AbstractFirebaseNestContext<DemoFirebaseContextAppContext, typeof demoFirebaseModelServices> {
Expand Down Expand Up @@ -36,3 +36,7 @@ export const onEventWithDemoNestContext = onEventWithNestContextFactory(mapDemoA
export const cloudEventWithDemoNestContext = cloudEventHandlerWithNestContextFactory(mapDemoApiNestContext);
export const blockingEventWithDemoNestContext = blockingFunctionHandlerWithNestContextFactory(mapDemoApiNestContext);
export const taskqueueEventWithDemoNestContext = taskQueueFunctionHandlerWithNestContextFactory(mapDemoApiNestContext);

// MARK: Functions
export type DemoUpdateModelfunction<I, O = void> = OnCallUpdateModelFunction<DemoApiNestContext, I, O>;
export type DemoOnCallUpdateModelMap = OnCallUpdateModelMap<DemoApiNestContext, DemoFirebaseModelTypes>;
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { updateGuestbookEntry } from './guestbookentry.update';
import { GuestbookEntry, UpdateGuestbookEntryParams } from '@dereekb/demo-firebase';
import { demoUpdateModel } from '../model/update.function';
import { GuestbookEntry, guestbookEntryIdentity, UpdateGuestbookEntryParams } from '@dereekb/demo-firebase';
import { demoGuestbookEntryContext, DemoApiFunctionContextFixture, demoApiFunctionContextFactory, demoAuthorizedUserContext, demoGuestbookContext } from '../../../test/fixture';
import { isDate, isValid } from 'date-fns';
import { describeCloudFunctionTest } from '@dereekb/firebase-server/test';

demoApiFunctionContextFactory((f: DemoApiFunctionContextFixture) => {
describeCloudFunctionTest('updateGuestbookEntry', { f, fn: updateGuestbookEntry }, (updateGuestbookEntryCloudFn) => {
describeCloudFunctionTest('updateGuestbookEntry', { f, fn: demoUpdateModel }, (updateGuestbookEntryCloudFn) => {
demoAuthorizedUserContext({ f }, (u) => {
demoGuestbookContext({ f, published: true }, (g) => {
describe('guestbook is active', () => {
Expand All @@ -26,7 +26,10 @@ demoApiFunctionContextFactory((f: DemoApiFunctionContextFixture) => {
signed
};

await u.callCloudFunction(updateGuestbookEntryCloudFn, params);
await u.callCloudFunction(updateGuestbookEntryCloudFn, {
modelType: guestbookEntryIdentity.model,
data: params
});

exists = await userGuestbookEntry.accessor.exists();
expect(exists).toBe(true);
Expand Down Expand Up @@ -61,7 +64,10 @@ demoApiFunctionContextFactory((f: DemoApiFunctionContextFixture) => {
published: true
};

await u.callCloudFunction(updateGuestbookEntryCloudFn, params);
await u.callCloudFunction(updateGuestbookEntryCloudFn, {
modelType: guestbookEntryIdentity.model,
data: params
});

exists = await userGuestbookEntry.accessor.exists();
expect(exists).toBe(true);
Expand Down
19 changes: 8 additions & 11 deletions apps/demo-api/src/app/function/guestbook/guestbookentry.update.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { UpdateGuestbookEntryParams } from '@dereekb/demo-firebase';
import { inAuthContext } from '@dereekb/firebase-server';
import { onCallWithDemoNestContext } from '../function';
import { DemoUpdateModelfunction } from '../function';
import { guestbookEntryForUser } from './guestbook.util';

export const updateGuestbookEntry = onCallWithDemoNestContext(
inAuthContext(async (nest, data: UpdateGuestbookEntryParams, context) => {
const guestbookEntryUpdateEntry = await nest.guestbookActions.updateGuestbookEntry(data);
export const updateGuestbookEntry: DemoUpdateModelfunction<UpdateGuestbookEntryParams> = async (nest, data, context) => {
const guestbookEntryUpdateEntry = await nest.guestbookActions.updateGuestbookEntry(data);

const uid = context.auth.uid;
const { guestbook: guestbookId } = guestbookEntryUpdateEntry.params;
const uid = context.auth.uid;
const { guestbook: guestbookId } = guestbookEntryUpdateEntry.params;

const guestbookEntryDocument = guestbookEntryForUser(nest, guestbookId, uid);
await guestbookEntryUpdateEntry(guestbookEntryDocument);
})
);
const guestbookEntryDocument = guestbookEntryForUser(nest, guestbookId, uid);
await guestbookEntryUpdateEntry(guestbookEntryDocument);
};
1 change: 1 addition & 0 deletions apps/demo-api/src/app/function/model/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './update.function';
11 changes: 11 additions & 0 deletions apps/demo-api/src/app/function/model/update.function.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { updateProfile } from './../profile/profile.update';
import { updateGuestbookEntry } from './../guestbook/guestbookentry.update';
import { inAuthContext, onCallUpdateModel } from '@dereekb/firebase-server';
import { DemoOnCallUpdateModelMap, onCallWithDemoNestContext } from '../function';

export const demoUpdateModelMap: DemoOnCallUpdateModelMap = {
guestbookEntry: updateGuestbookEntry,
profile: updateProfile
};

export const demoUpdateModel = onCallWithDemoNestContext(inAuthContext(onCallUpdateModel(demoUpdateModelMap)));
13 changes: 8 additions & 5 deletions apps/demo-api/src/app/function/profile/profile.function.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { updateProfile } from './profile.update';
import { demoUpdateModel } from '../model/update.function';
import { profileSetUsername } from './profile.set.username';
import { SetProfileUsernameParams, UpdateProfileParams } from '@dereekb/demo-firebase';
import { profileIdentity, SetProfileUsernameParams, UpdateProfileParams } from '@dereekb/demo-firebase';
import { DemoApiFunctionContextFixture, demoApiFunctionContextFactory, demoAuthorizedUserContext } from '../../../test/fixture';
import { describeCloudFunctionTest } from '@dereekb/firebase-server/test';

Expand Down Expand Up @@ -64,15 +64,18 @@ demoApiFunctionContextFactory((f: DemoApiFunctionContextFixture) => {
});

// describe tests for updateProfile
describeCloudFunctionTest('updateProfile', { f, fn: updateProfile }, (updateProfileCloudFn) => {
describeCloudFunctionTest('updateProfile', { f, fn: demoUpdateModel }, (updateProfileCloudFn) => {
demoAuthorizedUserContext({ f }, (u) => {
it(`should update the user's profile.`, async () => {
const bio = 'test bio';
const params: UpdateProfileParams = {
const data: UpdateProfileParams = {
bio
};

await u.callCloudFunction(updateProfileCloudFn, params);
await u.callCloudFunction(updateProfileCloudFn, {
modelType: profileIdentity.model,
data
});

const profileData = await u.instance.loadUserProfile().snapshotData();
expect(profileData?.bio).toBe(bio);
Expand Down
17 changes: 7 additions & 10 deletions apps/demo-api/src/app/function/profile/profile.update.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { ProfileDocument, UpdateProfileParams } from '@dereekb/demo-firebase';
import { inAuthContext } from '@dereekb/firebase-server';
import { onCallWithDemoNestContext } from '../function';
import { DemoUpdateModelfunction } from '../function';
import { profileForUser } from './profile.util';

export const updateProfile = onCallWithDemoNestContext(
inAuthContext(async (nest, data: UpdateProfileParams, context) => {
const updateProfile = await nest.profileActions.updateProfile(data);
export const updateProfile: DemoUpdateModelfunction<UpdateProfileParams> = async (nest, data, context) => {
const updateProfile = await nest.profileActions.updateProfile(data);

const uid = updateProfile.params.uid ?? context.auth.uid;
const profileDocument: ProfileDocument = profileForUser(nest, uid);
const uid = updateProfile.params.uid ?? context.auth.uid;
const profileDocument: ProfileDocument = profileForUser(nest, uid);

await updateProfile(profileDocument);
})
);
await updateProfile(profileDocument);
};
2 changes: 1 addition & 1 deletion apps/demo-api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ const { server, nest } = initNestServer(app);

export const api = onRequest(server);

export const { initUserOnCreate, profileSetUsername, updateProfile, updateGuestbookEntry } = allAppFunctions(nest);
export const { initUserOnCreate, profileSetUsername, updateModel } = allAppFunctions(nest);
2 changes: 2 additions & 0 deletions apps/demo-api/src/test/fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
} from '@dereekb/firebase-server/test';
import { JestBuildTestsWithContextFunction, JestTestContextFixture } from '@dereekb/util/test';
import { Module } from '@nestjs/common';
import { UserRecord } from 'firebase-admin/lib/auth/user-record';
import { WrappedFunction } from 'firebase-functions-test/lib/main';
import { DemoApiAppModule } from '../app/app.module';
import { initUserOnCreate } from '../app/function/auth/init.user.function';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class GuestbookEntryDocumentStore extends AbstractDbxFirebaseDocumentWith
switchMap((parent) =>
loadingStateFromObs(
from(
this.guestbookFunctions[updateGuestbookEntryKey]({
this.guestbookFunctions.updateGuestbookEntry({
...params,
guestbook: parent.id
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { AbstractDbxFirebaseDocumentStore } from '@dereekb/dbx-firebase';
import { UpdateProfileParams, DemoFirestoreCollections, Profile, ProfileDocument, ProfileFunctions, updateProfileKey, SetProfileUsernameParams, profileSetUsernameKey } from '@dereekb/demo-firebase';
import { UpdateProfileParams, DemoFirestoreCollections, Profile, ProfileDocument, ProfileFunctions, SetProfileUsernameParams, profileSetUsernameKey } from '@dereekb/demo-firebase';
import { LoadingState, loadingStateFromObs } from '@dereekb/rxjs';
import { from, Observable } from 'rxjs';

Expand All @@ -15,6 +15,6 @@ export class ProfileDocumentStore extends AbstractDbxFirebaseDocumentStore<Profi
}

updateProfile(params: UpdateProfileParams): Observable<LoadingState<void>> {
return loadingStateFromObs(from(this.profileFunctions[updateProfileKey](params)));
return loadingStateFromObs(from(this.profileFunctions.updateProfile(params)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,17 @@ export class UpdateGuestbookEntryParams extends GuestbookEntryParams {
published?: boolean;
}

export const updateGuestbookEntryKey = 'updateGuestbookEntry';
export const deleteGuestbookEntryKey = 'deleteGuestbookEntry';

export type GuestbookFunctionTypeMap = {
[updateGuestbookEntryKey]: [UpdateGuestbookEntryParams, void];
[deleteGuestbookEntryKey]: [GuestbookEntryParams, void];
};

export const guestbookFunctionTypeConfigMap: FirebaseFunctionTypeConfigMap<GuestbookFunctionTypeMap> = {
[updateGuestbookEntryKey]: null,
[deleteGuestbookEntryKey]: null
};

export abstract class GuestbookFunctions implements FirebaseFunctionMap<GuestbookFunctionTypeMap> {
[updateGuestbookEntryKey]: FirebaseFunctionMapFunction<GuestbookFunctionTypeMap, 'updateGuestbookEntry'>;
[deleteGuestbookEntryKey]: FirebaseFunctionMapFunction<GuestbookFunctionTypeMap, 'deleteGuestbookEntry'>;
}

Expand Down
22 changes: 11 additions & 11 deletions components/demo-firebase/src/lib/models/guestbook/guestbook.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CollectionReference, AbstractFirestoreDocument, snapshotConverterFunctions, firestoreString, firestoreDate, FirestoreCollection, UserRelatedById, DocumentReferenceRef, FirestoreContext, FirestoreCollectionWithParent, firestoreBoolean, DocumentDataWithId, AbstractFirestoreDocumentWithParent, optionalFirestoreDate, DocumentReference, FirestoreCollectionGroup, CollectionGroup } from '@dereekb/firebase';
import { CollectionReference, AbstractFirestoreDocument, snapshotConverterFunctions, firestoreString, firestoreDate, FirestoreCollection, UserRelatedById, DocumentReferenceRef, FirestoreContext, FirestoreCollectionWithParent, firestoreBoolean, DocumentDataWithId, AbstractFirestoreDocumentWithParent, optionalFirestoreDate, DocumentReference, FirestoreCollectionGroup, CollectionGroup, firestoreModelIdentity } from '@dereekb/firebase';
import { GrantedReadRole } from '@dereekb/model';
import { Maybe } from '@dereekb/util';

Expand All @@ -8,10 +8,10 @@ export interface GuestbookFirestoreCollections {
guestbookEntryCollectionGroup: GuestbookEntryFirestoreCollectionGroup;
}

export type GuestbookTypes = typeof guestbookCollectionName | typeof guestbookCollectionGuestbookEntryCollectionName;
export type GuestbookTypes = typeof guestbookIdentity | typeof guestbookEntryIdentity;

// MARK: Guestbook
export const guestbookCollectionName = 'guestbook';
export const guestbookIdentity = firestoreModelIdentity('guestbook');

export interface Guestbook {
/**
Expand Down Expand Up @@ -41,8 +41,8 @@ export type GuestbookWithId = DocumentDataWithId<Guestbook>;
export interface GuestbookRef extends DocumentReferenceRef<Guestbook> {}

export class GuestbookDocument extends AbstractFirestoreDocument<Guestbook, GuestbookDocument> {
get modelType() {
return guestbookCollectionName;
get modelIdentity() {
return guestbookIdentity;
}
}

Expand All @@ -56,7 +56,7 @@ export const guestbookConverter = snapshotConverterFunctions<Guestbook>({
});

export function guestbookCollectionReference(context: FirestoreContext): CollectionReference<Guestbook> {
return context.collection(guestbookCollectionName).withConverter<Guestbook>(guestbookConverter);
return context.collection(guestbookIdentity.collection).withConverter<Guestbook>(guestbookConverter);
}

export type GuestbookFirestoreCollection = FirestoreCollection<Guestbook, GuestbookDocument>;
Expand All @@ -71,7 +71,7 @@ export function guestbookFirestoreCollection(firestoreContext: FirestoreContext)
}

// MARK: Guestbook Entry
export const guestbookCollectionGuestbookEntryCollectionName = 'guestbookentry';
export const guestbookEntryIdentity = firestoreModelIdentity('guestbookEntry');

export interface GuestbookEntry extends UserRelatedById {
/**
Expand Down Expand Up @@ -101,8 +101,8 @@ export type GuestbookEntryRoles = 'owner' | GrantedReadRole;
export interface GuestbookEntryRef extends DocumentReferenceRef<GuestbookEntry> {}

export class GuestbookEntryDocument extends AbstractFirestoreDocumentWithParent<Guestbook, GuestbookEntry, GuestbookEntryDocument> {
get modelType() {
return guestbookCollectionGuestbookEntryCollectionName;
get modelIdentity() {
return guestbookEntryIdentity;
}
}

Expand All @@ -118,7 +118,7 @@ export const guestbookEntryConverter = snapshotConverterFunctions<GuestbookEntry

export function guestbookEntryCollectionReferenceFactory(context: FirestoreContext): (guestbook: GuestbookDocument) => CollectionReference<GuestbookEntry> {
return (guestbook: GuestbookDocument) => {
return context.subcollection(guestbook.documentRef, guestbookCollectionGuestbookEntryCollectionName).withConverter<GuestbookEntry>(guestbookEntryConverter);
return context.subcollection(guestbook.documentRef, guestbookEntryIdentity.collection).withConverter<GuestbookEntry>(guestbookEntryConverter);
};
}

Expand All @@ -140,7 +140,7 @@ export function guestbookEntryFirestoreCollectionFactory(firestoreContext: Fires
}

export function guestbookEntryCollectionReference(context: FirestoreContext): CollectionGroup<GuestbookEntry> {
return context.collectionGroup(guestbookCollectionGuestbookEntryCollectionName).withConverter<GuestbookEntry>(guestbookEntryConverter);
return context.collectionGroup(guestbookEntryIdentity.collection).withConverter<GuestbookEntry>(guestbookEntryConverter);
}

export type GuestbookEntryFirestoreCollectionGroup = FirestoreCollectionGroup<GuestbookEntry, GuestbookEntryDocument>;
Expand Down
Loading

0 comments on commit 3b60a06

Please sign in to comment.