Skip to content

Commit

Permalink
Implement onRemoved and onAdded callbacks to the Model class.
Browse files Browse the repository at this point in the history
  • Loading branch information
ivandotv committed Jul 1, 2022
1 parent 368b8d3 commit 515ec40
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/silver-dryers-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fuerte/core': minor
---

Add `onRemoved` and `onAdded` callbacks to the `Model` class.
27 changes: 24 additions & 3 deletions packages/core/src/__tests__/__fixtures__/TestModel.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { makeObservable, observable } from 'mobx'
import { Collection } from '../../collection/Collection'
import { Model } from '../../model/Model'
import {
ModelDeleteErrorCallback,
ModelDeleteStartCallback,
ModelDeleteSuccessCallback,
SaveConfig,
SaveResult,
TransportSaveConfig,
TransportSaveResponse
} from '../../types'
import type { TestCollection } from './TestCollection'
import { TestCollection } from './TestCollection'
import { TestTransport } from './TestTransport'

export type TestModelData = {
Expand All @@ -17,8 +19,8 @@ export type TestModelData = {
id?: string
}

export class TestModel extends Model {
static identityKey = 'id'
export class TestModel extends Model<TestCollection> {
static override identityKey = 'id'

foo: string

Expand Down Expand Up @@ -51,6 +53,8 @@ export class TestModel extends Model {
}
}

protected override onRemoved(collection: TestCollection): void {}

override onSaveSuccess(data: {
response: TransportSaveResponse<TestTransport>
config: SaveConfig
Expand Down Expand Up @@ -93,3 +97,20 @@ export class TestModel extends Model {
super.onDestroy()
}
}

// const model = new TestModel()

// // model.collection.load()
// const result = model
// .save({
// local: true
// })
// .then((result) => result.response?.data.id)

// const coll = new TestCollection()

// coll.save(model)

// type ExtractTransport<P> = P extends Collection<any, any, infer T> ? T : never

// type AA = ExtractTransport<TestCollection>
4 changes: 2 additions & 2 deletions packages/core/src/__tests__/__fixtures__/TestTransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export class TestTransport implements Transport<TestModel> {
})
}

save(_model: TestModel) {
save(_model: TestModel, config: any) {
return Promise.resolve({ data: { id: nanoid() } })
}

delete(_model: TestModel): Promise<{ data: any }> {
delete(_model: TestModel, config: any): Promise<{ data: any }> {
return Promise.resolve({ data: undefined })
}

Expand Down
16 changes: 13 additions & 3 deletions packages/core/src/__tests__/collection-add.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,18 @@ describe('Collection - add #add #collection', () => {
expect(result).toEqual(models)
})

test('model "onAdded" callback is called', () => {
const collection = fixtures.collection()
const model = fixtures.model({ id: '1' })

// @ts-expect-error - internal callback test
const onAddedSpy = jest.spyOn(model, 'onAdded')
collection.add(model)

expect(onAddedSpy).toHaveBeenCalledTimes(1)
expect(onAddedSpy).toHaveBeenCalledWith(collection)
})

test('Retrieve the added model', async () => {
const transport = fixtures.transport()
const collection = fixtures.collection(fixtures.factory(), transport)
Expand All @@ -172,7 +184,7 @@ describe('Collection - add #add #collection', () => {
expect(found).toBe(model)
})

test('When models are added, added hook is called', () => {
test('When models are added, added callback is called', () => {
const transport = fixtures.transport()
const collection = fixtures.collection(fixtures.factory(), transport)
const models = modelPool.slice(0, 5)
Expand Down Expand Up @@ -240,8 +252,6 @@ describe('Collection - add #add #collection', () => {
}

static identityKey = 'isbn'

static setIdentityFromResponse = true
}

const model = new Test('1')
Expand Down
21 changes: 20 additions & 1 deletion packages/core/src/__tests__/collection-delete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ describe('Collection - delete #delete #collection', () => {
const transport = fixtures.transport()
const collection = fixtures.collection(fixtures.factory(), transport)
const model = fixtures.model()

// @ts-expect-error - internal callback test
const onRemovedSpy = jest.spyOn(model, 'onRemoved')

collection.add(model)

const result = collection.delete(model.cid, {
Expand All @@ -290,6 +294,8 @@ describe('Collection - delete #delete #collection', () => {
expect(collection.models).toHaveLength(1)
await result
expect(collection.models).toHaveLength(0)
expect(onRemovedSpy).toHaveBeenCalledTimes(1)
expect(onRemovedSpy).toHaveBeenCalledWith(collection)
})

test('After failed deletion, model is removed from the collection', async () => {
Expand All @@ -299,15 +305,20 @@ describe('Collection - delete #delete #collection', () => {
const model = fixtures.model()
collection.add(model)

// @ts-expect-error - internal callback test
const onRemovedSpy = jest.spyOn(model, 'onRemoved')

await collection.delete(model.cid, {
removeImmediately: false,
removeOnError: true
})

expect(collection.models).toHaveLength(0)
expect(onRemovedSpy).toHaveBeenCalledTimes(1)
expect(onRemovedSpy).toHaveBeenCalledWith(collection)
})

test('After successfull deletion, model is removed', async () => {
test('After successfull deletion, model is not removed', async () => {
const transport = fixtures.transport()
jest
.spyOn(transport, 'delete')
Expand All @@ -316,12 +327,16 @@ describe('Collection - delete #delete #collection', () => {
const model = fixtures.model()
collection.add(model)

// @ts-expect-error - internal callback test
const onRemovedSpy = jest.spyOn(model, 'onRemoved')

await collection.delete(model.cid, {
remove: false
})

expect(collection.models).toHaveLength(1)
expect(collection.models[0]).toBe(model)
expect(onRemovedSpy).not.toHaveBeenCalled()
})

test('After failed deletion, model is not removed', async () => {
Expand All @@ -331,13 +346,17 @@ describe('Collection - delete #delete #collection', () => {
const model = fixtures.model()
collection.add(model)

// @ts-expect-error - internal callback test
const onRemovedSpy = jest.spyOn(model, 'onRemoved')

await collection.delete(model.cid, {
removeImmediately: false,
removeOnError: false
})

expect(collection.models).toHaveLength(1)
expect(collection.models[0]).toBe(model)
expect(onRemovedSpy).not.toHaveBeenCalled()
})
})
})
14 changes: 12 additions & 2 deletions packages/core/src/__tests__/collection-save.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ describe('Collection - save #save #collection', () => {
const collectionSaveStartSpy = jest.spyOn(collection, 'onSaveStart')
const modelSaveStartSpy = jest.spyOn(model, 'onSaveStart')

// @ts-expect-error collection config
await collection.save(model, config, transportConfig)

expect(collectionSaveStartSpy).toHaveBeenCalledWith({
Expand Down Expand Up @@ -197,7 +196,6 @@ describe('Collection - save #save #collection', () => {
.spyOn(transport, 'save')
.mockImplementation(() => Promise.resolve(response))

// @ts-expect-error collection config
await collection.save(model, config, transportConfig)

expect(onSaveSuccessSpy).toHaveBeenCalledWith({
Expand Down Expand Up @@ -263,6 +261,8 @@ describe('Collection - save #save #collection', () => {
const collection = fixtures.collection(fixtures.factory(), transport)
const model = fixtures.model()

// @ts-expect-error - internal callback test
const onAddedSpy = jest.spyOn(model, 'onAdded')
const promise = collection.save(model, { addImmediately: false })

expect(collection.models).toHaveLength(0)
Expand All @@ -271,6 +271,8 @@ describe('Collection - save #save #collection', () => {

expect(collection.models).toHaveLength(1)
expect(collection.models[0]).toBe(model)
expect(onAddedSpy).toHaveBeenCalledTimes(1)
expect(onAddedSpy).toHaveBeenCalledWith(collection)
})

test('Add the model after the failed save', async () => {
Expand All @@ -281,13 +283,18 @@ describe('Collection - save #save #collection', () => {
const collection = fixtures.collection(fixtures.factory(), transport)
const model = fixtures.model()

// @ts-expect-error - internal callback test
const onAddedSpy = jest.spyOn(model, 'onAdded')

await collection.save(model, {
addImmediately: false,
addOnError: true
})

expect(collection.models).toHaveLength(1)
expect(collection.models[0]).toBe(model)
expect(onAddedSpy).toHaveBeenCalledTimes(1)
expect(onAddedSpy).toHaveBeenCalledWith(collection)
})

test('Do not add the model after the failed save', async () => {
Expand All @@ -297,13 +304,16 @@ describe('Collection - save #save #collection', () => {
.mockImplementation(() => Promise.reject(false))
const collection = fixtures.collection(fixtures.factory(), transport)
const model = fixtures.model()
// @ts-expect-error - internal callback test
const onAddedSpy = jest.spyOn(model, 'onAdded')

await collection.save(model, {
addImmediately: false,
addOnError: false
})

expect(collection.models).toHaveLength(0)
expect(onAddedSpy).not.toHaveBeenCalled()
})
})
})
13 changes: 13 additions & 0 deletions packages/core/src/__tests__/model-removed.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,18 @@ describe('Model - remove #remove #model', () => {
expect(model.isDestroyed).toBe(true)
expect(onDestroyedSpy).toHaveBeenCalledTimes(1)
})

test('"onRemoved" callback is called', () => {
const collection = fixtures.collection()
const model = fixtures.model({ id: '1' })

// @ts-expect-error - internal callback test
const onRemovedSpy = jest.spyOn(model, 'onRemoved')
collection.add(model)
collection.remove(model.identity)

expect(onRemovedSpy).toHaveBeenCalledTimes(1)
expect(onRemovedSpy).toHaveBeenCalledWith(collection)
})
})
})
1 change: 0 additions & 1 deletion packages/core/src/__tests__/model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const fixtures = fixtureFactory()

beforeAll(() => {
TestModel.identityKey = 'id'
TestModel.setIdentityFromResponse = true
})

describe('Model #model', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/collection/AutosaveCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { debounceReaction } from '../utils'
import { Collection } from './Collection'

export class AutosaveCollection<
TModel extends Model,
TModel extends Model<Collection<any, any, any>>,
TFactory extends FactoryFn<TModel>,
TTransport extends Transport<TModel>
> extends Collection<TModel, TFactory, TTransport> {
Expand Down
14 changes: 8 additions & 6 deletions packages/core/src/collection/Collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,7 @@ export class Collection<
this.startTracking(model)

this.onAdded(model)
model._onAdded(this)
}

// add models to the collection
Expand Down Expand Up @@ -1024,14 +1025,15 @@ export class Collection<
const removed: TModel[] = []
const currentCount = this._models.length

const handleRemoval = (m: TModel): void => {
removed.push(m)
this.stopTracking(m)
// this.notifyRemoved(m)
const handleRemoval = (model: TModel): void => {
removed.push(model)
this.stopTracking(model)

if (config?.destroy) {
m.destroy()
model.destroy()
}
this.onRemoved(m)
this.onRemoved(model)
model._onRemoved(this)
}
// optimize for only one element
if (modelCids.size === 1) {
Expand Down
Loading

0 comments on commit 515ec40

Please sign in to comment.