From 69c9e08528c45c3f2fac94be1af2b208e30c982d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 11 Mar 2024 03:43:08 -0700 Subject: [PATCH] feat: typed serializers --- packages/model/src/-private/model.d.ts | 2 +- packages/serializer/.eslintrc.cjs | 2 +- packages/serializer/package.json | 5 + .../src/-private/transforms/boolean.ts | 4 + .../src/-private/transforms/date.ts | 4 + .../src/-private/transforms/number.ts | 4 + .../src/-private/transforms/string.ts | 4 + packages/serializer/src/index.ts | 5 +- packages/serializer/src/{json.js => json.ts} | 732 +++++++++++------- packages/serializer/src/{rest.js => rest.ts} | 107 +-- pnpm-lock.yaml | 21 +- 11 files changed, 531 insertions(+), 359 deletions(-) rename packages/serializer/src/{json.js => json.ts} (69%) rename packages/serializer/src/{rest.js => rest.ts} (91%) diff --git a/packages/model/src/-private/model.d.ts b/packages/model/src/-private/model.d.ts index 931eaa5f440..6deddb8573c 100644 --- a/packages/model/src/-private/model.d.ts +++ b/packages/model/src/-private/model.d.ts @@ -71,7 +71,7 @@ class Model extends EmberObject { binding?: T ): void; static eachTransformedAttribute( - callback: (this: ModelSchema, key: K, type: string | null) => void, + callback: (this: ModelSchema, key: K, type: string) => void, binding?: T ): void; diff --git a/packages/serializer/.eslintrc.cjs b/packages/serializer/.eslintrc.cjs index bf7106fbe2a..615d6341625 100644 --- a/packages/serializer/.eslintrc.cjs +++ b/packages/serializer/.eslintrc.cjs @@ -17,7 +17,7 @@ module.exports = { isolation.rules({ allowedImports: [ 'ember-inflector', - '@ember/application', + '@ember/owner', '@ember/service', '@ember/debug', '@ember/object', diff --git a/packages/serializer/package.json b/packages/serializer/package.json index a0c72853a57..f4701aaef49 100644 --- a/packages/serializer/package.json +++ b/packages/serializer/package.json @@ -49,6 +49,7 @@ "peerDependencies": { "@ember/string": "^3.1.1", "@warp-drive/core-types": "workspace:0.0.0-alpha.21", + "@ember-data/legacy-compat": "workspace:5.4.0-alpha.35", "ember-inflector": "^4.0.2" }, "dependenciesMeta": { @@ -72,6 +73,9 @@ }, "@ember-data/tracking": { "injected": true + }, + "@ember-data/legacy-compat": { + "injected": true } }, "dependencies": { @@ -95,6 +99,7 @@ "@ember-data/request": "workspace:5.4.0-alpha.35", "@ember-data/store": "workspace:5.4.0-alpha.35", "@ember-data/tracking": "workspace:5.4.0-alpha.35", + "@ember-data/legacy-compat": "workspace:5.4.0-alpha.35", "@ember/string": "^3.1.1", "@embroider/addon-dev": "^4.1.2", "@glimmer/component": "^1.1.2", diff --git a/packages/serializer/src/-private/transforms/boolean.ts b/packages/serializer/src/-private/transforms/boolean.ts index 3f9df0a6967..2efdae2bb10 100644 --- a/packages/serializer/src/-private/transforms/boolean.ts +++ b/packages/serializer/src/-private/transforms/boolean.ts @@ -2,6 +2,8 @@ @module @ember-data/serializer */ +import { TransformName } from '@warp-drive/core-types/symbols'; + /** The `BooleanTransform` class is used to serialize and deserialize boolean attributes on Ember Data record objects. This transform is @@ -62,6 +64,8 @@ export default class BooleanTransform { return Boolean(deserialized); } + [TransformName] = 'boolean' as const; + static create() { return new this(); } diff --git a/packages/serializer/src/-private/transforms/date.ts b/packages/serializer/src/-private/transforms/date.ts index 8956770297b..b4f01870330 100644 --- a/packages/serializer/src/-private/transforms/date.ts +++ b/packages/serializer/src/-private/transforms/date.ts @@ -2,6 +2,8 @@ @module @ember-data/serializer */ +import { TransformName } from '@warp-drive/core-types/symbols'; + /** The `DateTransform` class is used to serialize and deserialize date attributes on Ember Data record objects. This transform is used @@ -53,6 +55,8 @@ export default class DateTransform { } } + [TransformName] = 'date' as const; + static create() { return new this(); } diff --git a/packages/serializer/src/-private/transforms/number.ts b/packages/serializer/src/-private/transforms/number.ts index 96311570358..75cd6d52c57 100644 --- a/packages/serializer/src/-private/transforms/number.ts +++ b/packages/serializer/src/-private/transforms/number.ts @@ -2,6 +2,8 @@ @module @ember-data/serializer */ +import { TransformName } from '@warp-drive/core-types/symbols'; + function isNumber(value: number) { return value === value && value !== Infinity && value !== -Infinity; } @@ -48,6 +50,8 @@ export default class NumberTransform { } } + [TransformName] = 'number' as const; + static create() { return new this(); } diff --git a/packages/serializer/src/-private/transforms/string.ts b/packages/serializer/src/-private/transforms/string.ts index 57cb785567f..9f35c828a1e 100644 --- a/packages/serializer/src/-private/transforms/string.ts +++ b/packages/serializer/src/-private/transforms/string.ts @@ -2,6 +2,8 @@ @module @ember-data/serializer */ +import { TransformName } from '@warp-drive/core-types/symbols'; + /** The `StringTransform` class is used to serialize and deserialize string attributes on Ember Data record objects. This transform is @@ -31,6 +33,8 @@ export default class StringTransform { return !deserialized && deserialized !== '' ? null : String(deserialized); } + [TransformName] = 'string' as const; + static create() { return new this(); } diff --git a/packages/serializer/src/index.ts b/packages/serializer/src/index.ts index 4e80b8e3752..3427886ccc0 100644 --- a/packages/serializer/src/index.ts +++ b/packages/serializer/src/index.ts @@ -112,6 +112,7 @@ import { inject as service } from '@ember/service'; import type Store from '@ember-data/store'; import type { ModelSchema } from '@ember-data/store/-types/q/ds-model'; +import type { EmptyResourceDocument, SingleResourceDocument } from '@warp-drive/core-types/spec/raw'; /** > ⚠️ CAUTION you likely want the docs for [ Serializer](/ember-data/release/classes/%3CInterface%3E%20Serializer) @@ -265,7 +266,7 @@ export default class extends EmberObject { @param {Object} hash @return {Object} */ - normalize(_typeClass: ModelSchema, hash: Record): Record { - return hash; + normalize(_typeClass: ModelSchema, hash: Record): SingleResourceDocument | EmptyResourceDocument { + return hash as unknown as SingleResourceDocument; } } diff --git a/packages/serializer/src/json.js b/packages/serializer/src/json.ts similarity index 69% rename from packages/serializer/src/json.js rename to packages/serializer/src/json.ts index bd08ff5f04b..e9d357067af 100644 --- a/packages/serializer/src/json.js +++ b/packages/serializer/src/json.ts @@ -1,13 +1,22 @@ /** * @module @ember-data/serializer/json */ -import { getOwner } from '@ember/application'; import { assert, warn } from '@ember/debug'; +import { getOwner } from '@ember/owner'; import { dasherize } from '@ember/string'; import { singularize } from 'ember-inflector'; +import type { Snapshot } from '@ember-data/legacy-compat/-private'; +import type Store from '@ember-data/store'; +import type { ModelSchema } from '@ember-data/store/-types/q/ds-model'; +import type { JsonApiRelationship, JsonApiResource } from '@ember-data/store/-types/q/record-data-json-api'; +import type { ArrayValue, ObjectValue } from '@warp-drive/core-types/json/raw'; +import type { AttributeSchema } from '@warp-drive/core-types/schema'; +import type { EmptyResourceDocument, JsonApiDocument, SingleResourceDocument } from '@warp-drive/core-types/spec/raw'; + import Serializer from '.'; +import type { Transform } from './-private'; import { coerceId } from './-private'; const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; @@ -91,7 +100,7 @@ const PRIMARY_ATTRIBUTE_KEY = 'base'; @public @extends Serializer */ -const JSONSerializer = Serializer.extend({ +class JSONSerializer extends Serializer { /** The `primaryKey` is used when serializing and deserializing data. Ember Data always uses the `id` property to store the id of @@ -111,11 +120,11 @@ const JSONSerializer = Serializer.extend({ ``` @property primaryKey - @type {String} + @type {string} @public @default 'id' */ - primaryKey: 'id', + primaryKey = 'id'; /** The `attrs` object can be used to declare a simple mapping between @@ -182,9 +191,18 @@ const JSONSerializer = Serializer.extend({ @property attrs @public - @type {Object} + @type {object} */ - mergedProperties: ['attrs'], + declare attrs: Record< + string, + | string + | { + key: string; + serialize: boolean | 'id' | 'ids' | 'records'; + deserialize: 'records' | 'id' | 'ids'; + embedded?: 'always'; + } + >; /** Given a subclass of `Model` and a JSON object this method will @@ -195,25 +213,25 @@ const JSONSerializer = Serializer.extend({ @method applyTransforms @private - @param {Model} typeClass - @param {Object} data The data to transform - @return {Object} data The transformed data object + @param {ModelSchema} schema + @param {object} data The data to transform + @return {object} data The transformed data object */ - applyTransforms(typeClass, data) { - const attributes = typeClass.attributes; + applyTransforms(schema: ModelSchema, data: Record): Record { + const attributes = schema.attributes; - typeClass.eachTransformedAttribute((key, typeClass) => { + schema.eachTransformedAttribute((key, transformName) => { if (data[key] === undefined) { return; } - const transform = this.transformFor(typeClass); - const transformMeta = attributes.get(key); + const transform = this.transformFor(transformName); + const transformMeta = attributes.get(key)!; data[key] = transform.deserialize(data[key], transformMeta.options); }); return data; - }, + } /** The `normalizeResponse` method is used to normalize a payload from the @@ -225,7 +243,7 @@ const JSONSerializer = Serializer.extend({ the `requestType`. To override this method with a custom one, make sure to call - `return super.normalizeResponse(store, primaryModelClass, payload, id, requestType)` with your + `return super.normalizeResponse(store: Store, primarySchema: ModelSchema, payload, id, requestType)` with your pre-processed data. Here's an example of using `normalizeResponse` manually: @@ -233,9 +251,9 @@ const JSONSerializer = Serializer.extend({ ```javascript socket.on('message', function(message) { let data = message.data; - let modelClass = store.modelFor(data.modelName); + let schema = store.modelFor(data.modelName); let serializer = store.serializerFor(data.modelName); - let normalized = serializer.normalizeSingleResponse(store, modelClass, data, data.id); + let normalized = serializer.normalizeSingleResponse(store, schema, data, data.id); store.push(normalized); }); @@ -245,36 +263,52 @@ const JSONSerializer = Serializer.extend({ @method normalizeResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {string|null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeResponse(store, primaryModelClass, payload, id, requestType) { + normalizeResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: string | null, + requestType: + | 'findRecord' + | 'queryRecord' + | 'findAll' + | 'findBelongsTo' + | 'findHasMany' + | 'findMany' + | 'query' + | 'createRecord' + | 'deleteRecord' + | 'updateRecord' + ): JsonApiDocument { switch (requestType) { case 'findRecord': - return this.normalizeFindRecordResponse(...arguments); + return this.normalizeFindRecordResponse(store, primarySchema, payload, id as string, requestType); case 'queryRecord': - return this.normalizeQueryRecordResponse(...arguments); + return this.normalizeQueryRecordResponse(store, primarySchema, payload, id as null, requestType); case 'findAll': - return this.normalizeFindAllResponse(...arguments); + return this.normalizeFindAllResponse(store, primarySchema, payload, id as null, requestType); case 'findBelongsTo': - return this.normalizeFindBelongsToResponse(...arguments); + return this.normalizeFindBelongsToResponse(store, primarySchema, payload, id, requestType); case 'findHasMany': - return this.normalizeFindHasManyResponse(...arguments); + return this.normalizeFindHasManyResponse(store, primarySchema, payload, id, requestType); case 'findMany': - return this.normalizeFindManyResponse(...arguments); + return this.normalizeFindManyResponse(store, primarySchema, payload, id as null, requestType); case 'query': - return this.normalizeQueryResponse(...arguments); + return this.normalizeQueryResponse(store, primarySchema, payload, id as null, requestType); case 'createRecord': - return this.normalizeCreateRecordResponse(...arguments); + return this.normalizeCreateRecordResponse(store, primarySchema, payload, id, requestType); case 'deleteRecord': - return this.normalizeDeleteRecordResponse(...arguments); + return this.normalizeDeleteRecordResponse(store, primarySchema, payload, id as string, requestType); case 'updateRecord': - return this.normalizeUpdateRecordResponse(...arguments); + return this.normalizeUpdateRecordResponse(store, primarySchema, payload, id as string, requestType); } - }, + } /** Called by the default normalizeResponse implementation when the @@ -284,15 +318,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeFindRecordResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {string} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeFindRecordResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSingleResponse(...arguments); - }, + normalizeFindRecordResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: string, + requestType: 'findRecord' + ): JsonApiDocument { + return this.normalizeSingleResponse(store, primarySchema, payload, id, requestType); + } /** Called by the default normalizeResponse implementation when the @@ -302,15 +342,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeQueryRecordResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSingleResponse(...arguments); - }, + normalizeQueryRecordResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: null, + requestType: 'queryRecord' + ): JsonApiDocument { + return this.normalizeSingleResponse(store, primarySchema, payload, id, requestType); + } /** Called by the default normalizeResponse implementation when the @@ -320,15 +366,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeFindAllResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeFindAllResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeArrayResponse(...arguments); - }, + normalizeFindAllResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: null, + requestType: 'findAll' + ): JsonApiDocument { + return this.normalizeArrayResponse(store, primarySchema, payload, id, requestType); + } /** Called by the default normalizeResponse implementation when the @@ -338,15 +390,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeFindBelongsToResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {string|null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeFindBelongsToResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSingleResponse(...arguments); - }, + normalizeFindBelongsToResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: string | null, + requestType: 'findBelongsTo' + ): JsonApiDocument { + return this.normalizeSingleResponse(store, primarySchema, payload, id, requestType); + } /** Called by the default normalizeResponse implementation when the @@ -356,15 +414,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeFindHasManyResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {string|null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeFindHasManyResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeArrayResponse(...arguments); - }, + normalizeFindHasManyResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: string | null, + requestType: 'findHasMany' + ): JsonApiDocument { + return this.normalizeArrayResponse(store, primarySchema, payload, id, requestType); + } /** Called by the default normalizeResponse implementation when the @@ -374,15 +438,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeFindManyResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeFindManyResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeArrayResponse(...arguments); - }, + normalizeFindManyResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: null, + requestType: 'findMany' + ): JsonApiDocument { + return this.normalizeArrayResponse(store, primarySchema, payload, id, requestType); + } /** Called by the default normalizeResponse implementation when the @@ -392,15 +462,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeQueryResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeQueryResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeArrayResponse(...arguments); - }, + normalizeQueryResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: null, + requestType: 'query' + ): JsonApiDocument { + return this.normalizeArrayResponse(store, primarySchema, payload, id, requestType); + } /** Called by the default normalizeResponse implementation when the @@ -410,15 +486,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeCreateRecordResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {string|null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeCreateRecordResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSaveResponse(...arguments); - }, + normalizeCreateRecordResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: string | null, + requestType: 'createRecord' + ): JsonApiDocument { + return this.normalizeSaveResponse(store, primarySchema, payload, id, requestType); + } /** Called by the default normalizeResponse implementation when the @@ -428,15 +510,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeDeleteRecordResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {string} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeDeleteRecordResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSaveResponse(...arguments); - }, + normalizeDeleteRecordResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: string, + requestType: 'deleteRecord' + ): JsonApiDocument { + return this.normalizeSaveResponse(store, primarySchema, payload, id, requestType); + } /** Called by the default normalizeResponse implementation when the @@ -446,15 +534,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeUpdateRecordResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {string} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeUpdateRecordResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSaveResponse(...arguments); - }, + normalizeUpdateRecordResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: string, + requestType: 'updateRecord' + ): JsonApiDocument { + return this.normalizeSaveResponse(store, primarySchema, payload, id, requestType); + } /** normalizeUpdateRecordResponse, normalizeCreateRecordResponse and @@ -464,15 +558,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeSaveResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {string|null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeSaveResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSingleResponse(...arguments); - }, + normalizeSaveResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: string | null, + requestType: 'createRecord' | 'deleteRecord' | 'updateRecord' + ): JsonApiDocument { + return this.normalizeSingleResponse(store, primarySchema, payload, id, requestType); + } /** normalizeQueryResponse and normalizeFindRecordResponse delegate to this @@ -482,15 +582,21 @@ const JSONSerializer = Serializer.extend({ @method normalizeSingleResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {string|null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeSingleResponse(store, primaryModelClass, payload, id, requestType) { - return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, true); - }, + normalizeSingleResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: string | null, + requestType: 'findRecord' | 'queryRecord' | 'createRecord' | 'deleteRecord' | 'updateRecord' | 'findBelongsTo' + ): JsonApiDocument { + return this._normalizeResponse(store, primarySchema, payload, id, requestType, true); + } /** normalizeQueryResponse, normalizeFindManyResponse, and normalizeFindHasManyResponse delegate @@ -500,55 +606,79 @@ const JSONSerializer = Serializer.extend({ @method normalizeArrayResponse @public @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document + @param {ModelSchema} primarySchema + @param {object} payload + @param {string|null} id + @param {string} requestType + @return {object} JSON-API Document */ - normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) { - return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, false); - }, + normalizeArrayResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue, + id: string | null, + requestType: 'findHasMany' | 'findMany' | 'findAll' | 'query' + ): JsonApiDocument { + return this._normalizeResponse(store, primarySchema, payload, id, requestType, false); + } /** @method _normalizeResponse @param {Store} store - @param {Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType + @param {ModelSchema} primarySchema + @param {object} payload + @param {string|null} id + @param {string} requestType @param {Boolean} isSingle - @return {Object} JSON-API Document + @return {object} JSON-API Document @private */ - _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { + _normalizeResponse( + store: Store, + primarySchema: ModelSchema, + payload: ObjectValue | ObjectValue[], + id: string | null, + requestType: + | 'findHasMany' + | 'findMany' + | 'findAll' + | 'query' + | 'findRecord' + | 'queryRecord' + | 'createRecord' + | 'deleteRecord' + | 'updateRecord' + | 'findBelongsTo', + isSingle: boolean + ): JsonApiDocument { const documentHash = { data: null, included: [], - }; + } as JsonApiDocument; - const meta = this.extractMeta(store, primaryModelClass, payload); + const meta = this.extractMeta(store, primarySchema, payload); if (meta) { assert( 'The `meta` returned from `extractMeta` has to be an object, not "' + typeof meta + '".', - typeof meta === 'object' + typeof meta === 'object' && !Array.isArray(meta) ); documentHash.meta = meta; } if (isSingle) { - const { data, included } = this.normalize(primaryModelClass, payload); + const { data, included } = this.normalize(primarySchema, payload as ObjectValue); documentHash.data = data; if (included) { documentHash.included = included; } } else { + assert('Expected an array response', Array.isArray(payload)); const ret = new Array(payload.length); for (let i = 0, l = payload.length; i < l; i++) { - const item = payload[i]; - const { data, included } = this.normalize(primaryModelClass, item); + const item = payload[i]!; + const { data, included } = this.normalize(primarySchema, item); if (included) { - documentHash.included = documentHash.included.concat(included); + documentHash.included = documentHash.included!.concat(included); } ret[i] = data; } @@ -557,7 +687,7 @@ const JSONSerializer = Serializer.extend({ } return documentHash; - }, + } /** Normalizes a part of the JSON payload returned by @@ -579,8 +709,8 @@ const JSONSerializer = Serializer.extend({ import { get } from '@ember/object'; export default class ApplicationSerializer extends JSONSerializer { - normalize(typeClass, hash) { - let fields = typeClass.fields; + normalize(schema, hash) { + let fields = schema.fields; fields.forEach(function(type, field) { let payloadField = underscore(field); @@ -597,46 +727,51 @@ const JSONSerializer = Serializer.extend({ @method normalize @public - @param {Model} typeClass - @param {Object} hash - @return {Object} + @param {ModelSchema} schema + @param {object} hash + @return {object} */ - normalize(modelClass, resourceHash) { + override normalize(schema: ModelSchema, resourceHash: ObjectValue): SingleResourceDocument | EmptyResourceDocument { let data = null; if (resourceHash) { - this.normalizeUsingDeclaredMapping(modelClass, resourceHash); + this.normalizeUsingDeclaredMapping(schema, resourceHash); if (typeof resourceHash.links === 'object') { - this.normalizeUsingDeclaredMapping(modelClass, resourceHash.links); + this.normalizeUsingDeclaredMapping(schema, resourceHash.links); } data = { - id: this.extractId(modelClass, resourceHash), - type: modelClass.modelName, - attributes: this.extractAttributes(modelClass, resourceHash), - relationships: this.extractRelationships(modelClass, resourceHash), + id: this.extractId(schema, resourceHash), + type: schema.modelName, + attributes: this.extractAttributes(schema, resourceHash), + relationships: this.extractRelationships(schema, resourceHash), }; - this.applyTransforms(modelClass, data.attributes); + this.applyTransforms(schema, data.attributes); } return { data }; - }, + } /** Returns the resource's ID. @method extractId @public - @param {Object} modelClass - @param {Object} resourceHash - @return {String} + @param {object} schema + @param {object} resourceHash + @return {string} */ - extractId(modelClass, resourceHash) { + extractId(schema: ModelSchema, resourceHash: ObjectValue): string { const primaryKey = this.primaryKey; const id = resourceHash[primaryKey]; - return coerceId(id); - }, + const strId = coerceId(id as string | number | null | undefined); + assert( + `The id for the ${schema.modelName} model must be coercable to a string, but you passed ${typeof id}`, + typeof strId === 'string' + ); + return strId; + } /** Returns the resource's attributes formatted as a JSON-API "attributes object". @@ -645,15 +780,15 @@ const JSONSerializer = Serializer.extend({ @method extractAttributes @public - @param {Object} modelClass - @param {Object} resourceHash - @return {Object} + @param {object} schema + @param {object} resourceHash + @return {object} */ - extractAttributes(modelClass, resourceHash) { + extractAttributes(schema: ModelSchema, resourceHash: ObjectValue): ObjectValue { let attributeKey; - const attributes = {}; + const attributes: ObjectValue = {}; - modelClass.eachAttribute((key) => { + schema.eachAttribute((key) => { attributeKey = this.keyForAttribute(key, 'deserialize'); if (resourceHash[attributeKey] !== undefined) { attributes[key] = resourceHash[attributeKey]; @@ -661,7 +796,7 @@ const JSONSerializer = Serializer.extend({ }); return attributes; - }, + } /** Returns a relationship formatted as a JSON-API "relationship object". @@ -670,11 +805,11 @@ const JSONSerializer = Serializer.extend({ @method extractRelationship @public - @param {Object} relationshipModelName - @param {Object} relationshipHash - @return {Object} + @param {object} relationshipModelName + @param {object} relationshipHash + @return {object} */ - extractRelationship(relationshipModelName, relationshipHash) { + extractRelationship(relationshipModelName: string, relationshipHash: ObjectValue): JsonApiRelationship | null { if (!relationshipHash) { return null; } @@ -688,15 +823,15 @@ const JSONSerializer = Serializer.extend({ relationshipHash.id = coerceId(relationshipHash.id); } - const modelClass = this.store.modelFor(relationshipModelName); - if (relationshipHash.type && !modelClass.fields.has('type')) { + const schema = this.store.modelFor(relationshipModelName); + if (relationshipHash.type && !schema.fields.has('type')) { relationshipHash.type = this.modelNameFromPayloadKey(relationshipHash.type); } return relationshipHash; } return { id: coerceId(relationshipHash), type: dasherize(singularize(relationshipModelName)) }; - }, + } /** Returns a polymorphic relationship formatted as a JSON-API "relationship object". @@ -713,14 +848,14 @@ const JSONSerializer = Serializer.extend({ @method extractPolymorphicRelationship @public - @param {Object} relationshipModelName - @param {Object} relationshipHash - @param {Object} relationshipOptions - @return {Object} + @param {object} relationshipModelName + @param {object} relationshipHash + @param {object} relationshipOptions + @return {object} */ - extractPolymorphicRelationship(relationshipModelName, relationshipHash, relationshipOptions) { + extractPolymorphicRelationship(relationshipModelName: string, relationshipHash, relationshipOptions) { return this.extractRelationship(relationshipModelName, relationshipHash); - }, + } /** Returns the resource's relationships formatted as a JSON-API "relationships object". @@ -729,14 +864,14 @@ const JSONSerializer = Serializer.extend({ @method extractRelationships @public - @param {Object} modelClass - @param {Object} resourceHash - @return {Object} + @param {object} schema + @param {object} resourceHash + @return {object} */ - extractRelationships(modelClass, resourceHash) { + extractRelationships(schema: ModelSchema, resourceHash: ObjectValue): JsonApiResource['relationships'] { const relationships = {}; - modelClass.eachRelationship((key, relationshipMeta) => { + schema.eachRelationship((key, relationshipMeta) => { let relationship = null; const relationshipKey = this.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); if (resourceHash[relationshipKey] !== undefined) { @@ -792,29 +927,29 @@ const JSONSerializer = Serializer.extend({ }); return relationships; - }, + } /** Dasherizes the model name in the payload @method modelNameFromPayloadKey @public - @param {String} key - @return {String} the model's modelName + @param {string} key + @return {string} the model's modelName */ - modelNameFromPayloadKey(key) { + modelNameFromPayloadKey(key: string): string { return dasherize(singularize(key)); - }, + } /** @method normalizeRelationships @private */ - normalizeRelationships(typeClass, hash) { + normalizeRelationships(schema: ModelSchema, hash: ObjectValue) { let payloadKey; if (this.keyForRelationship) { - typeClass.eachRelationship((key, relationship) => { + schema.eachRelationship((key, relationship) => { payloadKey = this.keyForRelationship(key, relationship.kind, 'deserialize'); if (key === payloadKey) { return; @@ -827,31 +962,31 @@ const JSONSerializer = Serializer.extend({ delete hash[payloadKey]; }); } - }, + } /** @method normalizeUsingDeclaredMapping @private */ - normalizeUsingDeclaredMapping(modelClass, hash) { + normalizeUsingDeclaredMapping(schema: ModelSchema, hash: ObjectValue) { const attrs = this.attrs; let normalizedKey; let payloadKey; if (attrs) { for (const key in attrs) { - normalizedKey = payloadKey = this._getMappedKey(key, modelClass); + normalizedKey = payloadKey = this._getMappedKey(key, schema); if (hash[payloadKey] === undefined) { continue; } - if (modelClass.attributes.has(key)) { + if (schema.attributes.has(key)) { normalizedKey = this.keyForAttribute(key, 'deserialize'); } - if (modelClass.relationshipsByName.has(key)) { - normalizedKey = this.keyForRelationship(key, modelClass, 'deserialize'); + if (schema.relationshipsByName.has(key)) { + normalizedKey = this.keyForRelationship(key, schema, 'deserialize'); } if (payloadKey !== normalizedKey) { @@ -860,7 +995,7 @@ const JSONSerializer = Serializer.extend({ } } } - }, + } /** Looks up the property key that was set by the custom `attr` mapping @@ -868,29 +1003,28 @@ const JSONSerializer = Serializer.extend({ @method _getMappedKey @private - @param {String} key - @return {String} key + @param {string} key + @return {string} key */ - _getMappedKey(key, modelClass) { + _getMappedKey(key: string, schema: ModelSchema): string { warn( 'There is no attribute or relationship with the name `' + key + '` on `' + - modelClass.modelName + + schema.modelName + '`. Check your serializers attrs hash.', - modelClass.attributes.has(key) || modelClass.relationshipsByName.has(key), + schema.attributes.has(key) || schema.relationshipsByName.has(key), { id: 'ds.serializer.no-mapped-attrs-key', } ); const attrs = this.attrs; - let mappedKey; if (attrs && attrs[key]) { - mappedKey = attrs[key]; + let mappedKey = attrs[key]; //We need to account for both the { title: 'post_title' } and //{ title: { key: 'post_title' }} forms - if (mappedKey.key) { + if (typeof mappedKey !== 'string' && mappedKey.key) { mappedKey = mappedKey.key; } if (typeof mappedKey === 'string') { @@ -899,7 +1033,7 @@ const JSONSerializer = Serializer.extend({ } return key; - }, + } /** Check attrs.key.serialize property to inform if the `key` @@ -907,14 +1041,18 @@ const JSONSerializer = Serializer.extend({ @method _canSerialize @private - @param {String} key + @param {string} key @return {boolean} true if the key can be serialized */ - _canSerialize(key) { + _canSerialize(key: string): boolean { const attrs = this.attrs; - return !attrs || !attrs[key] || attrs[key].serialize !== false; - }, + return ( + !attrs || + !attrs[key] || + (typeof attrs[key] !== 'string' && (attrs[key] as { serialize: boolean | string }).serialize !== false) + ); + } /** When attrs.key.serialize is set to true then @@ -923,14 +1061,14 @@ const JSONSerializer = Serializer.extend({ @method _mustSerialize @private - @param {String} key + @param {string} key @return {boolean} true if the key must be serialized */ - _mustSerialize(key) { + _mustSerialize(key: string) { const attrs = this.attrs; return attrs && attrs[key] && attrs[key].serialize === true; - }, + } /** Check if the given hasMany relationship should be serialized @@ -941,18 +1079,18 @@ const JSONSerializer = Serializer.extend({ @method shouldSerializeHasMany @public @param {Snapshot} snapshot - @param {String} key + @param {string} key @param {RelationshipSchema} relationship @return {boolean} true if the hasMany relationship should be serialized */ - shouldSerializeHasMany(snapshot, key, relationship) { + shouldSerializeHasMany(snapshot: Snapshot, key: string, relationship) { const schema = this.store.modelFor(snapshot.modelName); const relationshipType = schema.determineRelationshipType(relationship, this.store); if (this._mustSerialize(key)) { return true; } return this._canSerialize(key) && (relationshipType === 'manyToNone' || relationshipType === 'manyToMany'); - }, + } // SERIALIZE /** @@ -1105,11 +1243,11 @@ const JSONSerializer = Serializer.extend({ @method serialize @public @param {Snapshot} snapshot - @param {Object} options - @return {Object} json + @param {object} options + @return {object} json */ - serialize(snapshot, options) { - const json = {}; + serialize(snapshot: Snapshot, options?: { includeId: boolean }): ObjectValue { + const json: ObjectValue = {}; if (options && options.includeId) { const id = snapshot.id; @@ -1131,7 +1269,7 @@ const JSONSerializer = Serializer.extend({ }); return json; - }, + } /** You can use this method to customize how a serialized record is added to the complete @@ -1157,14 +1295,14 @@ const JSONSerializer = Serializer.extend({ @method serializeIntoHash @public - @param {Object} hash - @param {Model} typeClass + @param {object} hash + @param {ModelSchema} schema @param {Snapshot} snapshot - @param {Object} options + @param {object} options */ - serializeIntoHash(hash, typeClass, snapshot, options) { + serializeIntoHash(hash: ObjectValue, schema: ModelSchema, snapshot: Snapshot, options?: { includeId: boolean }) { Object.assign(hash, this.serialize(snapshot, options)); - }, + } /** `serializeAttribute` can be used to customize how `attr` @@ -1188,11 +1326,11 @@ const JSONSerializer = Serializer.extend({ @method serializeAttribute @public @param {Snapshot} snapshot - @param {Object} json - @param {String} key - @param {Object} attribute + @param {object} json + @param {string} key + @param {object} attribute */ - serializeAttribute(snapshot, json, key, attribute) { + serializeAttribute(snapshot: Snapshot, json: ObjectValue, key: string, attribute: AttributeSchema) { if (this._canSerialize(key)) { const type = attribute.type; let value = snapshot.attr(key); @@ -1212,7 +1350,7 @@ const JSONSerializer = Serializer.extend({ json[payloadKey] = value; } - }, + } /** `serializeBelongsTo` can be used to customize how `belongsTo` @@ -1238,10 +1376,10 @@ const JSONSerializer = Serializer.extend({ @method serializeBelongsTo @public @param {Snapshot} snapshot - @param {Object} json - @param {Object} relationship + @param {object} json + @param {object} relationship */ - serializeBelongsTo(snapshot, json, relationship) { + serializeBelongsTo(snapshot: Snapshot, json: ObjectValue, relationship) { const name = relationship.name; if (this._canSerialize(name)) { @@ -1266,7 +1404,7 @@ const JSONSerializer = Serializer.extend({ this.serializePolymorphicType(snapshot, json, relationship); } } - }, + } /** `serializeHasMany` can be used to customize how `hasMany` @@ -1292,10 +1430,10 @@ const JSONSerializer = Serializer.extend({ @method serializeHasMany @public @param {Snapshot} snapshot - @param {Object} json - @param {Object} relationship + @param {object} json + @param {object} relationship */ - serializeHasMany(snapshot, json, relationship) { + serializeHasMany(snapshot: Snapshot, json: ObjectValue, relationship) { const name = relationship.name; if (this.shouldSerializeHasMany(snapshot, name, relationship)) { @@ -1313,7 +1451,7 @@ const JSONSerializer = Serializer.extend({ // TODO support for polymorphic manyToNone and manyToMany relationships } } - }, + } /** You can use this method to customize how polymorphic objects are @@ -1345,10 +1483,10 @@ const JSONSerializer = Serializer.extend({ @method serializePolymorphicType @public @param {Snapshot} snapshot - @param {Object} json - @param {Object} relationship + @param {object} json + @param {object} relationship */ - serializePolymorphicType() {}, + serializePolymorphicType() {} /** `extractMeta` is used to deserialize any meta information in the @@ -1361,7 +1499,7 @@ const JSONSerializer = Serializer.extend({ import JSONSerializer from '@ember-data/serializer/json'; export default class PostSerializer extends JSONSerializer { - extractMeta(store, typeClass, payload) { + extractMeta(store, schema, payload) { if (payload && payload.hasOwnProperty('_pagination')) { let meta = payload._pagination; delete payload._pagination; @@ -1374,16 +1512,19 @@ const JSONSerializer = Serializer.extend({ @method extractMeta @public @param {Store} store - @param {Model} modelClass - @param {Object} payload + @param {ModelSchema} schema + @param {object} payload */ - extractMeta(store, modelClass, payload) { + extractMeta(store: Store, schema: ModelSchema, payload: ObjectValue | ArrayValue) { + if (Array.isArray(payload)) { + return; + } if (payload && payload['meta'] !== undefined) { const meta = payload.meta; delete payload.meta; return meta; } - }, + } /** `extractErrors` is used to extract model errors when a call @@ -1453,10 +1594,10 @@ const JSONSerializer = Serializer.extend({ import JSONSerializer from '@ember-data/serializer/json'; export default class PostSerializer extends JSONSerializer { - extractErrors(store, typeClass, payload, id) { + extractErrors(store, schema, payload, id) { if (payload && typeof payload === 'object' && payload._problems) { payload = payload._problems; - this.normalizeErrors(typeClass, payload); + this.normalizeErrors(schema, payload); } return payload; } @@ -1466,12 +1607,12 @@ const JSONSerializer = Serializer.extend({ @method extractErrors @public @param {Store} store - @param {Model} typeClass - @param {Object} payload - @param {(String|Number)} id - @return {Object} json The deserialized errors + @param {ModelSchema} schema + @param {object} payload + @param {string|null} id + @return {object} json The deserialized errors */ - extractErrors(store, typeClass, payload, id) { + extractErrors(store: Store, schema: ModelSchema, payload: ObjectValue, id: string | null) { if (payload && typeof payload === 'object' && payload.errors) { // the default assumption is that errors is already in JSON:API format const extracted = {}; @@ -1494,11 +1635,11 @@ const JSONSerializer = Serializer.extend({ }); // if the user has an attrs hash, convert keys using it - this.normalizeUsingDeclaredMapping(typeClass, extracted); + this.normalizeUsingDeclaredMapping(schema, extracted); // for each attr and relationship, make sure that we use // the normalized key - typeClass.eachAttribute((name) => { + schema.eachAttribute((name) => { const key = this.keyForAttribute(name, 'deserialize'); if (key !== name && extracted[key] !== undefined) { extracted[name] = extracted[key]; @@ -1506,7 +1647,7 @@ const JSONSerializer = Serializer.extend({ } }); - typeClass.eachRelationship((name) => { + schema.eachRelationship((name) => { const key = this.keyForRelationship(name, 'deserialize'); if (key !== name && extracted[key] !== undefined) { extracted[name] = extracted[key]; @@ -1518,7 +1659,7 @@ const JSONSerializer = Serializer.extend({ } return payload; - }, + } /** `keyForAttribute` can be used to define rules for how to convert an @@ -1539,13 +1680,13 @@ const JSONSerializer = Serializer.extend({ @method keyForAttribute @public - @param {String} key - @param {String} method - @return {String} normalized key + @param {string} key + @param {string} method + @return {string} normalized key */ - keyForAttribute(key, method) { + keyForAttribute(key: string, method) { return key; - }, + } /** `keyForRelationship` can be used to define a custom key when @@ -1567,14 +1708,14 @@ const JSONSerializer = Serializer.extend({ @method keyForRelationship @public - @param {String} key - @param {String} typeClass - @param {String} method - @return {String} normalized key + @param {string} key + @param {ModelSchema} schema + @param {string} method + @return {string} normalized key */ - keyForRelationship(key, typeClass, method) { + keyForRelationship(key: string, schema: ModelSchema, method): string { return key; - }, + } /** `keyForLink` can be used to define a custom key when deserializing link @@ -1582,30 +1723,31 @@ const JSONSerializer = Serializer.extend({ @method keyForLink @public - @param {String} key - @param {String} kind `belongsTo` or `hasMany` - @return {String} normalized key + @param {string} key + @param {string} kind `belongsTo` or `hasMany` + @return {string} normalized key */ - keyForLink(key, kind) { + keyForLink(key: string, kind: 'belongsTo' | 'hasMany'): string { return key; - }, + } // HELPERS /** @method transformFor @private - @param {String} attributeType + @param {string} transformName @param {Boolean} skipAssertion @return {Transform} transform */ - transformFor(attributeType, skipAssertion) { - const transform = getOwner(this).lookup('transform:' + attributeType); + transformFor(transformName: string, skipAssertion?: boolean): Transform { + const transform = getOwner(this)!.lookup(`transform:${transformName}`) as Transform; - assert(`Unable to find the transform for \`attr('${attributeType}')\``, skipAssertion || !!transform); + assert(`Unable to find the transform for \`attr('${transformName}')\``, skipAssertion || !!transform); return transform; - }, -}); + } +} +JSONSerializer.prototype.mergedProperties = ['attrs']; export default JSONSerializer; diff --git a/packages/serializer/src/rest.js b/packages/serializer/src/rest.ts similarity index 91% rename from packages/serializer/src/rest.js rename to packages/serializer/src/rest.ts index c2ee688964c..9eea55b0753 100644 --- a/packages/serializer/src/rest.js +++ b/packages/serializer/src/rest.ts @@ -7,11 +7,15 @@ import { camelize, dasherize } from '@ember/string'; import { singularize } from 'ember-inflector'; import { DEBUG } from '@ember-data/env'; +import type { Snapshot } from '@ember-data/legacy-compat/-private'; +import { upgradeStore } from '@ember-data/legacy-compat/-private'; +import type Store from '@ember-data/store'; +import type { ModelSchema } from '@ember-data/store/-types/q/ds-model'; import { coerceId } from './-private'; import JSONSerializer from './json'; -function makeArray(value) { +function makeArray(value: T | T[]): T[] { return Array.isArray(value) ? value : [value]; } @@ -67,7 +71,7 @@ function makeArray(value) { @public @extends JSONSerializer */ -const RESTSerializer = JSONSerializer.extend({ +class RESTSerializer extends JSONSerializer { /** `keyForPolymorphicType` can be used to define a custom key when serializing and deserializing a polymorphic type. By default, the @@ -94,11 +98,11 @@ const RESTSerializer = JSONSerializer.extend({ @param {String} method @return {String} normalized key */ - keyForPolymorphicType(key, typeClass, method) { + keyForPolymorphicType(key: string, typeClass: ModelSchema, method: unknown): string { const relationshipKey = this.keyForRelationship(key); return `${relationshipKey}Type`; - }, + } /** Normalizes a part of the JSON payload returned by @@ -180,7 +184,8 @@ const RESTSerializer = JSONSerializer.extend({ @return {Object} @private */ - _normalizeArray(store, modelName, arrayHash, prop) { + _normalizeArray(store: Store, modelName: string, arrayHash: object | object[], prop: string) { + upgradeStore(store); const documentHash = { data: [], included: [], @@ -198,9 +203,10 @@ const RESTSerializer = JSONSerializer.extend({ }); return documentHash; - }, + } - _normalizePolymorphicRecord(store, hash, prop, primaryModelClass, primarySerializer) { + _normalizePolymorphicRecord(store: Store, hash, prop, primaryModelClass: ModelSchema, primarySerializer) { + upgradeStore(store); let serializer = primarySerializer; let modelClass = primaryModelClass; @@ -217,7 +223,7 @@ const RESTSerializer = JSONSerializer.extend({ } return serializer.normalize(modelClass, hash, prop); - }, + } /** @method _normalizeResponse @@ -230,7 +236,7 @@ const RESTSerializer = JSONSerializer.extend({ @return {Object} JSON-API Document @private */ - _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { + _normalizeResponse(store: Store, primaryModelClass: ModelSchema, payload, id, requestType, isSingle) { const documentHash = { data: null, included: [], @@ -247,10 +253,10 @@ const RESTSerializer = JSONSerializer.extend({ const keys = Object.keys(payload); - for (var i = 0, length = keys.length; i < length; i++) { - var prop = keys[i]; - var modelName = prop; - var forcedSecondary = false; + for (let i = 0, length = keys.length; i < length; i++) { + const prop = keys[i]; + let modelName = prop; + let forcedSecondary = false; /* If you want to provide sideloaded records of the same type that the @@ -277,7 +283,7 @@ const RESTSerializer = JSONSerializer.extend({ modelName = prop.substr(1); } - var typeName = this.modelNameFromPayloadKey(modelName); + const typeName = this.modelNameFromPayloadKey(modelName); if (!store.getSchemaDefinitionService().doesTypeExist(typeName)) { warn(this.warnMessageNoModelForKey(modelName, typeName), false, { id: 'ds.serializer.model-for-key-missing', @@ -285,8 +291,8 @@ const RESTSerializer = JSONSerializer.extend({ continue; } - var isPrimary = !forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass); - var value = payload[prop]; + const isPrimary = !forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass); + const value = payload[prop]; if (value === null) { continue; @@ -355,11 +361,11 @@ const RESTSerializer = JSONSerializer.extend({ } return documentHash; - }, + } - isPrimaryType(store, modelName, primaryModelClass) { + isPrimaryType(store: Store, modelName: string, primaryModelClass: ModelSchema) { return dasherize(modelName) === primaryModelClass.modelName; - }, + } /** This method allows you to push a payload containing top-level @@ -393,22 +399,22 @@ const RESTSerializer = JSONSerializer.extend({ @param {Store} store @param {Object} payload */ - pushPayload(store, payload) { + pushPayload(store: Store, payload: object) { const documentHash = { data: [], included: [], }; - for (var prop in payload) { - var modelName = this.modelNameFromPayloadKey(prop); + for (const prop in payload) { + const modelName = this.modelNameFromPayloadKey(prop); if (!store.getSchemaDefinitionService().doesTypeExist(modelName)) { warn(this.warnMessageNoModelForKey(prop, modelName), false, { id: 'ds.serializer.model-for-key-missing', }); continue; } - var type = store.modelFor(modelName); - var typeSerializer = store.serializerFor(type.modelName); + const type = store.modelFor(modelName); + const typeSerializer = store.serializerFor(type.modelName); makeArray(payload[prop]).forEach((hash) => { const { data, included } = typeSerializer.normalize(type, hash, prop); @@ -420,7 +426,7 @@ const RESTSerializer = JSONSerializer.extend({ } store.push(documentHash); - }, + } /** This method is used to convert each JSON root key in the payload @@ -480,9 +486,9 @@ const RESTSerializer = JSONSerializer.extend({ @param {String} key @return {String} the model's modelName */ - modelNameFromPayloadKey(key) { + override modelNameFromPayloadKey(key: string): string { return dasherize(singularize(key)); - }, + } // SERIALIZE @@ -639,9 +645,6 @@ const RESTSerializer = JSONSerializer.extend({ @param {Object} options @return {Object} json */ - serialize(snapshot, options) { - return this._super(...arguments); - }, /** You can use this method to customize the root keys serialized into the JSON. @@ -670,10 +673,10 @@ const RESTSerializer = JSONSerializer.extend({ @param {Snapshot} snapshot @param {Object} options */ - serializeIntoHash(hash, typeClass, snapshot, options) { + override serializeIntoHash(hash, typeClass: ModelSchema, snapshot: Snapshot, options) { const normalizedRootKey = this.payloadKeyFromModelName(typeClass.modelName); hash[normalizedRootKey] = this.serialize(snapshot, options); - }, + } /** You can use `payloadKeyFromModelName` to override the root key for an outgoing @@ -722,9 +725,9 @@ const RESTSerializer = JSONSerializer.extend({ @param {String} modelName @return {String} */ - payloadKeyFromModelName(modelName) { + payloadKeyFromModelName(modelName: string): string { return camelize(modelName); - }, + } /** You can use this method to customize how polymorphic objects are serialized. @@ -747,7 +750,7 @@ const RESTSerializer = JSONSerializer.extend({ } else { json[typeKey] = camelize(belongsTo.modelName); } - }, + } /** You can use this method to customize how a polymorphic relationship should @@ -791,26 +794,24 @@ const RESTSerializer = JSONSerializer.extend({ }; } - return this._super(...arguments); - }, -}); + return super.extractPolymorphicRelationship(...arguments); + } +} if (DEBUG) { - RESTSerializer.reopen({ - warnMessageNoModelForKey(prop, typeKey) { - return ( - 'Encountered "' + - prop + - '" in payload, but no model was found for model name "' + - typeKey + - '" (resolved model name using ' + - this.constructor.toString() + - '.modelNameFromPayloadKey("' + - prop + - '"))' - ); - }, - }); + RESTSerializer.prototype.warnMessageNoModelForKey = function (prop: string, typeKey: string) { + return ( + 'Encountered "' + + prop + + '" in payload, but no model was found for model name "' + + typeKey + + '" (resolved model name using ' + + this.constructor.toString() + + '.modelNameFromPayloadKey("' + + prop + + '"))' + ); + }; } export { EmbeddedRecordsMixin } from './-private'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 87a06c89f2e..ebfe9009d3e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -167,7 +167,7 @@ importers: version: file:packages/request-utils(@babel/core@7.23.9)(@warp-drive/core-types@0.0.0-alpha.21) '@ember-data/serializer': specifier: workspace:5.4.0-alpha.35 - version: file:packages/serializer(@babel/core@7.23.9)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) + version: file:packages/serializer(@babel/core@7.23.9)(@ember-data/legacy-compat@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) '@ember-data/store': specifier: workspace:5.4.0-alpha.35 version: file:packages/store(@babel/core@7.23.9)(@ember-data/request@5.4.0-alpha.35)(@ember-data/tracking@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21) @@ -1775,6 +1775,9 @@ importers: '@babel/runtime': specifier: ^7.23.9 version: 7.23.9 + '@ember-data/legacy-compat': + specifier: workspace:5.4.0-alpha.35 + version: file:packages/legacy-compat(@babel/core@7.23.9)(@ember-data/graph@5.4.0-alpha.35)(@ember-data/json-api@5.4.0-alpha.35)(@ember-data/request@5.4.0-alpha.35)(@ember-data/store@5.4.0-alpha.35)(@warp-drive/core-types@0.0.0-alpha.21) '@ember-data/request': specifier: workspace:5.4.0-alpha.35 version: file:packages/request(@babel/core@7.23.9)(@warp-drive/core-types@0.0.0-alpha.21) @@ -1824,6 +1827,8 @@ importers: specifier: ^5.89.0 version: 5.89.0 dependenciesMeta: + '@ember-data/legacy-compat': + injected: true '@ember-data/private-build-infra': injected: true '@ember-data/request': @@ -2206,7 +2211,7 @@ importers: version: file:packages/request-utils(@babel/core@7.23.9)(@warp-drive/core-types@0.0.0-alpha.21) '@ember-data/serializer': specifier: workspace:5.4.0-alpha.35 - version: file:packages/serializer(@babel/core@7.23.9)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) + version: file:packages/serializer(@babel/core@7.23.9)(@ember-data/legacy-compat@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) '@ember-data/store': specifier: workspace:5.4.0-alpha.35 version: file:packages/store(@babel/core@7.23.9)(@ember-data/request@5.4.0-alpha.35)(@ember-data/tracking@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21) @@ -2502,7 +2507,7 @@ importers: version: file:packages/request-utils(@babel/core@7.23.9)(@warp-drive/core-types@0.0.0-alpha.21) '@ember-data/serializer': specifier: workspace:5.4.0-alpha.35 - version: file:packages/serializer(@babel/core@7.23.9)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) + version: file:packages/serializer(@babel/core@7.23.9)(@ember-data/legacy-compat@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) '@ember-data/store': specifier: workspace:5.4.0-alpha.35 version: file:packages/store(@babel/core@7.23.9)(@ember-data/request@5.4.0-alpha.35)(@ember-data/tracking@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21) @@ -2988,7 +2993,7 @@ importers: version: file:packages/request-utils(@babel/core@7.23.9)(@warp-drive/core-types@0.0.0-alpha.21) '@ember-data/serializer': specifier: workspace:5.4.0-alpha.35 - version: file:packages/serializer(@babel/core@7.23.9)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) + version: file:packages/serializer(@babel/core@7.23.9)(@ember-data/legacy-compat@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) '@ember-data/store': specifier: workspace:5.4.0-alpha.35 version: file:packages/store(@babel/core@7.23.9)(@ember-data/request@5.4.0-alpha.35)(@ember-data/tracking@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21) @@ -3722,7 +3727,7 @@ importers: version: file:packages/request-utils(@babel/core@7.23.9)(@warp-drive/core-types@0.0.0-alpha.21) '@ember-data/serializer': specifier: workspace:5.4.0-alpha.35 - version: file:packages/serializer(@babel/core@7.23.9)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) + version: file:packages/serializer(@babel/core@7.23.9)(@ember-data/legacy-compat@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) '@ember-data/store': specifier: workspace:5.4.0-alpha.35 version: file:packages/store(@babel/core@7.23.9)(@ember-data/request@5.4.0-alpha.35)(@ember-data/tracking@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21) @@ -18731,7 +18736,7 @@ packages: '@ember-data/private-build-infra': file:packages/private-build-infra '@ember-data/request': file:packages/request(@babel/core@7.23.9)(@warp-drive/core-types@0.0.0-alpha.21) '@ember-data/request-utils': file:packages/request-utils(@babel/core@7.23.9)(@warp-drive/core-types@0.0.0-alpha.21) - '@ember-data/serializer': file:packages/serializer(@babel/core@7.23.9)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) + '@ember-data/serializer': file:packages/serializer(@babel/core@7.23.9)(@ember-data/legacy-compat@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2) '@ember-data/store': file:packages/store(@babel/core@7.23.9)(@ember-data/request@5.4.0-alpha.35)(@ember-data/tracking@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21) '@ember-data/tracking': file:packages/tracking(@babel/core@7.23.9)(ember-source@5.6.0) '@ember/edition-utils': 1.2.0 @@ -19155,17 +19160,19 @@ packages: - supports-color dev: true - file:packages/serializer(@babel/core@7.23.9)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2): + file:packages/serializer(@babel/core@7.23.9)(@ember-data/legacy-compat@5.4.0-alpha.35)(@ember/string@3.1.1)(@warp-drive/core-types@0.0.0-alpha.21)(ember-inflector@4.0.2): resolution: {directory: packages/serializer, type: directory} id: file:packages/serializer name: '@ember-data/serializer' version: 5.4.0-alpha.35 engines: {node: '>= 18.19.1'} peerDependencies: + '@ember-data/legacy-compat': workspace:5.4.0-alpha.35 '@ember/string': ^3.1.1 '@warp-drive/core-types': workspace:0.0.0-alpha.21 ember-inflector: ^4.0.2 dependencies: + '@ember-data/legacy-compat': file:packages/legacy-compat(@babel/core@7.23.9)(@ember-data/graph@5.4.0-alpha.35)(@ember-data/json-api@5.4.0-alpha.35)(@ember-data/request@5.4.0-alpha.35)(@ember-data/store@5.4.0-alpha.35)(@warp-drive/core-types@0.0.0-alpha.21) '@ember-data/private-build-infra': file:packages/private-build-infra '@ember/string': 3.1.1(@babel/core@7.23.9) '@embroider/macros': 1.13.4(@babel/core@7.23.9)