Skip to content

Commit

Permalink
[DOC serializer] implements MinimumSerializerInterface (#6451)
Browse files Browse the repository at this point in the history
  • Loading branch information
runspired committed Sep 25, 2019
1 parent ef2d508 commit 1e7c573
Show file tree
Hide file tree
Showing 15 changed files with 686 additions and 331 deletions.
527 changes: 265 additions & 262 deletions packages/-ember-data/node-tests/fixtures/expected.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import Adapter from '@ember-data/adapter';
import Serializer from '@ember-data/serializer';
import { resolve, all } from 'rsvp';
import { ExistingResourceObject } from '@ember-data/store/-private/ts-interfaces/ember-data-json-api';
import { Dict } from '@ember-data/store/-private/ts-interfaces/utils';
import { ConfidentDict } from '@ember-data/store/-private/ts-interfaces/utils';
import { StableRecordIdentifier } from '@ember-data/store/-private/ts-interfaces/identifier';
import { identifierCacheFor } from '@ember-data/store/-private';
import { set } from '@ember/object';
Expand All @@ -30,8 +30,8 @@ if (IDENTIFIERS) {
let store;
let calls;
let secondaryCache: {
id: Dict<string, string>;
username: Dict<string, string>;
id: ConfidentDict<string>;
username: ConfidentDict<string>;
};
class TestSerializer extends Serializer {
normalizeResponse(_, __, payload) {
Expand Down Expand Up @@ -232,7 +232,7 @@ if (IDENTIFIERS) {
module('Secondary Cache using an attribute as an alternate id', function(hooks) {
let store;
let calls;
let secondaryCache: Dict<string, string>;
let secondaryCache: ConfidentDict<string>;
class TestSerializer extends Serializer {
normalizeResponse(_, __, payload) {
return payload;
Expand Down
1 change: 1 addition & 0 deletions packages/adapter/addon/-private/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { determineBodyPromise } from './utils/determine-body-promise';
export { serializeQueryParams } from './utils/serialize-query-params';
export { default as fetch } from './utils/fetch';
export { default as BuildURLMixin } from './build-url-mixin';
export { default as serializeIntoHash } from './utils/serialize-into-hash';
11 changes: 11 additions & 0 deletions packages/adapter/addon/-private/utils/serialize-into-hash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function serializeIntoHash(store, modelClass, snapshot, options = { includeId: true }) {
const serializer = store.serializerFor(modelClass.modelName);

if (typeof serializer.serializeIntoHash === 'function') {
const data = {};
serializer.serializeIntoHash(data, modelClass, snapshot, options);
return data;
}

return serializer.serialize(snapshot, options);
}
7 changes: 2 additions & 5 deletions packages/adapter/addon/json-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { dasherize } from '@ember/string';
import RESTAdapter from './rest';
import { pluralize } from 'ember-inflector';
import { serializeIntoHash } from './-private';

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

// TODO: Remove this once we have a better way to override HTTP verbs.
updateRecord(store, type, snapshot) {
let data = {};
let serializer = store.serializerFor(type.modelName);

serializer.serializeIntoHash(data, type, snapshot, { includeId: true });
const data = serializeIntoHash(store, type, snapshot);

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

Expand Down
14 changes: 5 additions & 9 deletions packages/adapter/addon/rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import AdapterError, {
} from '@ember-data/adapter/error';
import { warn } from '@ember/debug';
import { DEBUG } from '@glimmer/env';
import { serializeIntoHash } from './-private';

const Promise = EmberPromise;
const hasJQuery = typeof jQuery !== 'undefined';
Expand Down Expand Up @@ -725,13 +726,11 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, {
@return {Promise} promise
*/
createRecord(store, type, snapshot) {
let data = {};
let serializer = store.serializerFor(type.modelName);
let url = this.buildURL(type.modelName, null, snapshot, 'createRecord');

serializer.serializeIntoHash(data, type, snapshot, { includeId: true });
const data = serializeIntoHash(store, type, snapshot);

return this.ajax(url, 'POST', { data: data });
return this.ajax(url, 'POST', { data });
},

/**
Expand All @@ -751,15 +750,12 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, {
@return {Promise} promise
*/
updateRecord(store, type, snapshot) {
let data = {};
let serializer = store.serializerFor(type.modelName);

serializer.serializeIntoHash(data, type, snapshot);
const data = serializeIntoHash(store, type, snapshot, {});

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

return this.ajax(url, 'PUT', { data: data });
return this.ajax(url, 'PUT', { data });
},

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/store/addon/-private/identifiers/cache.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DEBUG } from '@glimmer/env';
import { warn } from '@ember/debug';
import { Dict } from '../ts-interfaces/utils';
import { ConfidentDict } from '../ts-interfaces/utils';
import { ResourceIdentifierObject, ExistingResourceObject } from '../ts-interfaces/ember-data-json-api';
import {
StableRecordIdentifier,
Expand Down Expand Up @@ -30,8 +30,8 @@ interface KeyOptions {
_allIdentifiers: StableRecordIdentifier[];
}

type IdentifierMap = Dict<string, StableRecordIdentifier>;
type TypeMap = Dict<string, KeyOptions>;
type IdentifierMap = ConfidentDict<StableRecordIdentifier>;
type TypeMap = ConfidentDict<KeyOptions>;
export type MergeMethod = (
targetIdentifier: StableRecordIdentifier,
matchedIdentifier: StableRecordIdentifier,
Expand Down
76 changes: 48 additions & 28 deletions packages/store/addon/-private/system/core-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import Reference from './references/reference';
import { Dict } from '../ts-interfaces/utils';

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

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

function deprecateTestRegistration(factoryType: 'adapter', factoryName: '-json-api'): void;
function deprecateTestRegistration(factoryType: 'serializer', factoryName: '-json-api' | '-rest' | '-default'): void;
function deprecateTestRegistration(factoryType: 'serializer' | 'adapter', factoryName: '-json-api' | '-rest' | '-default'): void {
function deprecateTestRegistration(
factoryType: 'serializer' | 'adapter',
factoryName: '-json-api' | '-rest' | '-default'
): void {
deprecate(
`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.`,
false,
Expand Down Expand Up @@ -1269,8 +1273,8 @@ abstract class CoreStore extends Service {
if (missingInternalModels.length) {
warn(
'Ember Data expected to find records with the following ids in the adapter response but they were missing: [ "' +
missingInternalModels.map(r => r.id).join('", "') +
'" ]',
missingInternalModels.map(r => r.id).join('", "') +
'" ]',
false,
{
id: 'ds.store.missing-records-from-adapter',
Expand All @@ -1291,9 +1295,9 @@ abstract class CoreStore extends Service {
if (pair) {
pair.resolver.reject(
error ||
new Error(
`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`
)
new Error(
`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`
)
);
}
}
Expand Down Expand Up @@ -1331,12 +1335,12 @@ abstract class CoreStore extends Service {
}

if (totalInGroup > 1) {
(function (groupedInternalModels) {
(function(groupedInternalModels) {
_findMany(adapter, store, modelName, ids, groupedInternalModels, optionsMap)
.then(function (foundInternalModels) {
.then(function(foundInternalModels) {
handleFoundRecords(foundInternalModels, groupedInternalModels);
})
.catch(function (error) {
.catch(function(error) {
rejectInternalModels(groupedInternalModels, error);
});
})(groupedInternalModels);
Expand Down Expand Up @@ -3015,7 +3019,7 @@ abstract class CoreStore extends Service {
return internalModelFactoryFor(this).lookup(resource);
}

serializeRecord(record: Record, options?: Dict<string, unknown>): unknown {
serializeRecord(record: Record, options?: Dict<unknown>): unknown {
if (CUSTOM_MODEL_CLASS) {
let identifier = recordIdentifierFor(record);
let internalModel = internalModelFactoryFor(this).peek(identifier);
Expand All @@ -3026,7 +3030,7 @@ abstract class CoreStore extends Service {
}
}

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

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, {
id: 'ember-data:default-serializer',
until: '4.0',
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-serializers'
});
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,
{
id: 'ember-data:default-serializer',
until: '4.0',
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-serializers',
}
);

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

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, {
id: 'ember-data:default-serializer',
until: '4.0',
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-serializers'
});
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,
{
id: 'ember-data:default-serializer',
until: '4.0',
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-serializers',
}
);

assert(
`No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
Expand Down Expand Up @@ -3448,12 +3460,12 @@ abstract class CoreStore extends Service {
if (shouldTrack) {
throw new Error(
'Async Request leaks detected. Add a breakpoint here and set `store.generateStackTracesForTrackedRequests = true;`to inspect traces for leak origins:\n\t - ' +
tracked.map(o => o.label).join('\n\t - ')
tracked.map(o => o.label).join('\n\t - ')
);
} else {
warn(
'Async Request leaks detected. Add a breakpoint here and set `store.generateStackTracesForTrackedRequests = true;`to inspect traces for leak origins:\n\t - ' +
tracked.map(o => o.label).join('\n\t - '),
tracked.map(o => o.label).join('\n\t - '),
false,
{
id: 'ds.async.leak.detected',
Expand Down Expand Up @@ -3506,14 +3518,15 @@ abstract class CoreStore extends Service {
defineProperty(
CoreStore.prototype,
'defaultAdapter',
computed('adapter', function () {
computed('adapter', function() {
deprecate(
`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.`,
`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.`,
false,
{
id: 'ember-data:default-adapter',
until: '4.0',
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-adapter'
url: 'https://deprecations.emberjs.com/ember-data/v3.x#toc_ember-data:default-adapter',
}
);
let adapter = this.adapter || '-json-api';
Expand Down Expand Up @@ -3580,9 +3593,16 @@ function _commit(adapter, store, operation, snapshot) {

return internalModel;
},
function (error) {
function(error) {
if (error instanceof InvalidError) {
let parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
let parsedErrors;

if (typeof serializer.extractErrors === 'function') {
parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
} else {
parsedErrors = errorsArrayToHash(error.errors);
}

store.recordWasInvalid(internalModel, parsedErrors, error);
} else {
store.recordWasError(internalModel, error);
Expand Down
11 changes: 9 additions & 2 deletions packages/store/addon/-private/system/fetch-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { normalizeResponseHelper } from './store/serializer-response';
import { InvalidError } from '@ember-data/adapter/error';
import coerceId from './coerce-id';
import { A } from '@ember/array';

import { _findHasMany, _findBelongsTo, _findAll, _query, _queryRecord } from './store/finders';
import RequestCache from './request-cache';
import { CollectionResourceDocument, SingleResourceDocument } from '../ts-interfaces/ember-data-json-api';
Expand All @@ -18,6 +17,7 @@ import { symbol } from '../ts-interfaces/utils/symbol';
import Store from './ds-model-store';
import recordDataFor from './record-data-for';
import CoreStore from './core-store';
import { errorsArrayToHash } from './errors-utils';

function payloadIsNotBlank(adapterPayload): boolean {
if (Array.isArray(adapterPayload)) {
Expand Down Expand Up @@ -135,7 +135,14 @@ export default class FetchManager {
},
function(error) {
if (error instanceof InvalidError) {
let parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
let parsedErrors = error.errors;

if (typeof serializer.extractErrors === 'function') {
parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
} else {
parsedErrors = errorsArrayToHash(error.errors);
}

throw { error, parsedErrors };
} else {
throw { error };
Expand Down
4 changes: 2 additions & 2 deletions packages/store/addon/-private/system/identity-map.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import InternalModelMap from './internal-model-map';
import { Dict } from '../ts-interfaces/utils';
import { ConfidentDict } from '../ts-interfaces/utils';

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

/**
Retrieves the `InternalModelMap` for a given modelName,
Expand Down
8 changes: 4 additions & 4 deletions packages/store/addon/-private/system/internal-model-map.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { assert } from '@ember/debug';
import InternalModel from './model/internal-model';
import { Dict } from '../ts-interfaces/utils';
import { ConfidentDict } from '../ts-interfaces/utils';

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

constructor(public modelName: string) {}

Expand Down Expand Up @@ -104,7 +104,7 @@ export default class InternalModelMap {
* @property metadata
* @type Object
*/
get metadata(): Dict<string, any> {
get metadata(): ConfidentDict<any> {
return this._metadata || (this._metadata = Object.create(null));
}

Expand Down
Loading

0 comments on commit 1e7c573

Please sign in to comment.