Skip to content

Commit 5c63e62

Browse files
committed
saveRecord
1 parent 57fb11d commit 5c63e62

File tree

4 files changed

+95
-5
lines changed

4 files changed

+95
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { assert } from '@ember/debug';
2+
3+
import { recordIdentifierFor, storeFor, type StoreRequestInput } from '@ember-data/store';
4+
import type { InstanceCache } from '@ember-data/store/-private/caches/instance-cache';
5+
import type { StableRecordIdentifier } from '@warp-drive/core-types';
6+
import type { Cache } from '@warp-drive/core-types/cache';
7+
import { SkipCache } from '@warp-drive/core-types/request';
8+
9+
export type SaveRecordRequestInput = StoreRequestInput & {
10+
op: 'createRecord' | 'deleteRecord' | 'updateRecord';
11+
data: {
12+
record: StableRecordIdentifier;
13+
options: SaveRecordBuilderOptions;
14+
};
15+
records: [StableRecordIdentifier];
16+
};
17+
18+
export type SaveRecordBuilderOptions = Record<string, unknown>;
19+
20+
function _resourceIsFullDeleted(identifier: StableRecordIdentifier, cache: Cache): boolean {
21+
return cache.isDeletionCommitted(identifier) || (cache.isNew(identifier) && cache.isDeleted(identifier));
22+
}
23+
24+
function resourceIsFullyDeleted(instanceCache: InstanceCache, identifier: StableRecordIdentifier): boolean {
25+
const cache = instanceCache.cache;
26+
return !cache || _resourceIsFullDeleted(identifier, cache);
27+
}
28+
29+
/**
30+
* FIXME: Docs
31+
This function builds a request config for the given type.
32+
When passed to `store.request`, this config will result in the same behavior as a `store.findAll` request.
33+
Additionally, it takes the same options as `store.findAll`.
34+
35+
@since x.x.x
36+
@method query
37+
@public
38+
@param {String} type the name of the resource
39+
@param {object} query a query to be used by the adapter
40+
@param {SaveRecordBuilderOptions} options optional, may include `adapterOptions` hash which will be passed to adapter.query
41+
@return {SaveRecordRequestInput} request config
42+
*/
43+
export function saveRecordBuilder<T>(record: T, options: Record<string, unknown> = {}): SaveRecordRequestInput {
44+
const store = storeFor(record);
45+
assert(`Unable to initiate save for a record in a disconnected state`, store);
46+
const identifier = recordIdentifierFor(record);
47+
48+
if (!identifier) {
49+
// this commonly means we're disconnected
50+
// but just in case we throw here to prevent bad things.
51+
throw new Error(`Record Is Disconnected`);
52+
}
53+
// TODO we used to check if the record was destroyed here
54+
assert(
55+
`Cannot initiate a save request for an unloaded record: ${identifier.lid}`,
56+
store._instanceCache.recordIsLoaded(identifier)
57+
);
58+
if (resourceIsFullyDeleted(store._instanceCache, identifier)) {
59+
throw new Error('cannot build saveRecord request for deleted record');
60+
}
61+
62+
if (!options) {
63+
options = {};
64+
}
65+
let operation: 'createRecord' | 'deleteRecord' | 'updateRecord' = 'updateRecord';
66+
67+
const cache = store.cache;
68+
if (cache.isNew(identifier)) {
69+
operation = 'createRecord';
70+
} else if (cache.isDeleted(identifier)) {
71+
operation = 'deleteRecord';
72+
}
73+
74+
return {
75+
op: operation,
76+
data: {
77+
options,
78+
record: identifier,
79+
},
80+
records: [identifier],
81+
cacheOptions: { [SkipCache as symbol]: true },
82+
};
83+
}
84+
85+
/*
86+
87+
TODO:
88+
* [] test this
89+
* [] make sure nothing fails bc of willCommit change
90+
91+
*/

packages/legacy-compat/src/legacy-network-handler/legacy-network-handler.ts

+2
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ function saveRecord<T>(context: StoreRequestContext): Promise<T> {
180180

181181
upgradeStore(store);
182182

183+
store.cache.willCommit(identifier, context);
184+
183185
const saveOptions = Object.assign(
184186
{ [SaveOp]: operation as 'updateRecord' | 'deleteRecord' | 'createRecord' },
185187
options

packages/store/src/-private/store-service.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -2121,7 +2121,7 @@ class Store extends EmberObject {
21212121
if (DEBUG) {
21222122
assertDestroyingStore(this, 'saveRecord');
21232123
}
2124-
assert(`Unable to initate save for a record in a disconnected state`, storeFor(record));
2124+
assert(`Unable to initiate save for a record in a disconnected state`, storeFor(record));
21252125
const identifier = recordIdentifierFor(record);
21262126
const cache = this.cache;
21272127

@@ -2160,9 +2160,6 @@ class Store extends EmberObject {
21602160
cacheOptions: { [SkipCache as symbol]: true },
21612161
};
21622162

2163-
// we lie here on the type because legacy doesn't have enough context
2164-
cache.willCommit(identifier, { request } as unknown as StoreRequestContext);
2165-
21662163
return this.request<T>(request).then((document) => document.content);
21672164
}
21682165

packages/store/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@
120120
*
121121
* ### Presenting Data from the Cache
122122
*
123-
* Now that we have a source and a cach for our data, we need to configure how
123+
* Now that we have a source and a cache for our data, we need to configure how
124124
* the Store delivers that data back to our application. We do this via the hook
125125
* [instantiateRecord](https://api.emberjs.com/ember-data/release/classes/Store/methods/instantiateRecord%20(hook)?anchor=instantiateRecord%20(hook)),
126126
* which allows us to transform the data for a resource before handing it to the application.

0 commit comments

Comments
 (0)