Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DOC serializer] implements MinimumSerializerInterface #6451

Merged
merged 19 commits into from
Sep 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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') {
runspired marked this conversation as resolved.
Show resolved Hide resolved
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;
runspired marked this conversation as resolved.
Show resolved Hide resolved

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