diff --git a/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js b/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js index 33eb086f920..48d264fabe6 100644 --- a/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js +++ b/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js @@ -2561,7 +2561,7 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { }); if (hasJQuery) { - test('on error appends errorThrown for sanity', function(assert) { + test('on error appends errorThrown for sanity', async function(assert) { assert.expect(2); let jqXHR = { @@ -2581,12 +2581,12 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { assert.ok(false); }; - return run(() => { - return store.findRecord('post', '1').catch(err => { - assert.equal(err, errorThrown); - assert.ok(err, 'promise rejected'); - }); - }); + try { + await store.findRecord('post', '1'); + } catch (err) { + assert.equal(err, errorThrown); + assert.ok(err, 'promise rejected'); + } }); test('on error wraps the error string in an DS.AdapterError object', function(assert) { diff --git a/packages/-ember-data/tests/unit/adapters/json-api-adapter/ajax-options-test.js b/packages/-ember-data/tests/unit/adapters/json-api-adapter/ajax-options-test.js index f6df0e2381c..a6b18ff4a26 100644 --- a/packages/-ember-data/tests/unit/adapters/json-api-adapter/ajax-options-test.js +++ b/packages/-ember-data/tests/unit/adapters/json-api-adapter/ajax-options-test.js @@ -9,7 +9,12 @@ module('unit/adapters/json-api-adapter/ajax-options - building requests', functi setupTest(hooks); hooks.beforeEach(function() { - this.owner.register('adapter:application', JSONAPIAdapter.extend({ useFetch: true })); + this.owner.register( + 'adapter:application', + class extends JSONAPIAdapter { + useFetch = true; + } + ); this.owner.register('serializer:application', JSONAPISerializer.extend()); }); diff --git a/packages/-ember-data/tests/unit/adapters/rest-adapter/ajax-options-test.js b/packages/-ember-data/tests/unit/adapters/rest-adapter/ajax-options-test.js index a6bc87dabbd..9cf44f74c71 100644 --- a/packages/-ember-data/tests/unit/adapters/rest-adapter/ajax-options-test.js +++ b/packages/-ember-data/tests/unit/adapters/rest-adapter/ajax-options-test.js @@ -20,7 +20,12 @@ module('unit/adapters/rest-adapter/ajax-options - building requests', function(h this.owner.register('model:person', Person); this.owner.register('model:place', Place); - this.owner.register('adapter:application', RESTAdapter.extend({ useFetch: true })); + this.owner.register( + 'adapter:application', + class extends RESTAdapter { + useFetch = true; + } + ); this.owner.register('serializer:application', RESTSerializer.extend()); }); @@ -243,7 +248,12 @@ module('unit/adapters/rest-adapter/ajax-options - building requests', function(h module('ajax-options - ajax', function(hooks) { hooks.beforeEach(function() { - this.owner.register('adapter:application', RESTAdapter.extend({ useFetch: false })); + this.owner.register( + 'adapter:application', + class extends RESTAdapter { + useFetch = false; + } + ); }); test('ajaxOptions() Content-Type is not set with ajax GET', function(assert) { @@ -268,8 +278,14 @@ module('unit/adapters/rest-adapter/ajax-options - building requests', function(h assert.notOk(ajaxOptions.contentType, 'contentType not set with POST no data'); }); - test('ajaxOptions() Content-Type is set with ajax POST with data', function(assert) { + test('ajaxOptions() Content-Type is set with ajax POST with data if not useFetch', function(assert) { let store = this.owner.lookup('service:store'); + this.owner.register( + 'adapter:application', + class extends RESTAdapter { + useFetch = false; + } + ); let adapter = store.adapterFor('application'); let url = 'example.com'; @@ -278,5 +294,26 @@ module('unit/adapters/rest-adapter/ajax-options - building requests', function(h assert.equal(ajaxOptions.contentType, 'application/json; charset=utf-8', 'contentType is set with POST'); }); + + test('ajaxOptions() Content-Type is set with ajax POST with data if useFetch', function(assert) { + let store = this.owner.lookup('service:store'); + this.owner.register( + 'adapter:application', + class extends RESTAdapter { + useFetch = true; + } + ); + let adapter = store.adapterFor('application'); + + let url = 'example.com'; + let type = 'POST'; + let ajaxOptions = adapter.ajaxOptions(url, type, { data: { type: 'post' } }); + + assert.equal( + ajaxOptions.headers['content-type'], + 'application/json; charset=utf-8', + 'contentType is set with POST' + ); + }); }); }); diff --git a/packages/-ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/packages/-ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 0ca40a3cb14..668a6e2c298 100644 --- a/packages/-ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/packages/-ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -23,12 +23,12 @@ module('unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda requests = []; lengths = []; - const ApplicationAdapter = RESTAdapter.extend({ - coalesceFindRequests: true, + class ApplicationAdapter extends RESTAdapter { + coalesceFindRequests = true; findRecord(store, type, id, snapshot) { return { id }; - }, + } ajax(url, type, options) { requests.push({ @@ -48,8 +48,8 @@ module('unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda let testRecords = options.data.ids.map(id => ({ id })); return EmberPromise.resolve({ testRecords: testRecords }); - }, - }); + } + } this.owner.register('adapter:application', ApplicationAdapter); this.owner.register('serializer:application', RESTSerializer.extend()); diff --git a/packages/adapter/addon/index.js b/packages/adapter/addon/index.js index 504bf6bddfc..8ac492e4779 100644 --- a/packages/adapter/addon/index.js +++ b/packages/adapter/addon/index.js @@ -55,7 +55,7 @@ import EmberObject from '@ember/object'; @class Adapter @extends EmberObject */ -export default EmberObject.extend({ +export default class Adapter extends EmberObject { /** If you would like your adapter to use a custom serializer you can set the `defaultSerializer` property to be the name of the custom @@ -77,7 +77,7 @@ export default EmberObject.extend({ @property defaultSerializer @type {String} */ - defaultSerializer: '-default', + defaultSerializer = '-default'; /** The `findRecord()` method is invoked when the store is asked for a record that @@ -113,7 +113,6 @@ export default EmberObject.extend({ @param {Snapshot} snapshot @return {Promise} promise */ - findRecord: null, /** The `findAll()` method is used to retrieve all records for a given type. @@ -145,7 +144,6 @@ export default EmberObject.extend({ @param {SnapshotRecordArray} snapshotRecordArray @return {Promise} promise */ - findAll: null, /** This method is called when you call `query` on the store. @@ -178,7 +176,6 @@ export default EmberObject.extend({ @param {Object} adapterOptions @return {Promise} promise */ - query: null, /** The `queryRecord()` method is invoked when the store is asked for a single @@ -217,7 +214,6 @@ export default EmberObject.extend({ @param {Object} adapterOptions @return {Promise} promise */ - queryRecord: null, /** If the globally unique IDs for your records should be generated on the client, @@ -251,7 +247,6 @@ export default EmberObject.extend({ newly created record. @return {(String|Number)} id */ - generateIdForRecord: null, /** Proxies to the serializer's `serialize` method. @@ -278,7 +273,7 @@ export default EmberObject.extend({ */ serialize(snapshot, options) { return snapshot.serialize(options); - }, + } /** Implement this method in a subclass to handle the creation of @@ -321,7 +316,6 @@ export default EmberObject.extend({ @param {Snapshot} snapshot @return {Promise} promise */ - createRecord: null, /** Implement this method in a subclass to handle the updating of @@ -373,7 +367,6 @@ export default EmberObject.extend({ @param {Snapshot} snapshot @return {Promise} promise */ - updateRecord: null, /** Implement this method in a subclass to handle the deletion of @@ -417,7 +410,6 @@ export default EmberObject.extend({ @param {Snapshot} snapshot @return {Promise} promise */ - deleteRecord: null, /** By default the store will try to coalesce all `fetchRecord` calls within the same runloop @@ -428,7 +420,7 @@ export default EmberObject.extend({ @property coalesceFindRequests @type {boolean} */ - coalesceFindRequests: true, + coalesceFindRequests = true; /** The store will call `findMany` instead of multiple `findRecord` @@ -467,7 +459,6 @@ export default EmberObject.extend({ @param {Array} snapshots @return {Promise} promise */ - findMany: null, /** Organize records into groups, each of which is to be passed to separate @@ -486,7 +477,7 @@ export default EmberObject.extend({ */ groupRecordsForFindMany(store, snapshots) { return [snapshots]; - }, + } /** This method is used by the store to determine if the store should @@ -536,7 +527,7 @@ export default EmberObject.extend({ */ shouldReloadRecord(store, snapshot) { return false; - }, + } /** This method is used by the store to determine if the store should @@ -591,7 +582,7 @@ export default EmberObject.extend({ */ shouldReloadAll(store, snapshotRecordArray) { return !snapshotRecordArray.length; - }, + } /** This method is used by the store to determine if the store should @@ -627,7 +618,7 @@ export default EmberObject.extend({ */ shouldBackgroundReloadRecord(store, snapshot) { return true; - }, + } /** This method is used by the store to determine if the store should @@ -663,7 +654,7 @@ export default EmberObject.extend({ */ shouldBackgroundReloadAll(store, snapshotRecordArray) { return true; - }, -}); + } +} export { BuildURLMixin } from './-private'; diff --git a/packages/adapter/addon/json-api.js b/packages/adapter/addon/json-api.js index 4cb605611b1..425884831ad 100644 --- a/packages/adapter/addon/json-api.js +++ b/packages/adapter/addon/json-api.js @@ -143,10 +143,10 @@ import RESTAdapter from './rest'; @constructor @extends RESTAdapter */ -const JSONAPIAdapter = RESTAdapter.extend({ - defaultSerializer: '-json-api', +class JSONAPIAdapter extends RESTAdapter { + defaultSerializer = '-json-api'; - _defaultContentType: 'application/vnd.api+json', + _defaultContentType = 'application/vnd.api+json'; /** @method ajaxOptions @@ -157,12 +157,12 @@ const JSONAPIAdapter = RESTAdapter.extend({ @return {Object} */ ajaxOptions(url, type, options = {}) { - let hash = this._super(url, type, options); + let hash = super.ajaxOptions(url, type, options); hash.headers['Accept'] = hash.headers['Accept'] || 'application/vnd.api+json'; return hash; - }, + } /** By default the JSONAPIAdapter will send each find request coming from a `store.find` @@ -219,17 +219,17 @@ const JSONAPIAdapter = RESTAdapter.extend({ @property coalesceFindRequests @type {boolean} */ - coalesceFindRequests: false, + coalesceFindRequests = false; findMany(store, type, ids, snapshots) { let url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); - }, + } pathForType(modelName) { let dasherized = dasherize(modelName); return pluralize(dasherized); - }, + } updateRecord(store, type, snapshot) { const data = serializeIntoHash(store, type, snapshot); @@ -237,7 +237,7 @@ const JSONAPIAdapter = RESTAdapter.extend({ let url = this.buildURL(type.modelName, snapshot.id, snapshot, 'updateRecord'); return this.ajax(url, 'PATCH', { data: data }); - }, -}); + } +} export default JSONAPIAdapter; diff --git a/packages/adapter/addon/rest.js b/packages/adapter/addon/rest.js index 5a6108a242b..7f5b7a6018f 100644 --- a/packages/adapter/addon/rest.js +++ b/packages/adapter/addon/rest.js @@ -293,31 +293,30 @@ const hasJQuery = typeof jQuery !== 'undefined'; @extends Adapter @uses BuildURLMixin */ -let RESTAdapter = Adapter.extend(BuildURLMixin, { - defaultSerializer: '-rest', +class RESTAdapter extends Adapter.extend(BuildURLMixin) { + defaultSerializer = '-rest'; - _defaultContentType: 'application/json; charset=utf-8', + _defaultContentType = 'application/json; charset=utf-8'; - fastboot: computed({ + @computed + get fastboot() { // Avoid computed property override deprecation in fastboot as suggested by: // https://deprecations.emberjs.com/v3.x/#toc_computed-property-override - get() { - if (this._fastboot) { - return this._fastboot; - } - return (this._fastboot = getOwner(this).lookup('service:fastboot')); - }, - set(key, value) { - return (this._fastboot = value); - }, - }), + if (this._fastboot) { + return this._fastboot; + } + return (this._fastboot = getOwner(this).lookup('service:fastboot')); + } + + set fastboot(value) { + return (this._fastboot = value); + } /** @property useFetch @type {Boolean} @public */ - useFetch: true, /** By default, the RESTAdapter will send the query params sorted alphabetically to the @@ -374,7 +373,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; } return newQueryParams; - }, + } /** By default the RESTAdapter will send each find request coming from a `store.find` @@ -423,7 +422,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { @property coalesceFindRequests @type {boolean} */ - coalesceFindRequests: false, + coalesceFindRequests = false; /** Endpoint paths can be prefixed with a `namespace` by setting the namespace @@ -507,7 +506,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { let query = this.buildQuery(snapshot); return this.ajax(url, 'GET', { data: query }); - }, + } /** Called by the store in order to fetch a JSON array for all @@ -532,7 +531,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { } return this.ajax(url, 'GET', { data: query }); - }, + } /** Called by the store in order to fetch a JSON array for @@ -559,7 +558,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { } return this.ajax(url, 'GET', { data: query }); - }, + } /** Called by the store in order to fetch a JSON object for @@ -587,7 +586,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { } return this.ajax(url, 'GET', { data: query }); - }, + } /** Called by the store in order to fetch several records together if `coalesceFindRequests` is true @@ -625,7 +624,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { findMany(store, type, ids, snapshots) { let url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); return this.ajax(url, 'GET', { data: { ids: ids } }); - }, + } /** Called by the store in order to fetch a JSON array for @@ -670,7 +669,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findHasMany')); return this.ajax(url, 'GET'); - }, + } /** Called by the store in order to fetch the JSON for the unloaded record in a @@ -714,7 +713,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findBelongsTo')); return this.ajax(url, 'GET'); - }, + } /** Called by the store when a newly created record is @@ -738,7 +737,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { const data = serializeIntoHash(store, type, snapshot); return this.ajax(url, 'POST', { data }); - }, + } /** Called by the store when an existing record is saved @@ -763,7 +762,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { let url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); return this.ajax(url, 'PUT', { data }); - }, + } /** Called by the store when a record is deleted. @@ -780,7 +779,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { let id = snapshot.id; return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), 'DELETE'); - }, + } _stripIDFromURL(store, snapshot) { let url = this.buildURL(snapshot.modelName, snapshot.id, snapshot); @@ -801,10 +800,10 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { } return expandedURL.join('/'); - }, + } // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers - maxURLLength: 2048, + maxURLLength = 2048; /** Organize records into groups, each of which is to be passed to separate @@ -872,7 +871,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { }); return groupsArray; - }, + } /** Takes an ajax response, and returns the json payload or an error. @@ -929,7 +928,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { } return new AdapterError(errors, detailedMessage); - }, + } /** Default `handleResponse` implementation uses this hook to decide if the @@ -944,7 +943,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { */ isSuccess(status, headers, payload) { return (status >= 200 && status < 300) || status === 304; - }, + } /** Default `handleResponse` implementation uses this hook to decide if the @@ -959,7 +958,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { */ isInvalid(status, headers, payload) { return status === 422; - }, + } /** Takes a URL, an HTTP method and a hash of data, and makes an @@ -1023,7 +1022,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { adapter._ajax(hash); }, 'DS: RESTAdapter#ajax ' + type + ' to ' + url); - }, + } /** @method _ajaxRequest @@ -1032,7 +1031,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { */ _ajaxRequest(options) { jQuery.ajax(options); - }, + } _fetchRequest(options) { let fetchFunction = fetch(); @@ -1044,7 +1043,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { 'cannot find the `fetch` module or the `fetch` global. Did you mean to install the `ember-fetch` addon?' ); } - }, + } _ajax(options) { if (this.useFetch) { @@ -1054,7 +1053,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { } else { this._ajaxRequest(options); } - }, + } /** @method ajaxOptions @@ -1102,7 +1101,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { options.url = this._ajaxURL(options.url); return options; - }, + } _ajaxURL(url) { if (get(this, 'fastboot.isFastBoot')) { @@ -1126,7 +1125,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { } return url; - }, + } /** @method parseErrorResponse @@ -1144,7 +1143,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { } return json; - }, + } /** @method normalizeErrorResponse @@ -1166,7 +1165,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { }, ]; } - }, + } /** Generates a detailed ("friendly") error message, with plenty @@ -1180,7 +1179,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { @param {Object} requestData @return {String} detailed error message */ - generatedDetailedMessage: function(status, headers, payload, requestData) { + generatedDetailedMessage(status, headers, payload, requestData) { let shortenedPayload; let payloadContentType = headers['content-type'] || 'Empty Content-Type'; @@ -1198,7 +1197,7 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { payloadDescription, shortenedPayload, ].join('\n'); - }, + } /** @method buildQuery @@ -1219,8 +1218,8 @@ let RESTAdapter = Adapter.extend(BuildURLMixin, { } return query; - }, -}); + } +} function ajaxSuccess(adapter, payload, requestData, responseData) { let response; @@ -1401,72 +1400,79 @@ function ajaxOptions(options, adapter) { } if (DEPRECATE_NAJAX) { - RESTAdapter = RESTAdapter.extend({ - /** - @method _najaxRequest - @private - @param {Object} options jQuery ajax options to be used for the najax request - */ - _najaxRequest(options) { - if (typeof najax !== 'undefined') { - najax(options); - } else { - throw new Error( - 'najax does not seem to be defined in your app. Did you override it via `addOrOverrideSandboxGlobals` in the fastboot server?' - ); + /** + @method _najaxRequest + @private + @param {Object} options jQuery ajax options to be used for the najax request + */ + RESTAdapter.prototype._najaxRequest = function(options) { + if (typeof najax !== 'undefined') { + najax(options); + } else { + throw new Error( + 'najax does not seem to be defined in your app. Did you override it via `addOrOverrideSandboxGlobals` in the fastboot server?' + ); + } + }; + + Object.defineProperty(RESTAdapter.prototype, 'useFetch', { + get() { + if (typeof this[UseFetch] === 'boolean') { + return this[UseFetch]; } - }, - useFetch: computed({ - get() { - if (this[UseFetch]) { - return this[UseFetch]; + // Mixin validates all properties. Might not have it in the container yet + let ENV = getOwner(this) ? getOwner(this).resolveRegistration('config:environment') : {}; + // TODO: https://github.com/emberjs/data/issues/6093 + let jQueryIntegrationDisabled = ENV && ENV.EmberENV && ENV.EmberENV._JQUERY_INTEGRATION === false; + + let shouldUseFetch; + if (jQueryIntegrationDisabled) { + shouldUseFetch = true; + } else if (typeof najax !== 'undefined') { + if (has('fetch')) { + deprecate( + 'You have ember-fetch and jquery installed. To use ember-fetch instead of najax, set `useFetch = true` in your adapter. In 4.0, ember-data will default to ember-fetch instead of najax when both ember-fetch and jquery are installed in FastBoot.', + false, + { + id: 'ember-data:najax-fallback', + until: '4.0', + } + ); + } else { + deprecate( + 'In 4.0, ember-data will default to ember-fetch instead of najax in FastBoot. It is recommended that you install ember-fetch or similar fetch polyfill in FastBoot and set `useFetch = true` in your adapter.', + false, + { + id: 'ember-data:najax-fallback', + until: '4.0', + } + ); } - let ENV = getOwner(this).resolveRegistration('config:environment'); - // TODO: https://github.com/emberjs/data/issues/6093 - let jQueryIntegrationDisabled = ENV && ENV.EmberENV && ENV.EmberENV._JQUERY_INTEGRATION === false; - - let shouldUseFetch; - if (jQueryIntegrationDisabled) { - shouldUseFetch = true; - } else if (typeof najax !== 'undefined') { - if (has('fetch')) { - deprecate( - 'You have ember-fetch and jquery installed. To use ember-fetch instead of najax, set `useFetch = true` in your adapter. In 4.0, ember-data will default to ember-fetch instead of najax when both ember-fetch and jquery are installed in FastBoot.', - false, - { - id: 'ember-data:najax-fallback', - until: '4.0', - } - ); - } else { - deprecate( - 'In 4.0, ember-data will default to ember-fetch instead of najax in FastBoot. It is recommended that you install ember-fetch or similar fetch polyfill in FastBoot and set `useFetch = true` in your adapter.', - false, - { - id: 'ember-data:najax-fallback', - until: '4.0', - } - ); - } + shouldUseFetch = false; + } else if (hasJQuery) { + shouldUseFetch = false; + } else { + shouldUseFetch = true; + } - shouldUseFetch = false; - } else if (hasJQuery) { - shouldUseFetch = false; - } else { - shouldUseFetch = true; - } + addSymbol(this, UseFetch, shouldUseFetch); - addSymbol(this, UseFetch, shouldUseFetch); + return shouldUseFetch; + }, - return shouldUseFetch; - }, - set(key, value) { - addSymbol(this, UseFetch, value); - return value; - }, - }), + set(value) { + addSymbol(this, UseFetch, value); + return value; + }, + }); +} else { + Object.defineProperty(RESTAdapter.prototype, 'useFetch', { + value() { + return true; + }, + configurable: true, }); }