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(EmberDataV5): Slice ember data array proxies #1

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion addon/helpers/append.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { helper } from '@ember/component/helper';
import { isSliceable } from '../utils/as-array';

export function append([...arrays]) {
return [].concat(...arrays);
return [].concat(...arrays.map((array) => isSliceable(array) ? array.slice() : array));
}

export default helper(append);
1 change: 1 addition & 0 deletions addon/helpers/chunk.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export function chunk(num, array) {
let size = max(integer, 0);

let length = 0;
array = asArray(array);
if (isEmberArray(array)) {
length = array.length;
}
Expand Down
7 changes: 6 additions & 1 deletion addon/helpers/object-at.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { helper } from '@ember/component/helper';
import { A, isArray as isEmberArray } from '@ember/array';
import { isSliceable } from '../utils/as-array';
import asArray from '../utils/as-array';

export function objectAt(index, array) {
if (isSliceable(array)) {
array = array.slice();
}
if (!isEmberArray(array)) {
return undefined;
}

index = parseInt(index, 10);

return A(array).objectAt(index);
return A(asArray(array)).objectAt(index);
}

export default helper(function([index, array]) {
Expand Down
2 changes: 2 additions & 0 deletions addon/helpers/previous.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import getIndex from '../utils/get-index';
import { isEmpty } from '@ember/utils';
import { A as emberArray } from '@ember/array';
import getValueArrayAndUseDeepEqualFromParams from '../-private/get-value-array-and-use-deep-equal-from-params';
import asArray from '../utils/as-array';

export function previous(currentValue, array, useDeepEqual = false) {
array = asArray(array);
let currentIndex = getIndex(array, currentValue, useDeepEqual);

if (isEmpty(currentIndex)) {
Expand Down
6 changes: 3 additions & 3 deletions addon/helpers/sort-by.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { get } from '@ember/object';
import { isEmpty } from '@ember/utils';
import { helper } from '@ember/component/helper';
import asArray from '../utils/as-array';
import asArray, { isSliceable } from '../utils/as-array';

const collator = new Intl.Collator(undefined, {
sensitivity: 'base'
Expand Down Expand Up @@ -109,8 +109,8 @@ function sortAsc(key, a, b) {
class SortBy {
constructor(...args) {
let [array] = args;
if (typeof array.toArray === "function") {
array = array.toArray();
if (isSliceable(array)) {
array = array.slice();
}

this.array = [...array];
Expand Down
2 changes: 2 additions & 0 deletions addon/helpers/toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { helper } from '@ember/component/helper';
import { get } from '@ember/object';
import { set } from '@ember/object';
import { isPresent } from '@ember/utils';
import asArray from '../utils/as-array';

function nextIndex(length, currentIdx) {
if (currentIdx === -1 || currentIdx + 1 === length) {
Expand All @@ -16,6 +17,7 @@ export function toggle([prop, obj, ...values]) {
let currentValue = get(obj, prop);

if (isPresent(values)) {
values = asArray(values);
let currentIdx = values.indexOf(currentValue);
let nextIdx = nextIndex(values.length, currentIdx);

Expand Down
7 changes: 7 additions & 0 deletions addon/helpers/without.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { helper } from '@ember/component/helper';
import { A as emberArray, isArray as isEmberArray } from '@ember/array';
import { isSliceable } from '../utils/as-array';

function contains(needle, haystack) {
return emberArray(haystack).includes(needle);
}

export function without(needle, haystack) {
if (isSliceable(haystack)) {
haystack = haystack.slice();
}
if (isSliceable(needle)) {
needle = needle.slice();
}
if (!isEmberArray(haystack)) {
return false;
}
Expand Down
16 changes: 11 additions & 5 deletions addon/utils/as-array.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { isArray } from '@ember/array';
import EmberObject, { get } from '@ember/object';
import { PromiseManyArray } from '@ember-data/model/-private';

function isIterable(value) {
return Symbol.iterator in Object(value);
}

// from https://github.com/flexyford/ember-power-select/blob/78a5430c1ac89daf315d0801fd5201e444e82434/addon/components/power-select.ts
function isArrayable(thing) {
return typeof thing.toArray === 'function';
return isSliceable(thing);
}

export function isSliceable(thing) {
return typeof thing?.slice === 'function';
}

function isPromiseLike(thing) {
return typeof thing.then === 'function';
return typeof thing?.then === 'function';
}

function isPromiseProxyLike(thing) {
Expand Down Expand Up @@ -40,6 +44,8 @@ function _asArray(maybeArray) {
// for perf-reasons falling back to e-array, instead of using it first
if (Array.isArray(maybeArray)) {
return maybeArray;
} else if (maybeArray instanceof PromiseManyArray) {
return get(maybeArray, 'content')?.slice() ?? [];
} else if (isArray(maybeArray)) {
return maybeArray;
} else if (typeof maybeArray === 'object' && maybeArray === null) {
Expand All @@ -61,7 +67,7 @@ function _asArray(maybeArray) {
throw new Error('Unknown content type in array-like object [ember-composable-helpers]');
}
if (isArrayable(content)) {
return content.toArray();
return content.slice();
} else {
return _asArray(content);
}
Expand All @@ -70,7 +76,7 @@ function _asArray(maybeArray) {
throw new Error('Promise-like objects is not supported as arrays [ember-composable-helpers]');
}
if (isArrayable(maybeArray)) {
return maybeArray.toArray();
return maybeArray.slice();
}
if (maybeArray instanceof EmberObject) {
throw new Error('EmberObjects is not supported as arrays [ember-composable-helpers]')
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/helpers/next-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ module('Integration | Helper | {{next}}', function(hooks) {
store.createRecord('pet', { name: 'Jake' })
]);

this.set('pets', person.pets.toArray());
this.set('pets', person.pets.slice());
this.set('currentPet', person.get('pets.firstObject'));

await render(hbs`
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/helpers/previous-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ module('Integration | Helper | {{previous}}', function(hooks) {
store.createRecord('pet', { name: 'Jake' })
]);

this.set('pets', person.pets.toArray());
this.set('pets', person.pets.slice());
this.set('currentPet', person.get('pets.lastObject'));

await render(hbs`
Expand Down
12 changes: 6 additions & 6 deletions tests/unit/utils/as-array-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ module('Unit | Utility | as-array', function () {
assert.equal(result.length, 3);
});

test('it works for [Object.toArray()]', function (assert) {
test('it works for [Object.slice()]', function (assert) {
let result = asArray({
a: 1, toArray() {
a: 1, slice() {
return [1, 2, 3];
}
});
Expand Down Expand Up @@ -86,10 +86,10 @@ module('Unit | Utility | as-array', function () {
assert.equal(asArray(item).length, 3);
});

test('it works for object-like content in array-proxy-like items [objects toArray]', function (assert) {
test('it works for object-like content in array-proxy-like items [objects slice]', function (assert) {
const item = new Promise((r) => r());
item.content = {
a: 1, toArray() {
a: 1, slice() {
return [1, 2, 3]
}
};
Expand All @@ -102,8 +102,8 @@ module('Unit | Utility | as-array', function () {
assert.equal(asArray(item).length, 3);
});

test('it works for ember object with toArray property [EmberObject]', function (assert) {
const item = EmberObject.extend({ toArray() { return [1, 2, 3] } }).create();
test('it works for ember object with slice property [EmberObject]', function (assert) {
const item = EmberObject.extend({ slice() { return [1, 2, 3] } }).create();
assert.equal(asArray(item).length, 3);
});

Expand Down