-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
[CHORE]: Extract internalModel access to identifiers in RecordArray modules #6715
Conversation
packages/-ember-data/tests/integration/record-arrays/adapter-populated-record-array-test.js
Outdated
Show resolved
Hide resolved
@@ -3679,75 +3679,70 @@ module('integration/relationships/has_many - Has-Many Relationships', function(h | |||
user: belongsTo('user', { inverse: null, async: false }), | |||
}); | |||
|
|||
run(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just reminding to revisit this...
@@ -122,7 +122,6 @@ export default class InternalModel { | |||
__recordData: RecordData | null; | |||
_isDestroyed: boolean; | |||
isError: boolean; | |||
_pendingRecordArrayManagerFlush: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this state was only used in record-array-manager, so put it there with a Set
of pending identifiers.
|
||
function recordArraysForIdentifier(store, identifier) { | ||
let internalModel = internalModelFactoryFor(store).peek(identifier); | ||
if (internalModel) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was only one failing test that required this guard. disconnectRecord
in store-wrapper-test
. It is pushing with data: []
and included: [houseHash]
. Is this possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out M3 hit this case so I had to make some adjustments, roughly speaking it is possible in the current state of things to try to sync-destroy during push via this API. I'm going to bring this up in a meeting as EmberData does not do a sync-destroy here itself and we likely should not allow it going forward as the "syncLiveArray" code is undesirable complexity that remains from our need to handle observers greedily firing when we begin changes.
We may be able to refactor overtime to avoid delivering changes to the UI until a single "ui flush" which would help us avoid this problem.
The M3 failure is because M3 registers query-arrays (result of M3's queryURL method) with the record-array-manager. There's a few paths forward here:
|
5ceb06e
to
7d8e6de
Compare
@@ -100,7 +100,7 @@ module('integration/record_array_manager', function(hooks) { | |||
assert.equal(allSummary.called.length, 0, 'initial: no calls to all.willDestroy'); | |||
assert.equal(adapterPopulatedSummary.called.length, 0, 'initial: no calls to adapterPopulated.willDestroy'); | |||
assert.equal( | |||
internalPersonModel._recordArrays.size, | |||
manager.getRecordArrayForIdentifier(internalPersonModel.identifier).size, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this method should be getRecordArraysForIdentifier
@@ -100,7 +100,7 @@ module('integration/record_array_manager', function(hooks) { | |||
assert.equal(allSummary.called.length, 0, 'initial: no calls to all.willDestroy'); | |||
assert.equal(adapterPopulatedSummary.called.length, 0, 'initial: no calls to adapterPopulated.willDestroy'); | |||
assert.equal( | |||
internalPersonModel._recordArrays.size, | |||
manager.getRecordArrayForIdentifier(internalPersonModel.identifier).size, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
me and @runspired talked about adding a test to confirm that getRecordArrayForIdentifier
is === _recordArrays
|
||
const emberRun = emberRunloop.backburner; | ||
const pendingForIdentifier = new Set([]); | ||
const IMFallback = new WeakMap(); | ||
const RecordArraysCache = new WeakMap(); // store StableIdentifier => Set[RecordArray[]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move the comment above the line please
After reviewing with @igorT we decided we will
|
c6ab05d
to
ad7fd41
Compare
bcee390
to
c5968e2
Compare
@@ -157,6 +157,7 @@ export default class InternalModel { | |||
_scheduledDestroy: any; | |||
_modelClass: any; | |||
__deferredTriggers: any; | |||
__recordArrays: any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I brought this back b/c we use __recordArrays
in recordArray._dissociateFromOwnRecords
.
Since internal-model
has an identifier regardless of the flag, I think we would be safe to refactor.
@@ -18,7 +19,7 @@ const Person = Model.extend({ | |||
}, | |||
}); | |||
|
|||
module('integration/record-arrays/adapter_populated_record_array - AdapterPopulatedRecordArray', function(hooks) { | |||
module('scott integration/record-arrays/adapter_populated_record_array - AdapterPopulatedRecordArray', function(hooks) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't forget the Scott
removal
62c38ab
to
2020758
Compare
@runspired I believe this PR is ready to review. All tests passed with both feature flags on and off!! |
975f75c
to
eb97486
Compare
eb97486
to
44772f2
Compare
44772f2
to
6b8e07b
Compare
@@ -177,4 +177,6 @@ export default { | |||
REQUEST_SERVICE: null, | |||
CUSTOM_MODEL_CLASS: null, | |||
FULL_LINKS_ON_RELATIONSHIPS: true, | |||
RECORD_ARRAY_MANAGER_IDENTIFIERS: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be null
array._removeInternalModels(modelsToRemove); | ||
} | ||
} | ||
const pushIdentifiers = function(recordArray, identifiers, cache) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we name this function please
const emberRun = emberRunloop.backburner; | ||
let RecordArrayManager; | ||
|
||
export let associateWithRecordArray; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets export this after it's been assigned
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we have this assigned in a conditional block, it only allows us to import/export at the top level.
} | ||
}; | ||
|
||
const destroy = function(entry) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets bring these back into the named style, and see if we run into issues
@@ -2657,7 +2658,12 @@ abstract class CoreStore extends Service { | |||
internalModel.setupData(data); | |||
|
|||
if (!isUpdate) { | |||
this.recordArrayManager.recordDidChange(internalModel); | |||
// TODO: do we want to maintain old API with this flag? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a leftover comment
this.recordArrayManager.recordDidChange(internalModel); | ||
// TODO: do we want to maintain old API with this flag? | ||
if (RECORD_ARRAY_MANAGER_IDENTIFIERS) { | ||
this.recordArrayManager.recordDidChange(internalModel.identifier); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that we use the identifier on line 2644, we could extract the let identifier
@@ -42,6 +44,10 @@ export default class InternalModelMap { | |||
return this._models.length; | |||
} | |||
|
|||
get modelIdentifiers(): StableRecordIdentifier[] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should probably call this recordIdentifiers. We also only use it in a single place, maybe it's not worth creating a method for it?
@@ -1363,8 +1359,14 @@ export default class InternalModel { | |||
@private | |||
*/ | |||
updateRecordArrays() { | |||
// @ts-ignore: Store is untyped and typescript does not detect instance props set in `init` | |||
this.store.recordArrayManager.recordDidChange(this); | |||
// TODO: do we want to maintain old API with this flag? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover comment
this.store.recordArrayManager.recordDidChange(this); | ||
// TODO: do we want to maintain old API with this flag? | ||
if (RECORD_ARRAY_MANAGER_IDENTIFIERS) { | ||
// @ts-ignore: Store is untyped and typescript does not detect instance props set in `init` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ts-ignore
is slightly incorrect, it seems we just need to expose recordArrayManager from CoreStore
REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT, | ||
} from '@ember-data/canary-features'; | ||
|
||
// only used by RECORD_ARRAY_MANAGER_IDENTIFIERS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets remove this comment
|
||
/** | ||
* @method recordDidChange | ||
* @public |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is meant to be public, no?
@param {String} modelName | ||
@param {Object} query | ||
@param {Array} internalModels | ||
@param {Object} payload |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️
} | ||
}; | ||
|
||
const destroy = function destroyEntry(entry) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should make the names consistent
entry.destroy(); | ||
}; | ||
|
||
const remove = function removeEntry(array, item) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should make the names consistent
@param {Object} payload normalized payload | ||
@internal | ||
*/ | ||
AdapterPopulatedRecordArray.prototype._setIdentifiers = function _setIdentifiers(identifiers, payload) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems safer to extend here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! I think the original intention was to work on the object directly instead of subclassing but this works too! Aligns closer to the semantics of defining objects in this file as well.
One question though - When it comes to switching this file over to TS though, would we modify the prototype or subclass?
this.manager._associateWithRecordArray(identifiers, this); | ||
|
||
if (DEPRECATE_EVENTED_API_USAGE) { | ||
const _hasDidLoad = DEBUG ? this._has('didLoad') : this.has('didLoad'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switch with let
@param {Object} payload normalized payload | ||
@internal | ||
*/ | ||
AdapterPopulatedRecordArray.prototype._setIdentifiers = function _setIdentifiers(identifiers, payload) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function setObjects(identifierOrInternalModel) {
// TODO: initial load should not cause change events at all, only
// subsequent. This requires changing the public api of adapter.query, but
// hopefully we can do that soon.
this.get('content').setObjects(identifiers);
this.setProperties({
isLoaded: true,
isUpdating: false,
meta: assign({}, payload.meta),
links: assign({}, payload.links),
});
this.manager._associateWithRecordArray(identifiers, this);
if (DEPRECATE_EVENTED_API_USAGE) {
const _hasDidLoad = DEBUG ? this._has('didLoad') : this.has('didLoad');
if (_hasDidLoad) {
// TODO: should triggering didLoad event be the last action of the runLoop?
once(this, 'trigger', 'didLoad');
}
}
};
}
if (RECORD_ARRAY_MANAGER_IDENTIFIERS) {
AdapterPopulatedRecordArray.prototype._setIdentifiers = function _setIdentifiers(identifiers, payload) {
setObjects(identifiers, payload)
}
} else {
AdapterPopulatedRecordArray.prototype._setInternalModels = function _setInternalModels(internalModels, payload) {
setObjects(identifiers, payload)
}
}
return internalModelForIdentifier(store, identifier).getRecord(); | ||
} | ||
|
||
function internalModelForIdentifier(store, identifier) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably don't need this helper function
@@ -113,8 +124,13 @@ export default ArrayProxy.extend(DeprecatedEvented, { | |||
@return {Model} record | |||
*/ | |||
objectAtContent(index) { | |||
let internalModel = get(this, 'content').objectAt(index); | |||
return internalModel && internalModel.getRecord(); | |||
let identifier = get(this, 'content').objectAt(index); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this might read nicer if
if (RECORD_ARRAY_MANAGER_IDENTIFIERS) {
let identifier = get(this, 'content').objectAt(index);
return identifier ? recordForIdentifier(this.store, identifier) : undefined;
} else {
let internalModel = get(this, 'content').objectAt(index);
return internalModel ? internalModel.getRecord() : undefined;
}
|
||
/* | ||
if (RECORD_ARRAY_MANAGER_IDENTIFIERS) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably be extending here
@@ -2,4 +2,4 @@ | |||
|
|||
{{outlet}} | |||
|
|||
<a href="/tests">Tests</a> | |||
<a href={{"/tests"}}>Tests</a> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets try removing this
const emberRun = emberRunloop.backburner; | ||
let RecordArrayManager; | ||
|
||
export let associateWithRecordArray; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets leave a comment that we should remove this after the FF land
6a1f0f7
to
940efc7
Compare
940efc7
to
65a8ac4
Compare
This is to reduce the need of
InternalModel
throughout the codebase. This is possible because we have an identifier cache available to lookup records that were populated locally. This doesn't encompass all the spots where an identifier can be swapped for an InternalModel, but is a start.Modifications include Record-Array, Record-Array-Manager, Adapter-Populated-Record-Array and Core-Store.
ref #6166