Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: deprecate proxies (implements emberjs/rfcs#846) #8134

Merged
merged 2 commits into from
Aug 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/enforce-pr-labels-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- uses: yogevbd/enforce-label-action@2.2.2
with:
BANNED_LABELS: 'backport-beta,backport-lts,backport-lts-prev,backport-old-release'
BANNED_LABEL/s_DESCRIPTION: "The following labels should only be applied to PRs targeting other release channel branches, remove them.['backport-beta', 'backport-lts', 'backport-lts-prev', 'backport-old-release']"
BANNED_LABELS_DESCRIPTION: "The following labels should only be applied to PRs targeting other release channel branches, remove them.['backport-beta', 'backport-lts', 'backport-lts-prev', 'backport-old-release']"
triage:
runs-on: ubuntu-latest
steps:
Expand Down
4 changes: 2 additions & 2 deletions @types/@ember/array/-private/mutable-enumerable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ interface MutableEnumerable<T> extends Enumerable<T> {
/**
* __Required.__ You must implement this method to apply this mixin.
*/
addObject(object: T): T;
addObject(object: T): this;
/**
* Adds each object in the passed enumerable to the receiver.
*/
addObjects(objects: T[] | Enumerable<T>): this;
/**
* __Required.__ You must implement this method to apply this mixin.
*/
removeObject(object: T): T;
removeObject(object: T): this;
/**
* Removes each object in the passed enumerable from the receiver.
*/
Expand Down
11 changes: 2 additions & 9 deletions @types/@ember/array/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@
import Enumerable from '@ember/array/-private/enumerable';
import type NativeArray from '@ember/array/-private/native-array';
import type ComputedProperty from '@ember/object/computed';
import type Mixin from '@ember/object/mixin';

/**
* This module implements Observer-friendly Array-like behavior. This mixin is picked up by the
* Array class as well as other controllers, etc. that want to appear to be arrays.
*/
interface Array<T> extends Enumerable<T> {
interface EmberArray<T> extends Enumerable<T> {
/**
* __Required.__ You must implement this method to apply this mixin.
*/
Expand Down Expand Up @@ -89,16 +88,10 @@ interface Array<T> extends Enumerable<T> {
*/
'@each': ComputedProperty<T>;
}
// Ember.Array rather than Array because the `array-type` lint rule doesn't realize the global is shadowed
// tslint:disable-next-line:array-type
// eslint-disable-next-line @typescript-eslint/no-unused-vars
declare class Array<T> extends Mixin<Array<unknown>> {
static detect(arr: unknown): boolean;
}

export const NativeArray;

export default Array;
export default EmberArray;

/**
* Creates an `Ember.NativeArray` from an Array like object.
Expand Down
6 changes: 3 additions & 3 deletions ember-data-types/q/minimum-adapter-interface.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type Store from '@ember-data/store';
import type Snapshot from '@ember-data/store/-private/network/snapshot';
import type SnapshotRecordArray from '@ember-data/store/-private/network/snapshot-record-array';
import type AdapterPopulatedRecordArray from '@ember-data/store/-private/record-arrays/adapter-populated-record-array';
import type { Collection } from '@ember-data/store/-private/record-arrays/identifier-array';

import type { ModelSchema } from './ds-model';
import type { RelationshipSchema } from './record-data-schemas';
Expand Down Expand Up @@ -122,15 +122,15 @@ export interface MinimumAdapterInterface {
* @param {ModelSchema} schema An object with methods for accessing information about
* the type, attributes and relationships of the primary type associated with the request.
* @param {object} query
* @param {AdapterPopulatedRecordArray} recordArray
* @param {Collection} recordArray
* @param {object} options
* @return {Promise} a promise resolving with resource data to feed to the associated serializer
*/
query(
store: Store,
schema: ModelSchema,
query: Dict<unknown>,
recordArray: AdapterPopulatedRecordArray,
recordArray: Collection,
options: { adapterOptions?: unknown }
): Promise<AdapterPayload>;

Expand Down
4 changes: 4 additions & 0 deletions ember-data-types/q/record-data.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { LocalRelationshipOperation } from '@ember-data/record-data/-private/graph/-operations';

import type { CollectionResourceRelationship, SingleResourceRelationship } from './ember-data-json-api';
import type { RecordIdentifier, StableRecordIdentifier } from './identifier';
import type { JsonApiResource, JsonApiValidationError } from './record-data-json-api';
Expand Down Expand Up @@ -73,6 +75,8 @@ export interface RecordData {

unloadRecord(identifier: StableRecordIdentifier): void;

update(operation: LocalRelationshipOperation): void;

// Attrs
// =====

Expand Down
18 changes: 8 additions & 10 deletions packages/-ember-data/addon/-private/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
// public
import ArrayProxy from '@ember/array/proxy';
import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
import ObjectProxy from '@ember/object/proxy';

export { default as Store } from '@ember-data/store';
export { default as DS } from './core';
export { Errors } from '@ember-data/model/-private';
export { Snapshot } from '@ember-data/store/-private';

// `ember-data-model-fragments' and `ember-data-change-tracker` rely on `normalizeModelName`
export {
AdapterPopulatedRecordArray,
PromiseArray,
PromiseObject,
RecordArray,
RecordArrayManager,
SnapshotRecordArray,
normalizeModelName,
coerceId,
} from '@ember-data/store/-private';
export { RecordArrayManager, SnapshotRecordArray, normalizeModelName, coerceId } from '@ember-data/store/-private';
export { ManyArray, PromiseManyArray } from '@ember-data/model/-private';
export { RecordData } from '@ember-data/record-data/-private';

export const PromiseArray = ArrayProxy.extend(PromiseProxyMixin);
export const PromiseObject = ObjectProxy.extend(PromiseProxyMixin);
4 changes: 0 additions & 4 deletions packages/-ember-data/addon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,12 @@ import Transform from '@ember-data/serializer/transform';
import Store, { normalizeModelName } from '@ember-data/store';

import {
AdapterPopulatedRecordArray,
DS,
Errors,
ManyArray,
PromiseArray,
PromiseManyArray,
PromiseObject,
RecordArray,
RecordArrayManager,
Snapshot,
} from './-private';
Expand Down Expand Up @@ -171,8 +169,6 @@ if (macroCondition(dependencySatisfies('@ember-data/debug', '*'))) {
DS.DebugAdapter = importSync('@ember-data/debug').default;
}

DS.RecordArray = RecordArray;
DS.AdapterPopulatedRecordArray = AdapterPopulatedRecordArray;
DS.ManyArray = ManyArray;

DS.RecordArrayManager = RecordArrayManager;
Expand Down
3 changes: 3 additions & 0 deletions packages/-ember-data/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ module.exports = Object.assign({}, addonBaseConfig, {
'@ember-data/store',
'@ember-data/model',
'@ember-data/model/-private',
'@ember/array/proxy',
'@ember/object/promise-proxy-mixin',
'@ember/object/proxy',
];
},
treeForAddon(tree) {
Expand Down
4 changes: 0 additions & 4 deletions packages/-ember-data/node-tests/fixtures/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,6 @@ module.exports = {
'(private) @ember-data/store IdentifierCache#_mergeRecordIdentifiers',
'(private) @ember-data/store IdentifierCache#peekRecordIdentifier',
'(private) @ember-data/store ManyArray#isPolymorphic',
'(private) @ember-data/store ManyArray#relationship',
'(private) @ember-data/store RecordArray#content',
'(private) @ember-data/store RecordArray#objectAtContent',
'(private) @ember-data/store RecordArray#store',
'(private) @ember-data/store Snapshot#constructor',
'(private) @ember-data/store SnapshotRecordArray#_recordArray',
Expand Down Expand Up @@ -313,7 +310,6 @@ module.exports = {
'(public) @ember-data/store ManyArray#meta',
'(public) @ember-data/store ManyArray#reload',
'(public) @ember-data/store ManyArray#save',
'(public) @ember-data/store RecordArray#isLoaded',
'(public) @ember-data/store RecordArray#isUpdating',
'(public) @ember-data/store RecordArray#save',
'(public) @ember-data/store RecordArray#type',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ServerError } from '@ember-data/adapter/error';
import JSONAPIAdapter from '@ember-data/adapter/json-api';
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
import { LEGACY_SUPPORT } from '@ember-data/model/-private';
import { DEPRECATE_ARRAY_LIKE } from '@ember-data/private-build-infra/deprecations';
import JSONAPISerializer from '@ember-data/serializer/json-api';
import Store from '@ember-data/store';
import { deprecatedTest } from '@ember-data/unpublished-test-infra/test-support/deprecated-test';
Expand Down Expand Up @@ -697,7 +698,7 @@ module('autotracking has-many', function (hooks) {
store = owner.lookup('service:store');
});

test('We can re-render a pojo', async function (assert) {
test('We can re-render a simple array', async function (assert) {
class ChildrenList extends Component {
@service store;

Expand All @@ -706,7 +707,13 @@ module('autotracking has-many', function (hooks) {
}

get sortedChildren() {
return this.children.sortBy('name');
if (DEPRECATE_ARRAY_LIKE) {
let result = this.children.sortBy('name');
assert.expectDeprecation({ id: 'ember-data:deprecate-array-like' });
return result;
} else {
return this.children.slice().sort((a, b) => (a.name > b.name ? 1 : -1));
}
}

@action
Expand Down Expand Up @@ -760,7 +767,9 @@ module('autotracking has-many', function (hooks) {
@service store;

get sortedChildren() {
return this.args.person.children.sortBy('name');
let result = this.args.person.children.sortBy('name');
assert.expectDeprecation({ id: 'ember-data:deprecate-array-like' });
return result;
}

@action
Expand Down Expand Up @@ -860,19 +869,28 @@ module('autotracking has-many', function (hooks) {

deprecatedTest(
'We can re-render hasMany with PromiseManyArray.objectAt',
{ id: 'ember-data:deprecate-promise-many-array-behaviors', until: '5.0', count: 6 },
{ id: 'ember-data:deprecate-promise-many-array-behaviors', until: '5.0', count: 12 },
async function (assert) {
let calls = 0;
class ChildrenList extends Component {
@service store;

get firstChild() {
return this.args.person.children.objectAt(0);
const result = this.args.person.children.objectAt(0);
assert.expectDeprecation({ id: 'ember-data:deprecate-array-like' });
return result;
}

get lastChild() {
const result = this.args.person.children.objectAt(-1);
assert.expectDeprecation({ id: 'ember-data:deprecate-array-like' });
return result;
}

@action
createChild() {
const parent = this.args.person;
const name = 'RGB';
const name = 'RGB ' + calls++;
this.store.createRecord('person', { name, parent });
}
}
Expand All @@ -881,6 +899,7 @@ module('autotracking has-many', function (hooks) {
<button id="createChild" {{on "click" this.createChild}}>Add child</button>

<h2>{{this.firstChild.name}}</h2>
<h3>{{this.lastChild.name}}</h3>
`;
this.owner.register('component:children-list', ChildrenList);
this.owner.register('template:components/children-list', layout);
Expand All @@ -894,11 +913,13 @@ module('autotracking has-many', function (hooks) {

await click('#createChild');

assert.dom('h2').hasText('RGB', 'renders first child');
assert.dom('h2').hasText('RGB 0', 'renders first child');
assert.dom('h3').hasText('RGB 0', 'renders last child');

await click('#createChild');

assert.dom('h2').hasText('RGB', 'renders first child');
assert.dom('h2').hasText('RGB 0', 'renders first child');
assert.dom('h3').hasText('RGB 1', 'renders last child');
}
);

Expand Down Expand Up @@ -1054,7 +1075,7 @@ module('autotracking has-many', function (hooks) {
@service store;

get firstChild() {
return this.args.children.objectAt(0);
return this.args.children.at(0);
}

@action
Expand Down Expand Up @@ -1145,7 +1166,7 @@ module('autotracking has-many', function (hooks) {
@service store;

get children() {
return this.args.children.toArray();
return this.args.children.slice();
}

@action
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ module('tracking state flags on a record', function (hooks) {
// - access a prop on a single record (which is the prop
// we will now change)
if (this.children !== null) {
return this.children.toArray().filter((child) => {
return this.children.slice().filter((child) => {
return child.isNew;
});
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { helper } from '@ember/component/helper';
import { addObserver, removeObserver } from '@ember/object/observers';
import { render } from '@ember/test-helpers';

import hbs from 'htmlbars-inline-precompile';
import QUnit from 'qunit';

function freeze(obj) {
Expand Down Expand Up @@ -50,6 +53,23 @@ export function watchProperty(obj, propertyName) {
return { counter, unwatch };
}

export async function startWatching() {
this.set(
'observe',
helper(([obj, prop, value]) => {
obj.watchers[prop]();
})
);
this.set('__watchedObjects', this.__watchedObjects);
await render(hbs`
{{#each this.__watchedObjects key="@index" as |obj|}}
{{#each obj.properties key="@index" as |prop|}}
{{this.observe obj prop (get obj.context prop)}}
{{/each}}
{{/each}}
`);
}

export function watchProperties(obj, propertyNames) {
let watched = {};
let counters = {};
Expand All @@ -68,17 +88,11 @@ export function watchProperties(obj, propertyNames) {
let { counter, increment } = makeCounter();
watched[propertyName] = increment;
counters[propertyName] = counter;

addObserver(obj, propertyName, increment);
}

function unwatch() {
Object.keys(watched).forEach((propertyName) => {
removeObserver(obj, propertyName, watched[propertyName]);
});
}

return { counters, unwatch };
this.__watchedObjects = this.__watchedObjects || [];
this.__watchedObjects.push({ context: obj, counters, watchers: watched, properties: propertyNames });
return { counters };
}

QUnit.assert.watchedPropertyCounts = function assertWatchedPropertyCount(watchedObject, expectedCounts, label = '') {
Expand Down Expand Up @@ -133,17 +147,3 @@ QUnit.assert.watchedPropertyCount = function assertWatchedPropertyCount(watcher,
message: label,
});
};

QUnit.assert.dirties = function assertDirties(options, updateMethodCallback, label) {
let { object: obj, property, count } = options;
count = typeof count === 'number' ? count : 1;
let { counter, unwatch } = watchProperty(obj, property);
updateMethodCallback();
this.pushResult({
result: counter.count === count,
actual: counter.count,
expected: count,
message: label,
});
unwatch();
};
Loading
Loading