ember-m3
Version:
Alternative to @ember-data/model in which attributes and relationships are derived from API Payloads
105 lines (90 loc) • 3.23 kB
JavaScript
import Ember from 'ember';
import { notifyPropertyChange as _notifyPropertyChange } from '@ember/object';
import { assert } from '@ember/debug';
import { DEBUG } from '@glimmer/env';
const { changeProperties } = Ember;
const { propertyDidChange } = Ember;
export let notifyPropertyChange;
const HasNotifyPropertyChange = _notifyPropertyChange !== undefined;
if (HasNotifyPropertyChange) {
notifyPropertyChange = _notifyPropertyChange;
} else {
notifyPropertyChange = propertyDidChange;
}
// Separate array & prop changes for simplicity. This prevents us from
// re-issuing the property changes in order, but Ember already triggers array
// changes eagerly, even within `changeProperties`
// WeakMap<Store, [obj, startIdx: number, removeCount: number, addCount: number]>
const StoreToArrayChanges = new WeakMap();
// WeakMap<Store, [obj, property: string]>
const StoreToPropChanges = new WeakMap();
function getPropertyChanges(store) {
if (!StoreToPropChanges.has(store)) {
StoreToPropChanges.set(store, []);
}
return StoreToPropChanges.get(store);
}
function getArrayChanges(store) {
if (!StoreToArrayChanges.has(store)) {
StoreToArrayChanges.set(store, []);
}
return StoreToArrayChanges.get(store);
}
export function deferPropertyChange(store, obj, key) {
getPropertyChanges(store).push(obj, key);
}
export function deferArrayPropertyChange(store, array, start, deleteCount, addCount) {
if (DEBUG) {
// don't assert Ember.isArray as that will return true for native arrays
assert(
`deferArrayPropertyChange called on something other than an Ember array; wrap native arrays with Ember.A(array) or enable Array prototype extensions`,
typeof array.arrayContentDidChange === 'function'
);
}
getArrayChanges(store).push(array, start, deleteCount, addCount);
}
function flushArrayChanges(store) {
let changes = StoreToArrayChanges.get(store) || [];
changeProperties(() => {
for (let i = 0; i < changes.length; i += 4) {
let array = changes[i];
let startIdx = changes[i + 1];
let removeCount = changes[i + 2];
let addCount = changes[i + 3];
array.arrayContentDidChange(startIdx, removeCount, addCount);
}
});
StoreToArrayChanges.set(store, []);
}
function flushPropChanges(store) {
let changes = StoreToPropChanges.get(store) || [];
changeProperties(() => {
for (let i = 0; i < changes.length; i += 2) {
let obj = changes[i];
let change = changes[i + 1];
notifyPropertyChange(obj, change);
}
});
StoreToPropChanges.set(store, []);
}
export function flushChanges(store) {
changeProperties(() => {
flushArrayChanges(store);
flushPropChanges(store);
});
}
export function assertNoChanges(store) {
if (DEBUG) {
let propChanges = StoreToPropChanges.get(store) || [];
let changedProps = propChanges.filter((o, i) => i % 2 === 1);
assert(
`There should be no queued changes, but we have: ${changedProps.join(', ')} `,
changedProps.length === 0
);
let arrayChanges = StoreToArrayChanges.get(store) || [];
assert(
`There should be no queued array changes, but we have: ${arrayChanges.length} `,
arrayChanges.length === 0
);
}
}