Skip to content

Commit 1e7c573

Browse files
authored
[DOC serializer] implements MinimumSerializerInterface (#6451)
1 parent ef2d508 commit 1e7c573

File tree

15 files changed

+686
-331
lines changed

15 files changed

+686
-331
lines changed

packages/-ember-data/node-tests/fixtures/expected.js

Lines changed: 265 additions & 262 deletions
Large diffs are not rendered by default.

packages/-ember-data/tests/integration/identifiers/scenarios-test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Adapter from '@ember-data/adapter';
1313
import Serializer from '@ember-data/serializer';
1414
import { resolve, all } from 'rsvp';
1515
import { ExistingResourceObject } from '@ember-data/store/-private/ts-interfaces/ember-data-json-api';
16-
import { Dict } from '@ember-data/store/-private/ts-interfaces/utils';
16+
import { ConfidentDict } from '@ember-data/store/-private/ts-interfaces/utils';
1717
import { StableRecordIdentifier } from '@ember-data/store/-private/ts-interfaces/identifier';
1818
import { identifierCacheFor } from '@ember-data/store/-private';
1919
import { set } from '@ember/object';
@@ -30,8 +30,8 @@ if (IDENTIFIERS) {
3030
let store;
3131
let calls;
3232
let secondaryCache: {
33-
id: Dict<string, string>;
34-
username: Dict<string, string>;
33+
id: ConfidentDict<string>;
34+
username: ConfidentDict<string>;
3535
};
3636
class TestSerializer extends Serializer {
3737
normalizeResponse(_, __, payload) {
@@ -232,7 +232,7 @@ if (IDENTIFIERS) {
232232
module('Secondary Cache using an attribute as an alternate id', function(hooks) {
233233
let store;
234234
let calls;
235-
let secondaryCache: Dict<string, string>;
235+
let secondaryCache: ConfidentDict<string>;
236236
class TestSerializer extends Serializer {
237237
normalizeResponse(_, __, payload) {
238238
return payload;

packages/adapter/addon/-private/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export { determineBodyPromise } from './utils/determine-body-promise';
77
export { serializeQueryParams } from './utils/serialize-query-params';
88
export { default as fetch } from './utils/fetch';
99
export { default as BuildURLMixin } from './build-url-mixin';
10+
export { default as serializeIntoHash } from './utils/serialize-into-hash';
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export default function serializeIntoHash(store, modelClass, snapshot, options = { includeId: true }) {
2+
const serializer = store.serializerFor(modelClass.modelName);
3+
4+
if (typeof serializer.serializeIntoHash === 'function') {
5+
const data = {};
6+
serializer.serializeIntoHash(data, modelClass, snapshot, options);
7+
return data;
8+
}
9+
10+
return serializer.serialize(snapshot, options);
11+
}

packages/adapter/addon/json-api.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import { dasherize } from '@ember/string';
55
import RESTAdapter from './rest';
66
import { pluralize } from 'ember-inflector';
7+
import { serializeIntoHash } from './-private';
78

89
/**
910
The `JSONAPIAdapter` is the default adapter used by Ember Data. It
@@ -228,12 +229,8 @@ const JSONAPIAdapter = RESTAdapter.extend({
228229
return pluralize(dasherized);
229230
},
230231

231-
// TODO: Remove this once we have a better way to override HTTP verbs.
232232
updateRecord(store, type, snapshot) {
233-
let data = {};
234-
let serializer = store.serializerFor(type.modelName);
235-
236-
serializer.serializeIntoHash(data, type, snapshot, { includeId: true });
233+
const data = serializeIntoHash(store, type, snapshot);
237234

238235
let url = this.buildURL(type.modelName, snapshot.id, snapshot, 'updateRecord');
239236

packages/adapter/addon/rest.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import AdapterError, {
2323
} from '@ember-data/adapter/error';
2424
import { warn } from '@ember/debug';
2525
import { DEBUG } from '@glimmer/env';
26+
import { serializeIntoHash } from './-private';
2627

2728
const Promise = EmberPromise;
2829
const hasJQuery = typeof jQuery !== 'undefined';
@@ -725,13 +726,11 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, {
725726
@return {Promise} promise
726727
*/
727728
createRecord(store, type, snapshot) {
728-
let data = {};
729-
let serializer = store.serializerFor(type.modelName);
730729
let url = this.buildURL(type.modelName, null, snapshot, 'createRecord');
731730

732-
serializer.serializeIntoHash(data, type, snapshot, { includeId: true });
731+
const data = serializeIntoHash(store, type, snapshot);
733732

734-
return this.ajax(url, 'POST', { data: data });
733+
return this.ajax(url, 'POST', { data });
735734
},
736735

737736
/**
@@ -751,15 +750,12 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, {
751750
@return {Promise} promise
752751
*/
753752
updateRecord(store, type, snapshot) {
754-
let data = {};
755-
let serializer = store.serializerFor(type.modelName);
756-
757-
serializer.serializeIntoHash(data, type, snapshot);
753+
const data = serializeIntoHash(store, type, snapshot, {});
758754

759755
let id = snapshot.id;
760756
let url = this.buildURL(type.modelName, id, snapshot, 'updateRecord');
761757

762-
return this.ajax(url, 'PUT', { data: data });
758+
return this.ajax(url, 'PUT', { data });
763759
},
764760

765761
/**

packages/store/addon/-private/identifiers/cache.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DEBUG } from '@glimmer/env';
22
import { warn } from '@ember/debug';
3-
import { Dict } from '../ts-interfaces/utils';
3+
import { ConfidentDict } from '../ts-interfaces/utils';
44
import { ResourceIdentifierObject, ExistingResourceObject } from '../ts-interfaces/ember-data-json-api';
55
import {
66
StableRecordIdentifier,
@@ -30,8 +30,8 @@ interface KeyOptions {
3030
_allIdentifiers: StableRecordIdentifier[];
3131
}
3232

33-
type IdentifierMap = Dict<string, StableRecordIdentifier>;
34-
type TypeMap = Dict<string, KeyOptions>;
33+
type IdentifierMap = ConfidentDict<StableRecordIdentifier>;
34+
type TypeMap = ConfidentDict<KeyOptions>;
3535
export type MergeMethod = (
3636
targetIdentifier: StableRecordIdentifier,
3737
matchedIdentifier: StableRecordIdentifier,

packages/store/addon/-private/system/core-store.ts

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ import Reference from './references/reference';
8080
import { Dict } from '../ts-interfaces/utils';
8181

8282
import constructResource from '../utils/construct-resource';
83+
import { errorsArrayToHash } from './errors-utils';
8384
const emberRun = emberRunLoop.backburner;
8485

8586
const { ENV } = Ember;
@@ -103,7 +104,10 @@ const HAS_ADAPTER_PACKAGE = has('@ember-data/adapter');
103104

104105
function deprecateTestRegistration(factoryType: 'adapter', factoryName: '-json-api'): void;
105106
function deprecateTestRegistration(factoryType: 'serializer', factoryName: '-json-api' | '-rest' | '-default'): void;
106-
function deprecateTestRegistration(factoryType: 'serializer' | 'adapter', factoryName: '-json-api' | '-rest' | '-default'): void {
107+
function deprecateTestRegistration(
108+
factoryType: 'serializer' | 'adapter',
109+
factoryName: '-json-api' | '-rest' | '-default'
110+
): void {
107111
deprecate(
108112
`You looked up the ${factoryType} "${factoryName}" but it was not found. Likely this means you are using a legacy ember-qunit moduleFor helper. Add "needs: ['${factoryType}:${factoryName}']", "integration: true", or refactor to modern syntax to resolve this deprecation.`,
109113
false,
@@ -1269,8 +1273,8 @@ abstract class CoreStore extends Service {
12691273
if (missingInternalModels.length) {
12701274
warn(
12711275
'Ember Data expected to find records with the following ids in the adapter response but they were missing: [ "' +
1272-
missingInternalModels.map(r => r.id).join('", "') +
1273-
'" ]',
1276+
missingInternalModels.map(r => r.id).join('", "') +
1277+
'" ]',
12741278
false,
12751279
{
12761280
id: 'ds.store.missing-records-from-adapter',
@@ -1291,9 +1295,9 @@ abstract class CoreStore extends Service {
12911295
if (pair) {
12921296
pair.resolver.reject(
12931297
error ||
1294-
new Error(
1295-
`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`
1296-
)
1298+
new Error(
1299+
`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`
1300+
)
12971301
);
12981302
}
12991303
}
@@ -1331,12 +1335,12 @@ abstract class CoreStore extends Service {
13311335
}
13321336

13331337
if (totalInGroup > 1) {
1334-
(function (groupedInternalModels) {
1338+
(function(groupedInternalModels) {
13351339
_findMany(adapter, store, modelName, ids, groupedInternalModels, optionsMap)
1336-
.then(function (foundInternalModels) {
1340+
.then(function(foundInternalModels) {
13371341
handleFoundRecords(foundInternalModels, groupedInternalModels);
13381342
})
1339-
.catch(function (error) {
1343+
.catch(function(error) {
13401344
rejectInternalModels(groupedInternalModels, error);
13411345
});
13421346
})(groupedInternalModels);
@@ -3015,7 +3019,7 @@ abstract class CoreStore extends Service {
30153019
return internalModelFactoryFor(this).lookup(resource);
30163020
}
30173021

3018-
serializeRecord(record: Record, options?: Dict<string, unknown>): unknown {
3022+
serializeRecord(record: Record, options?: Dict<unknown>): unknown {
30193023
if (CUSTOM_MODEL_CLASS) {
30203024
let identifier = recordIdentifierFor(record);
30213025
let internalModel = internalModelFactoryFor(this).peek(identifier);
@@ -3026,7 +3030,7 @@ abstract class CoreStore extends Service {
30263030
}
30273031
}
30283032

3029-
saveRecord(record: Record, options?: Dict<string, unknown>): RSVP.Promise<Record> {
3033+
saveRecord(record: Record, options?: Dict<unknown>): RSVP.Promise<Record> {
30303034
if (CUSTOM_MODEL_CLASS) {
30313035
let identifier = recordIdentifierFor(record);
30323036
let internalModel = internalModelFactoryFor(this).peek(identifier);
@@ -3360,11 +3364,15 @@ abstract class CoreStore extends Service {
33603364
let adapter = this.adapterFor(modelName);
33613365
let serializerName = get(adapter, 'defaultSerializer');
33623366

3363-
deprecate(`store.serializerFor("${modelName}") resolved the "${serializerName}" serializer via the deprecated \`adapter.defaultSerializer\` property.\n\n\tPreviously, if no application or type-specific serializer was specified, the store would attempt to lookup a serializer via the \`defaultSerializer\` property on the type's adapter. This behavior is deprecated in favor of explicitly defining a type-specific serializer or application serializer`, !serializerName, {
3364-
id: 'ember-data:default-serializer',
3365-
until: '4.0',
3366-
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-serializers'
3367-
});
3367+
deprecate(
3368+
`store.serializerFor("${modelName}") resolved the "${serializerName}" serializer via the deprecated \`adapter.defaultSerializer\` property.\n\n\tPreviously, if no application or type-specific serializer was specified, the store would attempt to lookup a serializer via the \`defaultSerializer\` property on the type's adapter. This behavior is deprecated in favor of explicitly defining a type-specific serializer or application serializer`,
3369+
!serializerName,
3370+
{
3371+
id: 'ember-data:default-serializer',
3372+
until: '4.0',
3373+
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-serializers',
3374+
}
3375+
);
33683376

33693377
serializer = serializerName
33703378
? _serializerCache[serializerName] || owner.lookup(`serializer:${serializerName}`)
@@ -3408,11 +3416,15 @@ abstract class CoreStore extends Service {
34083416
serializer && deprecateTestRegistration('serializer', '-default');
34093417
}
34103418

3411-
deprecate(`store.serializerFor("${modelName}") resolved the "-default" serializer via the deprecated "-default" lookup fallback.\n\n\tPreviously, when no type-specific serializer, application serializer, or adapter.defaultSerializer had been defined by the app, the "-default" serializer would be used which defaulted to the \`JSONSerializer\`. This behavior is deprecated in favor of explicitly defining an application or type-specific serializer`, !serializer, {
3412-
id: 'ember-data:default-serializer',
3413-
until: '4.0',
3414-
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-serializers'
3415-
});
3419+
deprecate(
3420+
`store.serializerFor("${modelName}") resolved the "-default" serializer via the deprecated "-default" lookup fallback.\n\n\tPreviously, when no type-specific serializer, application serializer, or adapter.defaultSerializer had been defined by the app, the "-default" serializer would be used which defaulted to the \`JSONSerializer\`. This behavior is deprecated in favor of explicitly defining an application or type-specific serializer`,
3421+
!serializer,
3422+
{
3423+
id: 'ember-data:default-serializer',
3424+
until: '4.0',
3425+
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-serializers',
3426+
}
3427+
);
34163428

34173429
assert(
34183430
`No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
@@ -3448,12 +3460,12 @@ abstract class CoreStore extends Service {
34483460
if (shouldTrack) {
34493461
throw new Error(
34503462
'Async Request leaks detected. Add a breakpoint here and set `store.generateStackTracesForTrackedRequests = true;`to inspect traces for leak origins:\n\t - ' +
3451-
tracked.map(o => o.label).join('\n\t - ')
3463+
tracked.map(o => o.label).join('\n\t - ')
34523464
);
34533465
} else {
34543466
warn(
34553467
'Async Request leaks detected. Add a breakpoint here and set `store.generateStackTracesForTrackedRequests = true;`to inspect traces for leak origins:\n\t - ' +
3456-
tracked.map(o => o.label).join('\n\t - '),
3468+
tracked.map(o => o.label).join('\n\t - '),
34573469
false,
34583470
{
34593471
id: 'ds.async.leak.detected',
@@ -3506,14 +3518,15 @@ abstract class CoreStore extends Service {
35063518
defineProperty(
35073519
CoreStore.prototype,
35083520
'defaultAdapter',
3509-
computed('adapter', function () {
3521+
computed('adapter', function() {
35103522
deprecate(
3511-
`store.adapterFor(modelName) resolved the ("${this.adapter || '-json-api'}") adapter via the deprecated \`store.defaultAdapter\` property.\n\n\tPreviously, applications could define the store's \`adapter\` property which would be used by \`defaultAdapter\` and \`adapterFor\` as a fallback for when an adapter was not found by an exact name match. This behavior is deprecated in favor of explicitly defining an application or type-specific adapter.`,
3523+
`store.adapterFor(modelName) resolved the ("${this.adapter ||
3524+
'-json-api'}") adapter via the deprecated \`store.defaultAdapter\` property.\n\n\tPreviously, applications could define the store's \`adapter\` property which would be used by \`defaultAdapter\` and \`adapterFor\` as a fallback for when an adapter was not found by an exact name match. This behavior is deprecated in favor of explicitly defining an application or type-specific adapter.`,
35123525
false,
35133526
{
35143527
id: 'ember-data:default-adapter',
35153528
until: '4.0',
3516-
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-adapter'
3529+
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-adapter',
35173530
}
35183531
);
35193532
let adapter = this.adapter || '-json-api';
@@ -3580,9 +3593,16 @@ function _commit(adapter, store, operation, snapshot) {
35803593

35813594
return internalModel;
35823595
},
3583-
function (error) {
3596+
function(error) {
35843597
if (error instanceof InvalidError) {
3585-
let parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
3598+
let parsedErrors;
3599+
3600+
if (typeof serializer.extractErrors === 'function') {
3601+
parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
3602+
} else {
3603+
parsedErrors = errorsArrayToHash(error.errors);
3604+
}
3605+
35863606
store.recordWasInvalid(internalModel, parsedErrors, error);
35873607
} else {
35883608
store.recordWasError(internalModel, error);

packages/store/addon/-private/system/fetch-manager.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { normalizeResponseHelper } from './store/serializer-response';
88
import { InvalidError } from '@ember-data/adapter/error';
99
import coerceId from './coerce-id';
1010
import { A } from '@ember/array';
11-
1211
import { _findHasMany, _findBelongsTo, _findAll, _query, _queryRecord } from './store/finders';
1312
import RequestCache from './request-cache';
1413
import { CollectionResourceDocument, SingleResourceDocument } from '../ts-interfaces/ember-data-json-api';
@@ -18,6 +17,7 @@ import { symbol } from '../ts-interfaces/utils/symbol';
1817
import Store from './ds-model-store';
1918
import recordDataFor from './record-data-for';
2019
import CoreStore from './core-store';
20+
import { errorsArrayToHash } from './errors-utils';
2121

2222
function payloadIsNotBlank(adapterPayload): boolean {
2323
if (Array.isArray(adapterPayload)) {
@@ -135,7 +135,14 @@ export default class FetchManager {
135135
},
136136
function(error) {
137137
if (error instanceof InvalidError) {
138-
let parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
138+
let parsedErrors = error.errors;
139+
140+
if (typeof serializer.extractErrors === 'function') {
141+
parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
142+
} else {
143+
parsedErrors = errorsArrayToHash(error.errors);
144+
}
145+
139146
throw { error, parsedErrors };
140147
} else {
141148
throw { error };

packages/store/addon/-private/system/identity-map.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import InternalModelMap from './internal-model-map';
2-
import { Dict } from '../ts-interfaces/utils';
2+
import { ConfidentDict } from '../ts-interfaces/utils';
33

44
/**
55
@module @ember-data/store
@@ -13,7 +13,7 @@ import { Dict } from '../ts-interfaces/utils';
1313
@private
1414
*/
1515
export default class IdentityMap {
16-
private _map: Dict<string, InternalModelMap> = Object.create(null);
16+
private _map: ConfidentDict<InternalModelMap> = Object.create(null);
1717

1818
/**
1919
Retrieves the `InternalModelMap` for a given modelName,

packages/store/addon/-private/system/internal-model-map.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { assert } from '@ember/debug';
22
import InternalModel from './model/internal-model';
3-
import { Dict } from '../ts-interfaces/utils';
3+
import { ConfidentDict } from '../ts-interfaces/utils';
44

55
/**
66
@module @ember-data/store
@@ -17,9 +17,9 @@ import { Dict } from '../ts-interfaces/utils';
1717
@private
1818
*/
1919
export default class InternalModelMap {
20-
private _idToModel: Dict<string, InternalModel> = Object.create(null);
20+
private _idToModel: ConfidentDict<InternalModel> = Object.create(null);
2121
private _models: InternalModel[] = [];
22-
private _metadata: Dict<string, any> | null = null;
22+
private _metadata: ConfidentDict<any> | null = null;
2323

2424
constructor(public modelName: string) {}
2525

@@ -104,7 +104,7 @@ export default class InternalModelMap {
104104
* @property metadata
105105
* @type Object
106106
*/
107-
get metadata(): Dict<string, any> {
107+
get metadata(): ConfidentDict<any> {
108108
return this._metadata || (this._metadata = Object.create(null));
109109
}
110110

0 commit comments

Comments
 (0)