Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use ember source types #327

Merged
merged 14 commits into from
Dec 31, 2024
Merged
75 changes: 37 additions & 38 deletions addon/adapters/cloud-firestore-modular.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { getOwner } from '@ember/application';
import { getOwner } from '@ember/owner';
import { service } from '@ember/service';
import Adapter from '@ember-data/adapter';
import type DS from 'ember-data';
import { type ModelSchema } from 'ember-data';
import type ModelRegistry from 'ember-data/types/registries/model';
import type { ModelSchema } from '@ember-data/store/types';
import type { AdapterPayload } from '@ember-data/legacy-compat';
import type { Snapshot as _Snapshot } from '@ember-data/legacy-compat/legacy-network-handler/snapshot';
import type { SnapshotRecordArray as _SnapshotRecordArray } from '@ember-data/legacy-compat/-private';
import type { Collection } from '@ember-data/store/-private/record-arrays/identifier-array';
import type {
LegacyBelongsToField,
LegacyHasManyField,
} from '@warp-drive/core-types/schema/fields';
import type Model from 'ember-data/model';
import RSVP from 'rsvp';
import type Store from '@ember-data/store';

Expand Down Expand Up @@ -41,30 +48,27 @@ export interface AdapterOption {
[key: string]: unknown;
}

interface Snapshot extends DS.Snapshot {
interface Snapshot extends _Snapshot {
adapterOptions: AdapterOption;
}

interface SnapshotRecordArray
extends DS.SnapshotRecordArray<keyof ModelRegistry> {
interface SnapshotRecordArray extends _SnapshotRecordArray {
adapterOptions: AdapterOption;
}

interface BelongsToRelationshipMeta {
type: keyof ModelRegistry;
type BelongsToRelationshipMeta = LegacyBelongsToField & {
options: { isRealtime?: boolean };
}
};

interface HasManyRelationshipMeta {
type HasManyRelationshipMeta = LegacyHasManyField & {
key: string;
type: string;
options: {
isRealtime?: boolean;

buildReference?(db: Firestore, record: unknown): CollectionReference;
filter?(db: CollectionReference | Query, record: unknown): Query;
};
}
};

export default class CloudFirestoreAdapter extends Adapter {
@service('-firestore-data-manager')
Expand All @@ -73,9 +77,9 @@ export default class CloudFirestoreAdapter extends Adapter {
protected referenceKeyName = 'referenceTo';

protected get isFastBoot(): boolean {
const fastboot = getOwner(this).lookup('service:fastboot');
const fastboot = getOwner(this)?.lookup('service:fastboot');

return fastboot && fastboot.isFastBoot;
return !!fastboot && fastboot.isFastBoot;
}

public generateIdForRecord(_store: Store, type: unknown): string {
Expand All @@ -89,21 +93,21 @@ export default class CloudFirestoreAdapter extends Adapter {
store: Store,
type: ModelSchema,
snapshot: Snapshot,
): RSVP.Promise<unknown> {
): Promise<AdapterPayload> {
return this.updateRecord(store, type, snapshot);
}

public updateRecord(
_store: Store,
type: ModelSchema,
snapshot: Snapshot,
): RSVP.Promise<unknown> {
): Promise<AdapterPayload> {
return new RSVP.Promise((resolve, reject) => {
const collectionRef = this.buildCollectionRef(
type.modelName,
snapshot.adapterOptions,
);
const docRef = doc(collectionRef, snapshot.id);
const docRef = doc(collectionRef, snapshot.id!);
const batch = this.buildWriteBatch(docRef, snapshot);

batch
Expand Down Expand Up @@ -131,14 +135,14 @@ export default class CloudFirestoreAdapter extends Adapter {
_store: Store,
type: ModelSchema,
snapshot: Snapshot,
): RSVP.Promise<unknown> {
): Promise<AdapterPayload> {
return new RSVP.Promise((resolve, reject) => {
const db = getFirestore();
const collectionRef = this.buildCollectionRef(
type.modelName,
snapshot.adapterOptions,
);
const docRef = doc(collectionRef, snapshot.id);
const docRef = doc(collectionRef, snapshot.id!);
const batch = writeBatch(db);

batch.delete(docRef);
Expand All @@ -160,7 +164,7 @@ export default class CloudFirestoreAdapter extends Adapter {
type: ModelSchema,
id: string,
snapshot: Snapshot,
): RSVP.Promise<unknown> {
): Promise<AdapterPayload> {
return new RSVP.Promise(async (resolve, reject) => {
try {
const colRef = this.buildCollectionRef(
Expand Down Expand Up @@ -194,9 +198,9 @@ export default class CloudFirestoreAdapter extends Adapter {
public findAll(
_store: Store,
type: ModelSchema,
_sinceToken: string,
snapshotRecordArray?: SnapshotRecordArray,
): RSVP.Promise<unknown> {
_sinceToken: null,
snapshotRecordArray: SnapshotRecordArray,
): Promise<AdapterPayload> {
return new RSVP.Promise(async (resolve, reject) => {
try {
const db = getFirestore();
Expand All @@ -223,12 +227,13 @@ export default class CloudFirestoreAdapter extends Adapter {
});
}

// @ts-expect-error ember data types 3 arg
public query(
_store: Store,
type: ModelSchema,
queryOption: AdapterOption,
recordArray: DS.AdapterPopulatedRecordArray<unknown>,
): RSVP.Promise<unknown> {
recordArray: Collection,
): Promise<AdapterPayload> {
return new RSVP.Promise(async (resolve, reject) => {
try {
const colRef = this.buildCollectionRef(type.modelName, queryOption);
Expand Down Expand Up @@ -264,7 +269,7 @@ export default class CloudFirestoreAdapter extends Adapter {
_snapshot: Snapshot,
url: string,
relationship: BelongsToRelationshipMeta,
): RSVP.Promise<unknown> {
): Promise<AdapterPayload> {
return new RSVP.Promise(async (resolve, reject) => {
try {
const urlNodes = url.split('/');
Expand Down Expand Up @@ -303,7 +308,7 @@ export default class CloudFirestoreAdapter extends Adapter {
snapshot: Snapshot,
url: string,
relationship: HasManyRelationshipMeta,
): RSVP.Promise<unknown> {
): Promise<AdapterPayload> {
return new RSVP.Promise(async (resolve, reject) => {
try {
const queryRef = this.buildHasManyCollectionRef(
Expand All @@ -315,7 +320,7 @@ export default class CloudFirestoreAdapter extends Adapter {
const config = {
queryRef,
modelName: snapshot.modelName,
id: snapshot.id,
id: snapshot.id!,
field: relationship.key,
referenceKeyName: this.referenceKeyName,
};
Expand All @@ -339,7 +344,7 @@ export default class CloudFirestoreAdapter extends Adapter {
}

protected buildCollectionRef(
modelName: keyof ModelRegistry,
modelName: string,
adapterOptions?: AdapterOption,
): CollectionReference {
const db = getFirestore();
Expand Down Expand Up @@ -402,7 +407,7 @@ export default class CloudFirestoreAdapter extends Adapter {
);
}

const modelClass = store.modelFor(snapshot.modelName);
const modelClass = store.modelFor(snapshot.modelName) as typeof Model;
const cardinality = modelClass.determineRelationshipType(
relationship,
store,
Expand All @@ -420,7 +425,7 @@ export default class CloudFirestoreAdapter extends Adapter {
const collectionRef = collection(db, url);
const queryRef = query(
collectionRef,
where(inverse.name, '==', snapshotDocRef),
where(inverse?.name as string, '==', snapshotDocRef),
);

return (
Expand All @@ -436,9 +441,3 @@ export default class CloudFirestoreAdapter extends Adapter {
);
}
}

declare module 'ember-data/types/registries/adapter' {
export default interface AdapterRegistry {
'cloud-firestore-modular': CloudFirestoreAdapter;
}
}
28 changes: 9 additions & 19 deletions addon/serializers/cloud-firestore-modular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
*/

import { isNone } from '@ember/utils';
import type DS from 'ember-data';
import { type ModelSchema } from 'ember-data';
import type Model from '@ember-data/model';
import type { Snapshot } from '@ember-data/legacy-compat/legacy-network-handler/snapshot';
import JSONSerializer from '@ember-data/serializer/json';
import type Store from '@ember-data/store';

import type {
CollectionReference,
Expand Down Expand Up @@ -39,19 +38,13 @@ interface RelationshipDefinition {
};
}

type ModelClass = ModelSchema & {
determineRelationshipType(
descriptor: { kind: string; type: string },
store: Store,
): string;
};

export default class CloudFirestoreSerializer extends JSONSerializer {
public extractRelationship(
relationshipModelName: string,
relationshipHash: DocumentReference,
): { id: string; type: string } | Record<string, unknown> {
if (isNone(relationshipHash)) {
// @ts-expect-error ember data types aren't exporting serializer types correctly
return super.extractRelationship(relationshipModelName, relationshipHash);
}

Expand All @@ -62,7 +55,7 @@ export default class CloudFirestoreSerializer extends JSONSerializer {
}

public extractRelationships(
modelClass: ModelClass,
modelClass: typeof Model,
resourceHash: ResourceHash,
): Record<string, unknown> {
const newResourceHash = { ...resourceHash };
Expand Down Expand Up @@ -99,14 +92,16 @@ export default class CloudFirestoreSerializer extends JSONSerializer {

newResourceHash.links = links;

// @ts-expect-error ember data types aren't exporting serializer types correctly
return super.extractRelationships(modelClass, newResourceHash);
}

public serializeBelongsTo(
snapshot: DS.Snapshot,
snapshot: Snapshot,
json: { [key: string]: string | null | DocumentReference },
relationship: RelationshipDefinition,
): void {
// @ts-expect-error ember data types aren't exporting serializer types correctly
super.serializeBelongsTo(snapshot, json, relationship);

if (json[relationship.key]) {
Expand All @@ -128,10 +123,11 @@ export default class CloudFirestoreSerializer extends JSONSerializer {
}

public serialize(
snapshot: DS.Snapshot,
snapshot: Snapshot,
options: Record<string, unknown>,
): Record<string, unknown> {
const json: { [key: string]: unknown } = {
// @ts-expect-error ember data types aren't exporting serializer types correctly
...super.serialize(snapshot, options),
};

Expand All @@ -144,9 +140,3 @@ export default class CloudFirestoreSerializer extends JSONSerializer {
return json;
}
}

declare module 'ember-data/types/registries/serializer' {
export default interface SerializerRegistry {
'cloud-firestore-modular': CloudFirestoreSerializer;
}
}
Loading
Loading