8000 Merge pull request #144 from js-data/feat-collections · StudyForFun/js-data@5abe7c8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5abe7c8

Browse files
committed
Merge pull request js-data#144 from js-data/feat-collections
Feat collections
2 parents 8e42150 + 24bff90 commit 5abe7c8

File tree

11 files changed

+253
-74
lines changed

11 files changed

+253
-74
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@
77
- #131 - array of IDs based hasMany relations
88
- #132 - Allow resources to extend other resources
99
- #133 - Allow filtering by nested fields
10+
- #135 - JSData caching inconsistence behaviour when ejecting items
11+
- #139 - Option to specify default values of new resource instances.
1012

1113
###### Backwards compatible bug fixes
1214
- #127 - Memory leak in DS.changes
15+
- #134 - All resources get all methods defined on any resource
16+
- #142 - Allow omitting options in getEndpoint
1317

1418
##### 2.0.0-beta.4 - 28 April 2015
1519

src/datastore/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ var defaultsPrototype = Defaults.prototype;
6969

7070
defaultsPrototype.actions = {};
7171
defaultsPrototype.afterCreate = lifecycleNoopCb;
72+
defaultsPrototype.afterCreateCollection = lifecycleNoop;
7273
defaultsPrototype.afterCreateInstance = lifecycleNoop;
7374
defaultsPrototype.afterDestroy = lifecycleNoopCb;
7475
defaultsPrototype.afterEject = lifecycleNoop;
@@ -79,6 +80,7 @@ defaultsPrototype.afterValidate = lifecycleNoopCb;
7980
defaultsPrototype.allowSimpleWhere = true;
8081
defaultsPrototype.basePath = '';
8182
defaultsPrototype.beforeCreate = lifecycleNoopCb;
83+
defaultsPrototype.beforeCreateCollection = lifecycleNoop;
8284
defaultsPrototype.beforeCreateInstance = lifecycleNoop;
8385
defaultsPrototype.beforeDestroy = lifecycleNoopCb;
8486
defaultsPrototype.beforeEject = lifecycleNoop;
@@ -88,8 +90,11 @@ defaultsPrototype.beforeUpdate = lifecycleNoopCb;
8890
defaultsPrototype.beforeValidate = lifecycleNoopCb;
8991
defaultsPrototype.bypassCache = false;
9092
defaultsPrototype.cacheResponse = !!DSUtils.w;
93+
defaultsPrototype.clearEmptyQueries = true;
94+
defaultsPrototype.computed = {};
9195
defaultsPrototype.defaultAdapter = 'http';
9296
defaultsPrototype.debug = true;
97+
defaultsPrototype.defaultValues = {};
9398
defaultsPrototype.eagerEject = false;
9499
// TODO: Implement eagerInject in DS#create
95100
defaultsPrototype.eagerInject = false;
@@ -112,6 +117,7 @@ defaultsPrototype.logFn = function (a, b, c, d) {
112117
};
113118

114119
defaultsPrototype.maxAge = false;
120+
defaultsPrototype.methods = {};
115121
defaultsPrototype.notify = !!DSUtils.w;
116122
defaultsPrototype.reapAction = !!DSUtils.w ? 'inject' : 'none';
117123
defaultsPrototype.reapInterval = !!DSUtils.w ? 30000 : false;

src/datastore/sync_methods/defineResource.js

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,17 @@ export default function defineResource(definition) {
3535
}
3636

3737
function Resource(options) {
38+
this.defaultValues = {};
39+
this.methods = {};
40+
this.computed = {};
3841
DSUtils.deepMixIn(this, options);
42+
let parent = _this.defaults;
43+
if (definition.extends && definitions[definition.extends]) {
44+
parent = definitions[definition.extends];
45+
}
46+
DSUtils.fillIn(this.defaultValues, parent.defaultValues);
47+
DSUtils.fillIn(this.methods, parent.methods);
48+
DSUtils.fillIn(this.computed, parent.computed);
3949
this.endpoint = ('endpoint' in options) ? options.endpoint : this.name;
4050
}
4151

@@ -102,6 +112,7 @@ export default function defineResource(definition) {
102112
};
103113

104114
def.getEndpoint = (id, options) => {
115+
options = options || {};
105116
options.params = options.params || {};
106117

107118
let item;
@@ -172,9 +183,9 @@ export default function defineResource(definition) {
172183
}
173184

174185
// Apply developer-defined methods
175-
if (def.methods) {
176-
DSUtils.deepMixIn(def[_class].prototype, def.methods);
177-
}
186+
DSUtils.forOwn(def.methods, (fn, m) => {
187+
def[_class].prototype[m] = fn;
188+
});
178189

179190
def[_class].prototype.set = function (key, value) {
180191
DSUtils.set(this, key, value);
@@ -189,34 +200,32 @@ export default function defineResource(definition) {
189200
DSUtils.applyRelationGettersToTarget(_this, def, def[_class].prototype);
190201

191202
// Prepare for computed properties
192-
if (def.computed) {
193-
DSUtils.forOwn(def.computed, (fn, field) => {
194-
if (DSUtils.isFunction(fn)) {
195-
def.computed[field] = [fn];
196-
fn = def.computed[field];
197-
}
198-
if (def.methods && field in def.methods) {
199-
def.errorFn(`Computed property "${field}" conflicts with previously defined prototype method!`);
200-
}
201-
var deps;
202-
if (fn.length === 1) {
203-
let match = fn[0].toString().match(/function.*?\(([\s\S]*?)\)/);
204-
deps = match[1].split(',');
205-
def.computed[field] = deps.concat(fn);
206-
fn = def.computed[field];
207-
if (deps.length) {
208-
def.errorFn('Use the computed property array syntax for compatibility with minified code!');
209-
}
203+
DSUtils.forOwn(def.computed, (fn, field) => {
204+
if (DSUtils.isFunction(fn)) {
205+
def.computed[field] = [fn];
206+
fn = def.computed[field];
207+
}
208+
if (def.methods && field in def.methods) {
209+
def.errorFn(`Computed property "${field}" conflicts with previously defined prototype method!`);
210+
}
211+
var deps;
212+
if (fn.length === 1) {
213+
let match = fn[0].toString().match(/function.*?\(([\s\S]*?)\)/);
214+
deps = match[1].split(',');
215+
def.computed[field] = deps.concat(fn);
216+
fn = def.computed[field];
217+
if (deps.length) {
218+
def.errorFn('Use the computed property array syntax for compatibility with minified code!');
210219
}
211-
deps = fn.slice(0, fn.length - 1);
212-
DSUtils.forEach(deps, (val, index) => {
213-
deps[index] = val.trim();
214-
});
215-
fn.deps = DSUtils.filter(deps, dep => {
216-
return !!dep;
217-
});
220+
}
221+
deps = fn.slice(0, fn.length - 1);
222+
DSUtils.forEach(deps, (val, index) => {
223+
deps[index] = val.trim();
218224
});
219-
}
225+
fn.deps = DSUtils.filter(deps, dep => {
226+
return !!dep;
227+
});
228+
});
220229

221230
DSUtils.forEach(instanceMethods, name => {
222231
def[_class].prototype[`DS${DSUtils.pascalCase(name)}`] = function (...args) {
@@ -250,7 +259,7 @@ export default function defineResource(definition) {
250259
};
251260

252261
if (def.reapInterval) {
253-
setInterval(() => _this.reap(def.n, { isInterval: true }), def.reapInterval);
262+
setInterval(() => _this.reap(def.n, {isInterval: true}), def.reapInterval);
254263
}
255264

256265
// Proxy DS methods with shorthand ones

src/datastore/sync_methods/eject.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default function eject(resourceName, id, options) {
4949
if (items.$$injected) {
5050
DSUtils.remove(items, item);
5151
}
52-
if (!items.length) {
52+
if (!items.length && options.clearEmptyQueries) {
5353
toRemove.push(queryHash);
5454
}
5555
});

src/datastore/sync_methods/index.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ export default {
130130

131131
let Constructor = definition[definition.class];
132132
item = new Constructor();
133+
if (options.defaultValues) {
134+
DSUtils.deepMixIn(item, options.defaultValues);
135+
}
133136
DSUtils.deepMixIn(item, attrs);
134137
if (definition.computed) {
135138
this.compute(definition.name, item);
@@ -139,6 +142,63 @@ export default {
139142
}
140143
return item;
141144
},
145+
createCollection(resourceName, arr, params, options) {
146+
let _this = this;
147+
let definition = _this.defs[resourceName];
148+
149+
arr = arr || [];
150+
params = params || {};
151+
152+
if (!definition) {
153+
throw new NER(resourceName);
154+
} else if (arr && !DSUtils.isArray(arr)) {
155+
throw new IA('"arr" must be an array!');
156+
}
157+
158+
options = DSUtils._(definition, options);
159+
160+
options.logFn('createCollection', arr, options);
161+
162+
if (options.notify) {
163+
options.beforeCreateCollection(options, arr);
164+
}
165+
166+
Object.defineProperties(arr, {
167+
fetch: {
168+
value: function (params, options) {
169+
let __this = this;
170+
__this.params = params || __this.params;
171+
return _this.findAll(resourceName, __this.params, options).then(function (data) {
172+
if (data === __this) {
173+
return __this;
174+
}
175+
data.unshift(__this.length);
176+
data.unshift(0);
177+
__this.splice.apply(__this, data);
178+
data.shift();
179+
data.shift();
180+
if (data.$$injected) {
181+
_this.s[resourceName].queryData[DSUtils.toJson(__this.params)] = __this;
182+
__this.$$injected = true;
183+
}
184+
return __this;
185+
});
186+
}
187+
},
188+
params: {
189+
value: params,
190+
writable: true
191+
},
192+
resourceName: {
193+
value: resourceName
194+
}
195+
});
196+
197+
if (options.notify) {
198+
options.afterCreateCollection(options, arr);
199+
}
200+
return arr;
201+
},
142202
defineResource,
143203
digest() {
144204
this.observe.Platform.performMicrotaskCheckpoint();

src/utils.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,14 @@ export default {
414414
equals,
415415
Events,
416416
filter,
417+
fillIn(target, obj) {
418+
forOwn(obj, (v, k) => {
419+
if (!(k in target)) {
420+
target[k] = v;
421+
}
422+
});
423+
return target;
424+
},
417425
forEach,
418426
forOwn,
419427
fromJson(json) {

test/both/datastore/sync_methods/createInstance.test.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe('DS#createInstance', function () {
2424
});
2525

2626
it('create an instance', function () {
27-
store.defineResource({
27+
var Person = store.defineResource({
2828
name: 'person',
2929
methods: {
3030
fullName: function () {
@@ -39,11 +39,10 @@ describe('DS#createInstance', function () {
3939
});
4040

4141
store.defineResource({
42-
name: 'dog',
43-
useClass: true
42+
name: 'dog'
4443
});
4544

46-
store.defineResource({
45+
var Cat = store.defineResource({
4746
name: 'cat'
4847
});
4948

test/both/datastore/sync_methods/defineResource.test.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,4 +225,23 @@ describe('DS#defineResource', function () {
225225
assert.equal(Foo.getEndpoint(foo, {}), 'baz/10/foo');
226226
assert.equal(Bar.getEndpoint(bar, {}), 'baz/10/bar');
227227
});
228+
it('should allow default instance values', function () {
229+
store.defineResource('baz');
230+
var Foo = store.defineResource({
231+
name: 'foo',
232+
defaultValues: {
233+
beep: 'boop',
234+
foo: true
235+
}
236+
});
237+
var foo = Foo.createInstance({ id: 1, foo: false, type: 'foo', bazId: 10 });
238+
239+
assert.equal(DSUtils.toJson(foo), DSUtils.toJson({
240+
beep: 'boop',
241+
foo: false,
242+
id: 1,
243+
type: 'foo',
244+
bazId: 10
245+
}));
246+
});
228247
});

0 commit comments

Comments
 (0)
0