Skip to content

Commit

Permalink
[FEAT serializers] clean up packages organization (emberjs#6086)
Browse files Browse the repository at this point in the history
  • Loading branch information
runspired authored Aug 22, 2019
1 parent 5580f40 commit d10bbc0
Show file tree
Hide file tree
Showing 17 changed files with 176 additions and 64 deletions.
57 changes: 19 additions & 38 deletions packages/-ember-data/addon/setup-container.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
import { DebugAdapter } from './-private';
import Store from '@ember-data/store';
import JSONAPISerializer from '@ember-data/serializer/json-api';
import JSONSerializer from '@ember-data/serializer/json';
import RESTSerializer from '@ember-data/serializer/rest';
import JSONAPIAdapter from '@ember-data/adapter/json-api';

import { BooleanTransform, DateTransform, NumberTransform, StringTransform } from '@ember-data/serializer/-private';

function has(applicationOrRegistry, fullName) {
if (applicationOrRegistry.has) {
// < 2.1.0
return applicationOrRegistry.has(fullName);
} else {
// 2.1.0+
return applicationOrRegistry.hasRegistration(fullName);
function hasRegistration(application, registrationName) {
// fallback our ember-data tests necessary
// until we kill-off setupStore
// see https://github.com/emberjs/data/issues/6357
// or @ember/test-helpers kills off it's
// legacy support that calls our initializer with registry
// instead of application
if (typeof application.hasRegistration !== 'function') {
return application.has(registrationName);
}
return application.hasRegistration(registrationName);
}

/*
Configures a registry for use with an Ember-Data
store. Accepts an optional namespace argument.
@method initializeStore
@param {Ember.Registry} registry
*/
function initializeStore(registry) {
let registerOptionsForType = registry.registerOptionsForType || registry.optionsForType;
registerOptionsForType.call(registry, 'serializer', { singleton: false });
registerOptionsForType.call(registry, 'adapter', { singleton: false });
registry.register('serializer:-default', JSONSerializer);
registry.register('serializer:-rest', RESTSerializer);
function initializeStore(application) {
// we can just use registerOptionsForType when setupStore is killed
// see https://github.com/emberjs/data/issues/6357
let registerOptionsForType = application.registerOptionsForType || application.optionsForType;
registerOptionsForType.call(application, 'serializer', { singleton: false });
registerOptionsForType.call(application, 'adapter', { singleton: false });

registry.register('adapter:-json-api', JSONAPIAdapter);
registry.register('serializer:-json-api', JSONAPISerializer);
application.register('adapter:-json-api', JSONAPIAdapter);

if (!has(registry, 'service:store')) {
registry.register('service:store', Store);
if (!hasRegistration(application, 'service:store')) {
application.register('service:store', Store);
}
}

Expand Down Expand Up @@ -66,23 +62,8 @@ function initializeStoreInjections(registry) {
inject.call(registry, 'data-adapter', 'store', 'service:store');
}

/*
Configures a registry for use with Ember-Data
transforms.
@method initializeTransforms
@param {Ember.Registry} registry
*/
function initializeTransforms(registry) {
registry.register('transform:boolean', BooleanTransform);
registry.register('transform:date', DateTransform);
registry.register('transform:number', NumberTransform);
registry.register('transform:string', StringTransform);
}

export default function setupContainer(application) {
initializeDataAdapter(application);
initializeTransforms(application);
initializeStoreInjections(application);
initializeStore(application);
}
1 change: 1 addition & 0 deletions packages/-ember-data/app/serializers/-default.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from '@ember-data/serializer/json';
1 change: 1 addition & 0 deletions packages/-ember-data/app/serializers/-json-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from '@ember-data/serializer/json-api';
1 change: 1 addition & 0 deletions packages/-ember-data/app/serializers/-rest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from '@ember-data/serializer/rest';
1 change: 1 addition & 0 deletions packages/-ember-data/app/transforms/boolean.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { BooleanTransform as default } from '@ember-data/serializer/-private';
1 change: 1 addition & 0 deletions packages/-ember-data/app/transforms/date.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DateTransform as default } from '@ember-data/serializer/-private';
1 change: 1 addition & 0 deletions packages/-ember-data/app/transforms/number.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { NumberTransform as default } from '@ember-data/serializer/-private';
1 change: 1 addition & 0 deletions packages/-ember-data/app/transforms/string.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { StringTransform as default } from '@ember-data/serializer/-private';
11 changes: 11 additions & 0 deletions packages/-ember-data/tests/helpers/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import JSONAPISerializer from '@ember-data/serializer/json-api';
import RESTSerializer from '@ember-data/serializer/rest';
import config from '../../config/environment';
import Resolver from '../../resolver';
import { StringTransform, DateTransform, NumberTransform, BooleanTransform } from '@ember-data/serializer/-private';

const { _RegistryProxyMixin, _ContainerProxyMixin, Registry } = Ember;

Expand Down Expand Up @@ -68,6 +69,12 @@ export default function setupStore(options) {
registry.register('model:' + dasherize(prop), options[prop]);
}

// avoid the deprecation for auto-registration of transforms for our helper
registry.register('transform:string', StringTransform);
registry.register('transform:date', DateTransform);
registry.register('transform:number', NumberTransform);
registry.register('transform:boolean', BooleanTransform);

registry.optionsForType('serializer', { singleton: false });
registry.optionsForType('adapter', { singleton: false });

Expand All @@ -86,6 +93,10 @@ export default function setupStore(options) {
env.registry.register('serializer:application', options.serializer);
env.serializer = store.serializerFor('application');
} else {
// avoid deprecations for -json-api serializer in our tests
// uncomment to find locations to refactor to explicit registration
owner.register('serializer:-json-api', JSONAPISerializer);

// Many tests rely on falling back to this serializer
// they should refactor to register this as the application serializer
owner.register('serializer:-default', JSONAPISerializer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,16 @@ module('integration/store - serializerFor', function(hooks) {
let { owner } = this;
/*
serializer:-default is the "last chance" fallback and is
registered automatically as the json-api serializer.
unregistering it will cause serializerFor to return `undefined`.
the json-api serializer which is re-exported as app/serializers/-default.
here we override to ensure serializerFor will return `undefined`.
*/
owner.unregister('serializer:-default');
const lookup = owner.lookup;
owner.lookup = registrationName => {
if (registrationName === 'serializer:-default') {
return undefined;
}
return lookup.call(owner, registrationName);
};
/*
we fallback to -json-api adapter by default when no other adapter is present.
This adapter specifies a defaultSerializer. We register our own to ensure
Expand All @@ -64,7 +70,7 @@ module('integration/store - serializerFor', function(hooks) {

assert.expectAssertion(() => {
store.serializerFor('person');
}, /No serializer was found for 'person' and no 'application', Adapter\.defaultSerializer, or '-default' serializer were found as fallbacks\./);
}, /Assertion Failed: No serializer was found for 'person' and no 'application' serializer was found as a fallback/);
});

test('we find and instantiate the application serializer', async function(assert) {
Expand Down
11 changes: 9 additions & 2 deletions packages/-ember-data/tests/unit/store/adapter-interop-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import setupStore from 'dummy/tests/helpers/store';

import testInDebug from 'dummy/tests/helpers/test-in-debug';
import { module, test } from 'qunit';

import DS from 'ember-data';
import { setupTest } from 'ember-qunit';

let TestAdapter, store;

module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', function(hooks) {
setupTest(hooks);

hooks.beforeEach(function() {
TestAdapter = DS.Adapter.extend();
});
Expand Down Expand Up @@ -43,9 +45,14 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi
testInDebug('Adapter can not be set as an instance', function(assert) {
assert.expect(1);

store = DS.Store.create({
const BadStore = DS.Store.extend({
adapter: DS.Adapter.create(),
});
const { owner } = this;

owner.unregister('service:store');
owner.register('service:store', BadStore);
const store = owner.lookup('service:store');
assert.expectAssertion(() => store.get('defaultAdapter'));
});

Expand Down
1 change: 1 addition & 0 deletions packages/adapter/types/require/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default function(moduleName: string): any;
16 changes: 6 additions & 10 deletions packages/serializer/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,16 @@
"dummy/*": ["tests/dummy/app/*", "app/*"],
"@ember-data/serializer": ["addon"],
"@ember-data/serializer/*": ["addon/*"],
"@ember-data/store": ["../store/addon"],
"@ember-data/store/*": ["../store/addon/*"],
"@ember-data/canary-features": ["../canary-features/addon"],
"@ember-data/adapter": ["../adapter/addon"],
"@ember-data/adapter/*": ["../adapter/addon/*"],
"@ember-data/serializer/test-support": ["addon-test-support"],
"@ember-data/serializer/test-support/*": ["addon-test-support/*"],
"ember-data": ["../-ember-data/addon"],
"ember-data/*": ["../-ember-data/addon/*"],
"*": ["types/*"]
}
},
"include": [
"app/**/*",
"addon/**/*",
"tests/**/*",
"types/**/*",
"test-support/**/*",
"addon-test-support/**/*"
],
"include": ["app/**/*", "addon/**/*", "tests/**/*", "types/**/*", "test-support/**/*", "addon-test-support/**/*"],
"exclude": ["node_modules"]
}
111 changes: 109 additions & 2 deletions packages/store/addon/-private/system/core-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { default as RSVP, all, resolve, Promise, defer } from 'rsvp';
import Service from '@ember/service';
import { typeOf, isPresent, isNone } from '@ember/utils';

import require, { has } from 'require';
import Ember from 'ember';
import { InvalidError } from '@ember-data/adapter/error';
import { assert, warn, inspect } from '@ember/debug';
Expand Down Expand Up @@ -98,6 +99,21 @@ type PendingSaveItem = {

let globalClientIdCounter = 1;

const HAS_SERIALIZER_PACKAGE = has('@ember-data/serializer');

function deprecateTestRegistration(factoryType: 'serializer', factoryName: '-json-api' | '-rest' | '-default'): void;
// TODO add adapter here and deprecate those registrations as well after refactoring them to re-exports
function deprecateTestRegistration(factoryType: 'serializer', 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,
{
id: 'ember-data:-legacy-test-registrations',
until: '3.17',
}
);
}

// Implementors Note:
//
// The variables in this file are consistently named according to the following
Expand Down Expand Up @@ -285,6 +301,46 @@ abstract class CoreStore extends Service {
}

if (DEBUG) {
if (HAS_SERIALIZER_PACKAGE) {
// support for legacy moduleFor style unit tests
// that did not include transforms in "needs"
// or which were not set to integration:true
// that were relying on ember-test-helpers
// doing an auto-registration of the transform
// or us doing one
const Mapping = {
date: 'DateTransform',
boolean: 'BooleanTransform',
number: 'NumberTransform',
string: 'StringTransform',
};
let shouldWarn = false;

Object.keys(Mapping).forEach((attributeType: keyof typeof Mapping) => {
const transform = getOwner(this).lookup(`transform:${attributeType}`);

if (!transform) {
// we don't deprecate this because the moduleFor style tests with the closed
// resolver will be deprecated on their own. When that deprecation completes
// we can drop this.
const Transform = require(`@ember-data/serializer/-private`)[Mapping[attributeType]];
getOwner(this).register(`transform:${attributeType}`, Transform);
shouldWarn = true;
}
});

if (shouldWarn) {
deprecate(
`You are relying on the automatic registration of the transforms "date", "number", "boolean", and "string". Likely this means you are using a legacy ember-qunit moduleFor helper. Add "needs: ['transform:date', 'transform:boolean', 'transform:number', 'transform:string']", "integration: true", or refactor to modern syntax to resolve this deprecation.`,
false,
{
id: 'ember-data:-legacy-test-registrations',
until: '3.17',
}
);
}
}

this.shouldAssertMethodCallsOnDestroyedStore = this.shouldAssertMethodCallsOnDestroyedStore || false;
if (this.shouldTrackAsyncRequests === undefined) {
this.shouldTrackAsyncRequests = false;
Expand Down Expand Up @@ -3237,6 +3293,27 @@ abstract class CoreStore extends Service {
let owner = getOwner(this);

serializer = owner.lookup(`serializer:${normalizedModelName}`);

// in production this is handled by the re-export
if (DEBUG && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
if (normalizedModelName === '-json-api') {
const Serializer = require('@ember-data/serializer/json-api').default;
owner.register(`serializer:-json-api`, Serializer);
serializer = owner.lookup(`serializer:-json-api`);
deprecateTestRegistration('serializer', '-json-api');
} else if (normalizedModelName === '-rest') {
const Serializer = require('@ember-data/serializer/rest').default;
owner.register(`serializer:-rest`, Serializer);
serializer = owner.lookup(`serializer:-rest`);
deprecateTestRegistration('serializer', '-rest');
} else if (normalizedModelName === '-default') {
const Serializer = require('@ember-data/serializer/json').default;
owner.register(`serializer:-default`, Serializer);
serializer = owner.lookup(`serializer:-default`);
serializer && deprecateTestRegistration('serializer', '-default');
}
}

if (serializer !== undefined) {
set(serializer, 'store', this);
_serializerCache[normalizedModelName] = serializer;
Expand All @@ -3259,6 +3336,27 @@ abstract class CoreStore extends Service {
serializer = serializerName
? _serializerCache[serializerName] || owner.lookup(`serializer:${serializerName}`)
: undefined;

// in production this is handled by the re-export
if (DEBUG && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
if (serializerName === '-json-api') {
const Serializer = require('@ember-data/serializer/json-api').default;
owner.register(`serializer:-json-api`, Serializer);
serializer = owner.lookup(`serializer:-json-api`);
deprecateTestRegistration('serializer', '-json-api');
} else if (serializerName === '-rest') {
const Serializer = require('@ember-data/serializer/rest').default;
owner.register(`serializer:-rest`, Serializer);
serializer = owner.lookup(`serializer:-rest`);
deprecateTestRegistration('serializer', '-rest');
} else if (serializerName === '-default') {
const Serializer = require('@ember-data/serializer/json').default;
owner.register(`serializer:-default`, Serializer);
serializer = owner.lookup(`serializer:-default`);
serializer && deprecateTestRegistration('serializer', '-default');
}
}

if (serializer !== undefined) {
set(serializer, 'store', this);
_serializerCache[normalizedModelName] = serializer;
Expand All @@ -3267,12 +3365,21 @@ abstract class CoreStore extends Service {
}

// final fallback, no model specific serializer, no application serializer, no
// `serializer` property on store: use json-api serializer
// `serializer` property on store: use JSON serializer
serializer = _serializerCache['-default'] || owner.lookup('serializer:-default');
if (DEBUG && HAS_SERIALIZER_PACKAGE && serializer === undefined) {
const JSONSerializer = require('@ember-data/serializer/json').default;
owner.register('serializer:-default', JSONSerializer);
serializer = owner.lookup('serializer:-default');

serializer && deprecateTestRegistration('serializer', '-default');
}

assert(
`No serializer was found for '${modelName}' and no 'application', Adapter.defaultSerializer, or '-default' serializer were found as fallbacks.`,
`No serializer was found for '${modelName}' and no 'application' serializer was found as a fallback`,
serializer !== undefined
);

set(serializer, 'store', this);
_serializerCache[normalizedModelName] = serializer;
_serializerCache['-default'] = serializer;
Expand Down
8 changes: 0 additions & 8 deletions packages/store/addon/-private/system/store/serializers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,5 @@ export function serializerForAdapter(store, adapter, modelName) {
serializer = store.serializerFor(modelName);
}

if (serializer === null || serializer === undefined) {
serializer = {
extract(store, type, payload) {
return payload;
},
};
}

return serializer;
}
1 change: 1 addition & 0 deletions packages/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = Object.assign(addonBaseConfig, {
'ember-inflector',
'@ember/ordered-set',
'ember-data/-debug',
'require',
];
},
});
Loading

0 comments on commit d10bbc0

Please sign in to comment.