diff --git a/addon/adapters/cloud-firestore-modular.ts b/addon/adapters/cloud-firestore-modular.ts index 54116ae..1a087c4 100644 --- a/addon/adapters/cloud-firestore-modular.ts +++ b/addon/adapters/cloud-firestore-modular.ts @@ -7,8 +7,8 @@ import type { Snapshot as _Snapshot } from '@ember-data/legacy-compat/legacy-net 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, + LegacyBelongsToField as _LegacyBelongsToField, + LegacyHasManyField as _LegacyHasManyField, } from '@warp-drive/core-types/schema/fields'; import type Model from 'ember-data/model'; import RSVP from 'rsvp'; @@ -48,19 +48,21 @@ export interface AdapterOption { [key: string]: unknown; } -interface Snapshot extends _Snapshot { +export interface Snapshot extends _Snapshot { adapterOptions: AdapterOption; } -interface SnapshotRecordArray extends _SnapshotRecordArray { +export interface SnapshotRecordArray extends _SnapshotRecordArray { adapterOptions: AdapterOption; } -type BelongsToRelationshipMeta = LegacyBelongsToField & { - options: { isRealtime?: boolean }; +export type LegacyBelongsToField = _LegacyBelongsToField & { + options: { + isRealtime?: boolean; + }; }; -type HasManyRelationshipMeta = LegacyHasManyField & { +export type LegacyHasManyField = _LegacyHasManyField & { key: string; options: { isRealtime?: boolean; @@ -82,9 +84,9 @@ export default class CloudFirestoreAdapter extends Adapter { return !!fastboot && fastboot.isFastBoot; } - public generateIdForRecord(_store: Store, type: unknown): string { + public generateIdForRecord(_store: Store, type: string): string { const db = getFirestore(); - const collectionName = buildCollectionName(type as string); // TODO: EmberData types incorrect + const collectionName = buildCollectionName(type); return doc(collection(db, collectionName)).id; } @@ -268,7 +270,7 @@ export default class CloudFirestoreAdapter extends Adapter { _store: Store, _snapshot: Snapshot, url: string, - relationship: BelongsToRelationshipMeta, + relationship: LegacyBelongsToField, ): Promise { return new RSVP.Promise(async (resolve, reject) => { try { @@ -307,7 +309,7 @@ export default class CloudFirestoreAdapter extends Adapter { store: Store, snapshot: Snapshot, url: string, - relationship: HasManyRelationshipMeta, + relationship: LegacyHasManyField, ): Promise { return new RSVP.Promise(async (resolve, reject) => { try { @@ -391,7 +393,7 @@ export default class CloudFirestoreAdapter extends Adapter { store: Store, snapshot: Snapshot, url: string, - relationship: HasManyRelationshipMeta, + relationship: LegacyHasManyField, ): CollectionReference | Query { const db = getFirestore(); diff --git a/tests/dummy/app/models/user.ts b/tests/dummy/app/models/user.ts index 0f56a74..35e4cfc 100644 --- a/tests/dummy/app/models/user.ts +++ b/tests/dummy/app/models/user.ts @@ -16,6 +16,9 @@ export default class UserModel extends Model { @attr('number') public declare age: number; + @attr('string') + public declare username: string; + @hasMany('group', { async: true, inverse: 'members' }) public declare groups: AsyncHasMany; diff --git a/tests/unit/adapters/cloud-firestore-modular-test.ts b/tests/unit/adapters/cloud-firestore-modular-test.ts index 9d01514..0d23d93 100644 --- a/tests/unit/adapters/cloud-firestore-modular-test.ts +++ b/tests/unit/adapters/cloud-firestore-modular-test.ts @@ -29,6 +29,8 @@ import { } from 'ember-cloud-firestore-adapter/firebase/firestore'; import type CloudFirestoreModularAdapter from 'ember-cloud-firestore-adapter/adapters/cloud-firestore-modular'; import AdapterRecordNotFoundError from 'ember-cloud-firestore-adapter/utils/custom-errors'; +import type { Snapshot } from 'ember-cloud-firestore-adapter/adapters/cloud-firestore-modular'; +import type UserModel from 'dummy/tests/dummy/app/models/user'; import resetFixtureData from '../../helpers/reset-fixture-data'; module('Unit | Adapter | cloud firestore modular', function (hooks) { @@ -62,8 +64,14 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { test('should proxy a call to updateRecord and return with the created doc', async function (assert) { // Arrange const store = this.owner.lookup('service:store'); - const modelClass = { modelName: 'user' } as ModelSchema; - const snapshot = { id: 'user_100', age: 30, username: 'user_100' }; + const modelClass = store.modelFor('user'); + const snapshot = store + .createRecord('user', { + id: 'user_100', + age: 30, + username: 'user_100', + }) + ._createSnapshot() as Snapshot; const adapter = this.owner.lookup( 'adapter:cloud-firestore-modular', ) as CloudFirestoreModularAdapter; @@ -73,16 +81,12 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { .returns(Promise.resolve({ foo: 'foo' })); // Act - const result = await adapter.createRecord( - store, - modelClass, - snapshot as any, - ); + const result = await adapter.createRecord(store, modelClass, snapshot); // Assert assert.deepEqual(result, { foo: 'foo' }); assert.ok( - updateRecordStub.calledWithExactly(store, modelClass, snapshot as any), + updateRecordStub.calledWithExactly(store, modelClass, snapshot), ); }); }); @@ -91,11 +95,13 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { test('should update record and resolve with the updated doc', async function (assert) { // Arrange const store = this.owner.lookup('service:store'); - const modelClass = { modelName: 'user' } as ModelSchema; - const snapshot = { - id: 'user_a', - age: 50, - }; + const modelClass = store.modelFor('user'); + const snapshot = store + .createRecord('user', { + id: 'user_a', + age: 50, + }) + ._createSnapshot() as Snapshot; const adapter = this.owner.lookup( 'adapter:cloud-firestore-modular', ) as CloudFirestoreModularAdapter; @@ -106,11 +112,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { }); // Act - const result = await adapter.updateRecord( - store, - modelClass, - snapshot as any, - ); + const result = await adapter.updateRecord(store, modelClass, snapshot); // Assert assert.deepEqual(result, { age: 50, username: 'user_a' }); @@ -124,7 +126,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { test('should update record in a custom collection and resolve with the updated resource', async function (assert) { // Arrange const store = this.owner.lookup('service:store'); - const modelClass = { modelName: 'user' } as ModelSchema; + const modelClass = store.modelFor('user'); const snapshot = { id: 'user_a', age: 50, @@ -158,7 +160,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { test('should update record and process additional batched writes', async function (assert) { // Arrange const store = this.owner.lookup('service:store'); - const modelClass = { modelName: 'user' } as ModelSchema; + const modelClass = store.modelFor('user'); const snapshot = { id: 'user_a', age: 50, @@ -203,14 +205,16 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { test('should delete record', async function (assert) { // Arrange const store = this.owner.lookup('service:store'); - const modelClass = { modelName: 'user' } as ModelSchema; - const snapshot = { id: 'user_a' }; + const modelClass = store.modelFor('user'); + const snapshot = store + .createRecord('user', { id: 'user_a' }) + ._createSnapshot() as Snapshot; const adapter = this.owner.lookup( 'adapter:cloud-firestore-modular', ) as CloudFirestoreModularAdapter; // Act - await adapter.deleteRecord(store, modelClass, snapshot as any); + await adapter.deleteRecord(store, modelClass, snapshot); // Assert const userA = await getDoc(doc(db, 'users/user_a')); @@ -221,7 +225,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { test('should delete record in a custom collection', async function (assert) { // Arrange const store = this.owner.lookup('service:store'); - const modelClass = { modelName: 'post' } as ModelSchema; + const modelClass = store.modelFor('post'); const snapshot = { id: 'post_b', @@ -247,7 +251,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { test('should delete record and process additional batched writes', async function (assert) { // Arrange const store = this.owner.lookup('service:store'); - const modelClass = { modelName: 'user' } as ModelSchema; + const modelClass = store.modelFor('user'); const snapshot = { id: 'user_a', adapterOptions: { @@ -282,7 +286,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { const store = this.owner.lookup('service:store'); store.normalize = sinon.stub(); (store.push as (data: EmptyResourceDocument) => null) = sinon.stub(); - const modelClass = { modelName: 'user' } as ModelSchema; + const modelClass = store.modelFor('user'); const adapter = this.owner.lookup( 'adapter:cloud-firestore-modular', ) as CloudFirestoreModularAdapter; @@ -320,9 +324,11 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { const store = this.owner.lookup('service:store'); store.normalize = sinon.stub(); (store.push as (data: EmptyResourceDocument) => null) = sinon.stub(); - const modelClass = { modelName: 'user' } as ModelSchema; + const modelClass = store.modelFor('user'); const modelId = 'user_a'; - const snapshot = {}; + const snapshot = store + .createRecord('user', {}) + ._createSnapshot() as Snapshot; const adapter = this.owner.lookup( 'adapter:cloud-firestore-modular', ) as CloudFirestoreModularAdapter; @@ -332,7 +338,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { store, modelClass, modelId, - snapshot as any, + snapshot, ); // Assert @@ -349,7 +355,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { const store = this.owner.lookup('service:store'); store.normalize = sinon.stub(); (store.push as (data: EmptyResourceDocument) => null) = sinon.stub(); - const modelClass = { modelName: 'user' } as ModelSchema; + const modelClass = store.modelFor('user'); const modelId = 'user_a'; const snapshot = { adapterOptions: { @@ -381,16 +387,18 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { const store = this.owner.lookup('service:store'); store.normalize = sinon.stub(); (store.push as (data: EmptyResourceDocument) => null) = sinon.stub(); - const modelClass = { modelName: 'user' } as ModelSchema; + const modelClass = store.modelFor('user'); const modelId = 'user_100'; - const snapshot = {}; + const snapshot = store + .createRecord('user', {}) + ._createSnapshot() as Snapshot; const adapter = this.owner.lookup( 'adapter:cloud-firestore-modular', ) as CloudFirestoreModularAdapter; try { // Act - await adapter.findRecord(store, modelClass, modelId, snapshot as any); + await adapter.findRecord(store, modelClass, modelId, snapshot); } catch (error) { // Assert assert.ok(error instanceof AdapterRecordNotFoundError); @@ -408,7 +416,9 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { const store = this.owner.lookup('service:store'); store.normalize = sinon.stub(); (store.push as (data: EmptyResourceDocument) => null) = sinon.stub(); - const snapshot = {}; + const snapshot = store + .createRecord('user', {}) + ._createSnapshot() as Snapshot; const url = 'users/user_a'; const relationship = { type: 'user', options: {} }; const adapter = this.owner.lookup( @@ -418,7 +428,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { // Act const result = await adapter.findBelongsTo( store, - snapshot as any, + snapshot, url, relationship as any, ); @@ -648,7 +658,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { test('should query for records', async function (assert) { // Arrange const store = this.owner.lookup('service:store'); - const modelClass = { modelName: 'user' } as ModelSchema; + const modelClass = store.modelFor('user'); const queryRef = { filter(reference: CollectionReference) { return query(reference, where('age', '>=', 15), limit(1)); @@ -680,7 +690,7 @@ module('Unit | Adapter | cloud firestore modular', function (hooks) { test('should query for records in a custom collection', async function (assert) { // Arrange const store = this.owner.lookup('service:store'); - const modelClass = { modelName: 'user' } as ModelSchema; + const modelClass = store.modelFor('user'); const queryRef = { buildReference(firestore: Firestore) { return collection(firestore, 'admins');