Skip to content

Commit 67d61ac

Browse files
committed
feat(loki): chained/transform map op now accepts 'dataOptions' for clone/removeMeta (#34)
(from techfort/LokiJS#618)
1 parent efa450e commit 67d61ac

File tree

2 files changed

+113
-4
lines changed

2 files changed

+113
-4
lines changed

packages/loki/spec/generic/transforms.spec.js

+98
Original file line numberDiff line numberDiff line change
@@ -199,5 +199,103 @@ describe("transforms", () => {
199199

200200
});
201201
});
202+
describe("eqJoin step with dataOptions works", function () {
203+
it("works", () => {
204+
const db1 = new loki("testJoins");
205+
206+
const directors = db1.addCollection("directors");
207+
const films = db1.addCollection("films");
208+
209+
directors.insert([
210+
{name: "Martin Scorsese", directorId: 1},
211+
{name: "Francis Ford Coppola", directorId: 2},
212+
{name: "Steven Spielberg", directorId: 3},
213+
{name: "Quentin Tarantino", directorId: 4}
214+
]);
215+
216+
films.insert([
217+
{title: "Taxi", filmId: 1, directorId: 1},
218+
{title: "Raging Bull", filmId: 2, directorId: 1},
219+
{title: "The Godfather", filmId: 3, directorId: 2},
220+
{title: "Jaws", filmId: 4, directorId: 3},
221+
{title: "ET", filmId: 5, directorId: 3},
222+
{title: "Raiders of the Lost Ark", filmId: 6, directorId: 3}
223+
]);
224+
225+
// Since our collection options do not specify cloning, this is only safe
226+
// because we have cloned internal objects with dataOptions before modifying them.
227+
function fdmap(left, right) {
228+
// PhantomJS does not support es6 Object.assign
229+
//left = Object.assign(left, right);
230+
Object.keys(right).forEach((key) => {
231+
left[key] = right[key];
232+
});
233+
return left;
234+
}
235+
236+
// The 'joinData' in this instance is a Collection which we will call
237+
// data() on with the specified (optional) dataOptions on.
238+
// It could also be a resultset or data array.
239+
// Our left side resultset which this transform is executed on will also
240+
// call data() with specified (optional) dataOptions.
241+
films.addTransform("filmdirect", [
242+
{
243+
type: "eqJoin",
244+
joinData: directors,
245+
leftJoinKey: "directorId",
246+
rightJoinKey: "directorId",
247+
mapFun: fdmap,
248+
dataOptions: {removeMeta: true}
249+
}
250+
]);
251+
252+
// Although we removed all meta, the eqjoin inserts the resulting objects
253+
// into a new volatile collection which would adds its own meta and loki.
254+
// We don't care about these useless volatile data so grab results without it.
255+
const results = films.chain("filmdirect").data({removeMeta: true});
256+
257+
expect(results.length).toEqual(6);
258+
expect(results[0].title).toEqual("Taxi");
259+
expect(results[0].name).toEqual("Martin Scorsese");
260+
expect(results[5].title).toEqual("Raiders of the Lost Ark");
261+
expect(results[5].name).toEqual("Steven Spielberg");
262+
results.forEach((obj) => {
263+
expect(Object.keys(obj).length).toEqual(4);
264+
});
265+
});
266+
});
202267

268+
describe("map step with dataOptions works", function () {
269+
it("works", () => {
270+
const db1 = new loki("testJoins");
271+
272+
const c1 = db1.addCollection("c1");
273+
c1.insert([{a: 1, b: 9}, {a: 2, b: 8}, {a: 3, b: 7}, {a: 4, b: 6}]);
274+
275+
// only safe because our 'removeMeta' option will clone objects passed in
276+
function graftMap(obj) {
277+
obj.c = obj.b - obj.a;
278+
return obj;
279+
}
280+
281+
const tx = [{
282+
type: "map",
283+
value: graftMap,
284+
dataOptions: {removeMeta: true}
285+
}];
286+
287+
const results = c1.chain(tx).data({removeMeta: true});
288+
289+
expect(results.length).toEqual(4);
290+
expect(results[0].a).toEqual(1);
291+
expect(results[0].b).toEqual(9);
292+
expect(results[0].c).toEqual(8);
293+
expect(results[3].a).toEqual(4);
294+
expect(results[3].b).toEqual(6);
295+
expect(results[3].c).toEqual(2);
296+
results.forEach((obj) => {
297+
expect(Object.keys(obj).length).toEqual(3);
298+
});
299+
});
300+
});
203301
});

packages/loki/src/resultset.js

+15-4
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ export class Resultset {
442442
rs = rs.offset(step.value);
443443
break; // offset makes copy so update reference
444444
case "map":
445-
rs = rs.map(step.value);
445+
rs = rs.map(step.value, step.dataOptions);
446446
break;
447447
case "eqJoin":
448448
rs = rs.eqJoin(step.joinData, step.leftJoinKey, step.rightJoinKey, step.mapFun, step.dataOptions);
@@ -1129,7 +1129,10 @@ export class Resultset {
11291129
* @param {(string|function)} leftJoinKey - Property name in this result set to join on or a function to produce a value to join on
11301130
* @param {(string|function)} rightJoinKey - Property name in the joinData to join on or a function to produce a value to join on
11311131
* @param {function} [mapFun=] - a function that receives each matching pair and maps them into output objects - function(left,right){return joinedObject}
1132-
* @param {object} dataOptions - optional options to apply to data() calls for left and right sides
1132+
* @param {object} [dataOptions=] - optional options to apply to data() calls for left and right sides
1133+
* @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun
1134+
* @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object
1135+
* @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method.
11331136
* @returns {Resultset} A resultset with data in the format [{left: leftObj, right: rightObj}]
11341137
*/
11351138
eqJoin(joinData, leftJoinKey, rightJoinKey, mapFun, dataOptions) {
@@ -1187,8 +1190,16 @@ export class Resultset {
11871190
return this;
11881191
}
11891192

1190-
map(mapFun) {
1191-
let data = this.data().map(mapFun);
1193+
/**
1194+
* Applies a map function into a new collection for further chaining.
1195+
* @param {function} mapFun - javascript map function
1196+
* @param {object} [dataOptions=] - options to data() before input to your map function
1197+
* @param {boolean} dataOptions.removeMeta - allows removing meta before calling mapFun
1198+
* @param {boolean} dataOptions.forceClones - forcing the return of cloned objects to your map object
1199+
* @param {string} dataOptions.forceCloneMethod - Allows overriding the default or collection specified cloning method.
1200+
*/
1201+
map(mapFun, dataOptions) {
1202+
let data = this.data(dataOptions).map(mapFun);
11921203
//return return a new resultset with no filters
11931204
this.collection = new Collection("mappedData");
11941205
this.collection.insert(data);

0 commit comments

Comments
 (0)