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

[PERF] make internal model lazier #4562

Merged
merged 1 commit into from
Oct 21, 2016
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
442 changes: 277 additions & 165 deletions addon/-private/system/model/internal-model.js

Large diffs are not rendered by default.

15 changes: 10 additions & 5 deletions addon/-private/system/model/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many'
import { DidDefinePropertyMixin, RelationshipsClassMethodsMixin, RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext';
import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr';
import isEnabled from 'ember-data/-private/features';
import RootState from 'ember-data/-private/system/model/states';

const {
get,
computed
} = Ember;

/**
@module ember-data
*/

var get = Ember.get;

function intersection (array1, array2) {
var result = [];
array1.forEach((element) => {
Expand All @@ -30,7 +34,7 @@ var RESERVED_MODEL_PROPS = [
'currentState', 'data', 'store'
];

var retrieveFromCurrentState = Ember.computed('currentState', function(key) {
var retrieveFromCurrentState = computed('currentState', function(key) {
return get(this._internalModel.currentState, key);
}).readOnly();

Expand Down Expand Up @@ -122,7 +126,7 @@ var Model = Ember.Object.extend(Ember.Evented, {
@type {Boolean}
@readOnly
*/
hasDirtyAttributes: Ember.computed('currentState.isDirty', function() {
hasDirtyAttributes: computed('currentState.isDirty', function() {
return this.get('currentState.isDirty');
}),
/**
Expand Down Expand Up @@ -305,6 +309,7 @@ var Model = Ember.Object.extend(Ember.Evented, {
@private
@type {Object}
*/
currentState: RootState.empty,

/**
When the record is in the `invalid` state this object will contain
Expand Down Expand Up @@ -357,7 +362,7 @@ var Model = Ember.Object.extend(Ember.Evented, {
@property errors
@type {DS.Errors}
*/
errors: Ember.computed(function() {
errors: computed(function() {
let errors = Errors.create();

errors._registerHandlers(this._internalModel,
Expand Down
11 changes: 3 additions & 8 deletions addon/-private/system/model/states.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
/**
@module ember-data
*/
import Ember from 'ember';
import { assert } from "ember-data/-private/debug";

const { get } = Ember;
/*
This file encapsulates the various states that a record can transition
through during its lifecycle.
Expand Down Expand Up @@ -257,7 +255,7 @@ const DirtyState = {
heimdall.stop(token);
},

becomeDirty() { },
becomeDirty() {},

willCommit(internalModel) {
internalModel.transitionTo('inFlight');
Expand Down Expand Up @@ -430,7 +428,7 @@ createdState.uncommitted.pushedData = function(internalModel) {
internalModel.triggerLater('didLoad');
};

createdState.uncommitted.propertyWasReset = Ember.K;
createdState.uncommitted.propertyWasReset = function() {};

function assertAgainstUnloadRecord(internalModel) {
assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false);
Expand Down Expand Up @@ -581,9 +579,7 @@ const RootState = {
internalModel.transitionTo('deleted.saved');
},

didCommit(internalModel) {
internalModel.send('invokeLifecycleCallbacks', get(internalModel, 'lastDirtyType'));
},
didCommit() {},

// loaded.saved.notFound would be triggered by a failed
// `reload()` on an unchanged record
Expand Down Expand Up @@ -715,7 +711,6 @@ const RootState = {
deleteRecord() { },
willCommit() { },


rolledBack(internalModel) {
internalModel.clearErrorMessages();
internalModel.transitionTo('loaded.saved');
Expand Down
9 changes: 7 additions & 2 deletions addon/-private/system/record-array-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ import {
FilteredRecordArray,
AdapterPopulatedRecordArray
} from "ember-data/-private/system/record-arrays";
const { get, MapWithDefault } = Ember;
import OrderedSet from "ember-data/-private/system/ordered-set";

const {
get,
MapWithDefault,
run: emberRun
} = Ember;

const {
_addRecordToRecordArray,
_recordWasChanged,
Expand Down Expand Up @@ -78,7 +83,7 @@ export default Ember.Object.extend({
heimdall.increment(recordDidChange);
if (this.changedRecords.push(record) !== 1) { return; }

Ember.run.schedule('actions', this, this.updateRecordArrays);
emberRun.schedule('actions', this, this.updateRecordArrays);
},

recordArraysForRecord(record) {
Expand Down
59 changes: 22 additions & 37 deletions addon/-private/system/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import Model from 'ember-data/model';
import { instrument, assert, warn, runInDebug } from "ember-data/-private/debug";
import _normalizeLink from "ember-data/-private/system/normalize-link";
import normalizeModelName from "ember-data/-private/system/normalize-model-name";
import {
InvalidError
} from 'ember-data/adapters/errors';
import { InvalidError } from 'ember-data/adapters/errors';

import {
promiseArray,
Expand All @@ -22,13 +20,8 @@ import {
_objectIsAlive
} from "ember-data/-private/system/store/common";

import {
normalizeResponseHelper
} from "ember-data/-private/system/store/serializer-response";

import {
serializerForAdapter
} from "ember-data/-private/system/store/serializers";
import { normalizeResponseHelper } from "ember-data/-private/system/store/serializer-response";
import { serializerForAdapter } from "ember-data/-private/system/store/serializers";

import {
_find,
Expand All @@ -40,25 +33,27 @@ import {
_queryRecord
} from "ember-data/-private/system/store/finders";

import {
getOwner
} from 'ember-data/-private/utils';

import { getOwner } from 'ember-data/-private/utils';
import coerceId from "ember-data/-private/system/coerce-id";

import RecordArrayManager from "ember-data/-private/system/record-array-manager";
import ContainerInstanceCache from 'ember-data/-private/system/store/container-instance-cache';

import InternalModel from "ember-data/-private/system/model/internal-model";

import EmptyObject from "ember-data/-private/system/empty-object";

import isEnabled from 'ember-data/-private/features';

export let badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number';

const Backburner = Ember._Backburner;
var Map = Ember.Map;
const {
_Backburner: Backburner,
copy,
get,
isNone,
isPresent,
Map,
run: emberRun,
set,
Service
} = Ember;

//Get the materialized model from the internalModel/promise that returns
//an internal model and return it in a promiseObject. Useful for returning
Expand All @@ -68,19 +63,9 @@ function promiseRecord(internalModel, label) {
return promiseObject(toReturn, label);
}

var once = Ember.run.once;
var Promise = Ember.RSVP.Promise;
var Store;
const Promise = Ember.RSVP.Promise;

const {
copy,
get,
GUID_KEY,
isNone,
isPresent,
set,
Service
} = Ember;
let Store;

// Implementors Note:
//
Expand Down Expand Up @@ -807,7 +792,7 @@ Store = Service.extend({
} else {
this._pendingFetch.get(typeClass).push(pendingFetchItem);
}
Ember.run.scheduleOnce('afterRender', this, this.flushAllPendingFetches);
emberRun.scheduleOnce('afterRender', this, this.flushAllPendingFetches);

return promise;
},
Expand Down Expand Up @@ -1784,7 +1769,7 @@ Store = Service.extend({
snapshot: snapshot,
resolver: resolver
});
once(this, 'flushPendingSave');
emberRun.once(this, this.flushPendingSave);
},

/**
Expand Down Expand Up @@ -1839,7 +1824,7 @@ Store = Service.extend({
}
if (data) {
// normalize relationship IDs into records
this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data);
this._backburner.schedule('normalizeRelationships', this, this._setupRelationships, internalModel, data);
this.updateId(internalModel, data);
} else {
assert(`Your ${internalModel.type.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id);
Expand Down Expand Up @@ -1893,7 +1878,7 @@ Store = Service.extend({
var id = coerceId(data.id);

// ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record)
assert(`'${internalModel.type.modelName}:${internalModel[GUID_KEY]}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null));
assert(`'${internalModel.type.modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null));

// ID absolutely can't be different than oldID if oldID is not null
assert(`'${internalModel.type.modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId));
Expand Down Expand Up @@ -2262,7 +2247,7 @@ Store = Service.extend({
var internalModel = this._load(data);

this._backburner.join(() => {
this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data);
this._backburner.schedule('normalizeRelationships', this, this._setupRelationships, internalModel, data);
});

return internalModel;
Expand Down
2 changes: 1 addition & 1 deletion ember-cli-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module.exports = function(defaults) {
babel: {
plugins: [
// while ember-data strips itself, ember does not currently
{transformer: stripClassCallCheck, position: 'after'}
{ transformer: stripClassCallCheck, position: 'after' }
]
}
});
Expand Down
3 changes: 2 additions & 1 deletion lib/babel-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ function babelOptions(libraryName, _options) {
'es6.properties.shorthand',
'es6.blockScoping',
'es6.constants',
'es6.modules'
'es6.modules',
'es6.classes'
],
sourceMaps: false,
modules: 'amdStrict',
Expand Down
4 changes: 3 additions & 1 deletion lib/stripped-build-plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var path = require('path');
var filterImports = require('babel-plugin-filter-imports');
var featureFlags = require('babel-plugin-feature-flags');
var stripHeimdall = require('babel5-plugin-strip-heimdall');
var stripClassCallCheck = require('babel5-plugin-strip-class-callcheck');

function uniqueAdd(obj, key, values) {
var a = obj[key] = obj[key] || [];
Expand Down Expand Up @@ -32,7 +33,8 @@ module.exports = function(environment) {
featureFlags({
import: { module: 'ember-data/-private/features' },
features: features
})
}),
{ transformer: stripClassCallCheck, position: 'after' }
];

if (process.env.INSTRUMENT_HEIMDALL === 'false') {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/store/unload-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ testInDebug("unload a dirty record asserts", function(assert) {

assert.expectAssertion(function() {
record.unloadRecord();
}, "You can only unload a record which is not inFlight. `" + Ember.inspect(record) + "`", "can not unload dirty record");
}, "You can only unload a record which is not inFlight. `" + record._internalModel.toString() + "`", "can not unload dirty record");

// force back into safe to unload mode.
run(function() {
Expand Down