diff --git a/packages/loki/spec/generic/dynamic_view.spec.ts b/packages/loki/spec/generic/dynamic_view.spec.ts index e02f9f9a..59113a72 100644 --- a/packages/loki/spec/generic/dynamic_view.spec.ts +++ b/packages/loki/spec/generic/dynamic_view.spec.ts @@ -3,6 +3,7 @@ import {Loki} from "../../src/loki"; import {MemoryStorage} from "../../../memory-storage/src/memory_storage"; import {Collection} from "../../src/collection"; import {Doc} from "../../../common/types"; +import {LokiOps} from "../../src/result_set"; describe("dynamicviews", () => { interface User { @@ -291,10 +292,10 @@ describe("dynamicviews", () => { expect(resultsNoIndex.length).toEqual(0); const resultsWithIndex = itc.find({ - "testindex": 4 + "testindex": 4 }); //it("no results found", () => { - expect(resultsWithIndex.length).toEqual(0); + expect(resultsWithIndex.length).toEqual(0); //}); }); @@ -343,4 +344,154 @@ describe("dynamicviews", () => { }); }); }); + + it("applySortCriteria", () => { + const db = new Loki("dvtest.db"); + const coll = db.addCollection("any"); + coll.insert([{ + name: "mjolnir", + owner: "odin", + maker: "dwarves", + }, { + name: "tyrfing", + owner: "thor", + maker: "dwarves", + }, { + name: "gungnir", + owner: "odin", + maker: "elves", + }, { + name: "draupnir", + owner: "thor", + maker: "elves", + }]); + const dv = coll.addDynamicView("test"); + + let result = dv.applySortCriteria(["owner", "maker"]).data(); + expect(result).toEqual(dv.applySortCriteria([["owner", false], ["maker", false]]).data()); + expect(result.length).toBe(4); + expect(result[0].name).toBe("mjolnir"); + expect(result[1].name).toBe("gungnir"); + expect(result[2].name).toBe("tyrfing"); + expect(result[3].name).toBe("draupnir"); + + result = dv.applySortCriteria([["owner", false], ["maker", true]]).data(); + expect(result.length).toBe(4); + expect(result[0].name).toBe("gungnir"); + expect(result[1].name).toBe("mjolnir"); + expect(result[2].name).toBe("draupnir"); + expect(result[3].name).toBe("tyrfing"); + + result = dv.applySortCriteria([["owner", true], ["maker", false]]).data(); + expect(result.length).toBe(4); + expect(result[0].name).toBe("tyrfing"); + expect(result[1].name).toBe("draupnir"); + expect(result[2].name).toBe("mjolnir"); + expect(result[3].name).toBe("gungnir"); + + result = dv.applySortCriteria([["owner", true], ["maker", true]]).data(); + expect(result.length).toBe(4); + expect(result[0].name).toBe("draupnir"); + expect(result[1].name).toBe("tyrfing"); + expect(result[2].name).toBe("gungnir"); + expect(result[3].name).toBe("mjolnir"); + + result = dv.applySortCriteria(["maker", "owner"]).data(); + expect(result).toEqual(dv.applySortCriteria([["maker", false], ["owner", false]]).data()); + expect(result.length).toBe(4); + expect(result[0].name).toBe("mjolnir"); + expect(result[1].name).toBe("tyrfing"); + expect(result[2].name).toBe("gungnir"); + expect(result[3].name).toBe("draupnir"); + + result = dv.applySortCriteria([["maker", false], ["owner", true]]).data(); + expect(result.length).toBe(4); + expect(result[0].name).toBe("tyrfing"); + expect(result[1].name).toBe("mjolnir"); + expect(result[2].name).toBe("draupnir"); + expect(result[3].name).toBe("gungnir"); + + result = dv.applySortCriteria([["maker", true], ["owner", false]]).data(); + expect(result.length).toBe(4); + expect(result[0].name).toBe("gungnir"); + expect(result[1].name).toBe("draupnir"); + expect(result[2].name).toBe("mjolnir"); + expect(result[3].name).toBe("tyrfing"); + + result = dv.applySortCriteria([["maker", true], ["owner", true]]).data(); + expect(result.length).toBe(4); + expect(result[0].name).toBe("draupnir"); + expect(result[1].name).toBe("gungnir"); + expect(result[2].name).toBe("tyrfing"); + expect(result[3].name).toBe("mjolnir"); + }); + + describe("dynamic view simplesort options work correctly", () => { + it("works", function () { + const db = new Loki("dvtest.db"); + let coll = db.addCollection<{ a: number, b: number }>("colltest", {indices: ["a", "b"]}); + + // add basic dv with filter on a and basic simplesort on b + let dv = coll.addDynamicView("dvtest"); + dv.applyFind({a: {$lte: 20}}); + dv.applySimpleSort("b"); + + // data only needs to be inserted once since we are leaving collection intact while + // building up and tearing down dynamic views within it + coll.insert([{a: 1, b: 11}, {a: 2, b: 9}, {a: 8, b: 3}, {a: 6, b: 7}, {a: 2, b: 14}, {a: 22, b: 1}]); + + // test whether results are valid + let results = dv.data(); + expect(results.length).toBe(5); + for (let idx = 0; idx < results.length - 1; idx++) { + expect(LokiOps.$lte(results[idx]["b"], results[idx + 1]["b"])); + } + + // remove dynamic view + coll.removeDynamicView("dvtest"); + + // add basic dv with filter on a and simplesort (with js fallback) on b + dv = coll.addDynamicView("dvtest"); + dv.applyFind({a: {$lte: 20}}); + dv.applySimpleSort("b", {useJavascriptSorting: true}); + + // test whether results are valid + // for our simple integer datatypes javascript sorting is same as loki sorting + results = dv.data(); + expect(results.length).toBe(5); + for (let idx = 0; idx < results.length - 1; idx++) { + expect(results[idx]["b"] <= results[idx + 1]["b"]); + } + + // remove dynamic view + coll.removeDynamicView("dvtest"); + + // add basic dv with filter on a and simplesort (forced js sort) on b + dv = coll.addDynamicView("dvtest"); + dv.applyFind({a: {$lte: 20}}); + dv.applySimpleSort("b", {disableIndexIntersect: true, useJavascriptSorting: true}); + + // test whether results are valid + results = dv.data(); + expect(results.length).toBe(5); + for (let idx = 0; idx < results.length - 1; idx++) { + expect(results[idx]["b"] <= results[idx + 1]["b"]); + } + + // remove dynamic view + coll.removeDynamicView("dvtest"); + + // add basic dv with filter on a and simplesort (forced loki sort) on b + dv = coll.addDynamicView("dvtest"); + dv.applyFind({a: {$lte: 20}}); + dv.applySimpleSort("b", {forceIndexIntersect: true}); + + // test whether results are valid + results = dv.data(); + expect(results.length).toBe(5); + for (let idx = 0; idx < results.length - 1; idx++) { + expect(LokiOps.$lte(results[idx]["b"], results[idx + 1]["b"])); + } + }); + }); }); diff --git a/packages/loki/spec/generic/sortingIndexing.spec.ts b/packages/loki/spec/generic/sortingIndexing.spec.ts index e763a4d7..bd980063 100644 --- a/packages/loki/spec/generic/sortingIndexing.spec.ts +++ b/packages/loki/spec/generic/sortingIndexing.spec.ts @@ -1,6 +1,7 @@ /* global describe, beforeEach, it, expect */ import {Loki} from "../../src/loki"; import {Collection} from "../../src/collection"; +import {LokiOps} from "../../src/result_set"; describe("sorting and indexing", () => { let db: Loki; @@ -8,223 +9,209 @@ describe("sorting and indexing", () => { db = new Loki("sortingIndexingTest"); }); - describe("ResultSet simplesort", () => { - it("works", () => { - interface Sortable { - a: number; - b: number; - } + it("ResultSet simplesort", () => { + interface Sortable { + a: number; + b: number; + } - const rss = db.addCollection("rssort"); + const rss = db.addCollection("rssort"); - rss.insert({a: 4, b: 2}); - rss.insert({a: 7, b: 1}); - rss.insert({a: 3, b: 4}); - rss.insert({a: 9, b: 5}); + rss.insert({a: 4, b: 2}); + rss.insert({a: 7, b: 1}); + rss.insert({a: 3, b: 4}); + rss.insert({a: 9, b: 5}); - const results = rss.chain().simplesort("a").data(); - expect(results[0].a).toBe(3); - expect(results[1].a).toBe(4); - expect(results[2].a).toBe(7); - expect(results[3].a).toBe(9); - }); + const results = rss.chain().simplesort("a").data(); + expect(results[0].a).toBe(3); + expect(results[1].a).toBe(4); + expect(results[2].a).toBe(7); + expect(results[3].a).toBe(9); }); - describe("ResultSet simplesort descending", () => { - it("works", () => { - interface Sortable { - a: number; - b: number; - } - - const rss = db.addCollection("rssort"); - - rss.insert({a: 4, b: 2}); - rss.insert({a: 7, b: 1}); - rss.insert({a: 3, b: 4}); - rss.insert({a: 9, b: 5}); - - let results = rss.chain().simplesort("a", true).data(); - expect(results[0].a).toBe(9); - expect(results[1].a).toBe(7); - expect(results[2].a).toBe(4); - expect(results[3].a).toBe(3); - - // test when indexed - const rss2 = db.addCollection("rssort2", {indices: ["a"]}); - - rss2.insert({a: 4, b: 2}); - rss2.insert({a: 7, b: 1}); - rss2.insert({a: 3, b: 4}); - rss2.insert({a: 9, b: 5}); - - results = rss2.chain().simplesort("a", true).data(); - expect(results[0].a).toBe(9); - expect(results[1].a).toBe(7); - expect(results[2].a).toBe(4); - expect(results[3].a).toBe(3); - }); - }); - - describe("ResultSet simplesort on nested properties", () => { - it("works", function () { - interface Sortable { - foo: { - a: number; - b: number; - }; - } - - const rss = db.addCollection("rssort", - { - nestedProperties: ["foo.a"] - }); - - rss.insert({foo: {a: 4, b: 2}}); - rss.insert({foo: {a: 7, b: 1}}); - rss.insert({foo: {a: 3, b: 4}}); - rss.insert({foo: {a: 9, b: 5}}); - - const results = rss.chain().simplesort("foo.a").data(); - expect(results[0].foo.a).toBe(3); - expect(results[1].foo.a).toBe(4); - expect(results[2].foo.a).toBe(7); - expect(results[3].foo.a).toBe(9); - }); - }); - - describe("ResultSet simplesort with dates", () => { - it("works", () => { - const now = new Date().getTime(); - const dt1 = new Date(now - 1000); - const dt2 = new Date(now + 5000); - const dt3 = new Date(2000, 6, 1); - const dt4 = new Date(now + 2000); - const dt5 = new Date(now - 3000); - - interface Sortable { - a: number; - b: Date; - } - - const rss = db.addCollection("rssort"); - - rss.insert({a: 1, b: dt1}); - rss.insert({a: 2, b: dt2}); - rss.insert({a: 3, b: dt3}); - rss.insert({a: 4, b: dt4}); - rss.insert({a: 5, b: dt5}); - - const results = rss.chain().simplesort("b").data(); - expect(results[0].a).toBe(3); - expect(results[1].a).toBe(5); - expect(results[2].a).toBe(1); - expect(results[3].a).toBe(4); - expect(results[4].a).toBe(2); - }); + it("ResultSet simplesort descending", () => { + interface Sortable { + a: number; + b: number; + } + + const rss = db.addCollection("rssort"); + + rss.insert({a: 4, b: 2}); + rss.insert({a: 7, b: 1}); + rss.insert({a: 3, b: 4}); + rss.insert({a: 9, b: 5}); + + let results = rss.chain().simplesort("a", true).data(); + expect(results[0].a).toBe(9); + expect(results[1].a).toBe(7); + expect(results[2].a).toBe(4); + expect(results[3].a).toBe(3); + + // test when indexed + const rss2 = db.addCollection("rssort2", {indices: ["a"]}); + + rss2.insert({a: 4, b: 2}); + rss2.insert({a: 7, b: 1}); + rss2.insert({a: 3, b: 4}); + rss2.insert({a: 9, b: 5}); + + results = rss2.chain().simplesort("a", true).data(); + expect(results[0].a).toBe(9); + expect(results[1].a).toBe(7); + expect(results[2].a).toBe(4); + expect(results[3].a).toBe(3); }); - describe("ResultSet sort works correctly", () => { - it("works", () => { - interface Sortable { + it("ResultSet simplesort on nested properties", () => { + interface Sortable { + foo: { a: number; b: number; - c: string; - } - - const db = new Loki("test.db"); - const coll = db.addCollection("coll"); + }; + } - coll.insert([ - {a: 1, b: 9, c: "first"}, - {a: 5, b: 7, c: "second"}, - {a: 2, b: 9, c: "third"} - ]); + const rss = db.addCollection("rssort", + { + nestedProperties: ["foo.a"] + }); - const sortfun = (obj1: Sortable, obj2: Sortable) => { - if (obj1.a === obj2.a) return 0; - if (obj1.a > obj2.a) return 1; - if (obj1.a < obj2.a) return -1; - }; + rss.insert({foo: {a: 4, b: 2}}); + rss.insert({foo: {a: 7, b: 1}}); + rss.insert({foo: {a: 3, b: 4}}); + rss.insert({foo: {a: 9, b: 5}}); - const result = coll.chain().sort(sortfun).data(); - expect(result.length).toEqual(3); - expect(result[0].a).toEqual(1); - expect(result[1].a).toEqual(2); - expect(result[2].a).toEqual(5); - }); + const results = rss.chain().simplesort("foo.a").data(); + expect(results[0].foo.a).toBe(3); + expect(results[1].foo.a).toBe(4); + expect(results[2].foo.a).toBe(7); + expect(results[3].foo.a).toBe(9); }); - describe("ResultSet compoundsort works correctly", () => { - it("works", () => { - const db = new Loki("test.db"); + it("ResultSet simplesort with dates", () => { + const now = new Date().getTime(); + const dt1 = new Date(now - 1000); + const dt2 = new Date(now + 5000); + const dt3 = new Date(2000, 6, 1); + const dt4 = new Date(now + 2000); + const dt5 = new Date(now - 3000); + + interface Sortable { + a: number; + b: Date; + } + + const rss = db.addCollection("rssort"); + + rss.insert({a: 1, b: dt1}); + rss.insert({a: 2, b: dt2}); + rss.insert({a: 3, b: dt3}); + rss.insert({a: 4, b: dt4}); + rss.insert({a: 5, b: dt5}); + + const results = rss.chain().simplesort("b").data(); + expect(results[0].a).toBe(3); + expect(results[1].a).toBe(5); + expect(results[2].a).toBe(1); + expect(results[3].a).toBe(4); + expect(results[4].a).toBe(2); + }); - interface ABC { - a: number; - b: number; - c: string; - } + it("ResultSet sort works correctly", () => { + interface Sortable { + a: number; + b: number; + c: string; + } + + const db = new Loki("test.db"); + const coll = db.addCollection("coll"); + + coll.insert([ + {a: 1, b: 9, c: "first"}, + {a: 5, b: 7, c: "second"}, + {a: 2, b: 9, c: "third"} + ]); + + const sortfun = (obj1: Sortable, obj2: Sortable) => { + if (obj1.a === obj2.a) return 0; + if (obj1.a > obj2.a) return 1; + if (obj1.a < obj2.a) return -1; + }; + + const result = coll.chain().sort(sortfun).data(); + expect(result.length).toEqual(3); + expect(result[0].a).toEqual(1); + expect(result[1].a).toEqual(2); + expect(result[2].a).toEqual(5); + }); - const coll = db.addCollection("coll"); - - coll.insert([ - {a: 1, b: 9, c: "first"}, - {a: 5, b: 7, c: "second"}, - {a: 2, b: 9, c: "third"} - ]); - - let result = coll.chain().compoundsort(["b", "c"]).data(); - expect(result.length).toEqual(3); - expect(result[0].a).toEqual(5); - expect(result[1].a).toEqual(1); - expect(result[2].a).toEqual(2); - - result = coll.chain().compoundsort(["b", ["c", true]]).data(); - expect(result.length).toEqual(3); - expect(result[0].a).toEqual(5); - expect(result[1].a).toEqual(2); - expect(result[2].a).toEqual(1); - }); + it("ResultSet compoundsort works correctly", () => { + const db = new Loki("test.db"); + + interface ABC { + a: number; + b: number; + c: string; + } + + const coll = db.addCollection("coll"); + + coll.insert([ + {a: 1, b: 9, c: "first"}, + {a: 5, b: 7, c: "second"}, + {a: 2, b: 9, c: "third"} + ]); + + let result = coll.chain().compoundsort(["b", "c"]).data(); + expect(result.length).toEqual(3); + expect(result[0].a).toEqual(5); + expect(result[1].a).toEqual(1); + expect(result[2].a).toEqual(2); + + result = coll.chain().compoundsort(["b", ["c", true]]).data(); + expect(result.length).toEqual(3); + expect(result[0].a).toEqual(5); + expect(result[1].a).toEqual(2); + expect(result[2].a).toEqual(1); }); - describe("ResultSet compoundsort on nested properties works correctly", () => { - it("works", function () { - const db = new Loki("test.db"); + it("ResultSet compoundsort on nested properties works correctly", () => { + const db = new Loki("test.db"); - interface AZYBC { - a: number; - z: { - y: { - b: number; - c: string; - }; + interface AZYBC { + a: number; + z: { + y: { + b: number; + c: string; }; - } + }; + } - const coll = db.addCollection("coll", - { - nestedProperties: ["z.y.b", "z.y.c"] - }); - - coll.insert([ - {a: 1, z: {y: {b: 9, c: "first"}}}, - {a: 5, z: {y: {b: 7, c: "second"}}}, - { - a: 2, z: {y: {b: 9, c: "third"}} - }]); - - let result = coll.chain().compoundsort(["z.y.b", "z.y.c"]).data(); - expect(result.length).toEqual(3); - expect(result[0].a).toEqual(5); - expect(result[1].a).toEqual(1); - expect(result[2].a).toEqual(2); - - result = coll.chain().compoundsort(["z.y.b", ["z.y.c", true]]).data(); - expect(result.length).toEqual(3); - expect(result[0].a).toEqual(5); - expect(result[1].a).toEqual(2); - expect(result[2].a).toEqual(1); - }); + const coll = db.addCollection("coll", + { + nestedProperties: ["z.y.b", "z.y.c"] + }); + + coll.insert([ + {a: 1, z: {y: {b: 9, c: "first"}}}, + {a: 5, z: {y: {b: 7, c: "second"}}}, + { + a: 2, z: {y: {b: 9, c: "third"}} + }]); + + let result = coll.chain().compoundsort(["z.y.b", "z.y.c"]).data(); + expect(result.length).toEqual(3); + expect(result[0].a).toEqual(5); + expect(result[1].a).toEqual(1); + expect(result[2].a).toEqual(2); + + result = coll.chain().compoundsort(["z.y.b", ["z.y.c", true]]).data(); + expect(result.length).toEqual(3); + expect(result[0].a).toEqual(5); + expect(result[1].a).toEqual(2); + expect(result[2].a).toEqual(1); }); describe("collection indexing", () => { @@ -307,7 +294,7 @@ describe("sorting and indexing", () => { expect(indexVals[13] === "asdf").toEqual(true); }); - it("works", () => { + it("date sort as expected", () => { const now = new Date().getTime(); const dt1 = new Date(now - 1000); const dt2 = new Date(now + 5000); @@ -337,12 +324,10 @@ describe("sorting and indexing", () => { // Strict equality checks would need to be extra filtering phase const sdt = new Date(now + 5000); - // after refactoring binary indices to be loose equality/ranges everywhere, // this unit test passed, meaning the dteq op is not needed if binary index exists - - //results = cidx.find({'b': sdt}); - //expect(results.length).toBe(0); + results = cidx.find({"b": sdt}); + expect(results.length).toBe(0); // now try with new $dteq operator results = cidx.find({"b": {"$dteq": sdt}}); @@ -359,4 +344,60 @@ describe("sorting and indexing", () => { }); }); + it("simplesort index intersect works correctly", () => { + const db = new Loki("rss.db"); + const rss = db.addCollection<{ a: number, b: number }>("rssort", {indices: ["a", "b"]}); + + rss.insert({a: 4, b: 1}); + rss.insert({a: 7, b: 1}); + rss.insert({a: 3, b: 1}); + rss.insert({a: 9, b: 5}); + rss.insert({a: 14, b: 1}); + rss.insert({a: 17, b: 1}); + rss.insert({a: 13, b: 1}); + rss.insert({a: 19, b: 5}); + + // test explicit force index intercept simplesort code path + let results = rss.chain().find({b: 1}).simplesort("a", {forceIndexIntersect: true}).data(); + expect(results.length).toBe(6); + for (let i = 0; i < results.length - 1; i++) { + expect(LokiOps.$lte(results[i]["a"], results[i + 1]["a"])); + } + + // test explicit disable index intercept simplesort code path + results = rss.chain().find({b: 1}).simplesort("a", {disableIndexIntersect: true}).data(); + expect(results.length).toBe(6); + for (let i = 0; i < results.length - 1; i++) { + expect(LokiOps.$lte(results[i]["a"], results[i + 1]["a"])); + } + + // test 'smart' simplesort + results = rss.chain().find({b: 1}).simplesort("a").data(); + expect(results.length).toBe(6); + for (let i = 0; i < results.length - 1; i++) { + expect(LokiOps.$lte(results[i]["a"], results[i + 1]["a"])); + } + }); + + it("simplesort using javascript sorting works correctly", () => { + const db = new Loki("rss.db"); + const rss = db.addCollection<{ a: number, b: number }>("rssort", {indices: ["a", "b"]}); + + rss.insert({a: 4, b: 1}); + rss.insert({a: 7, b: 1}); + rss.insert({a: 3, b: 1}); + rss.insert({a: 9, b: 5}); + rss.insert({a: 14, b: 1}); + rss.insert({a: 17, b: 1}); + rss.insert({a: 13, b: 1}); + rss.insert({a: 19, b: 5}); + + // test explicit force index intercept simplesort code path + const results = rss.chain().find({b: 1}).simplesort("a", {useJavascriptSorting: true}).data(); + + expect(results.length).toBe(6); + for (let i = 0; i < results.length - 1; i++) { + expect(LokiOps.$lte(results[i]["a"], results[i + 1]["a"])); + } + }); }); diff --git a/packages/loki/spec/generic/transforms.spec.ts b/packages/loki/spec/generic/transforms.spec.ts index 289d6a18..e7e49491 100644 --- a/packages/loki/spec/generic/transforms.spec.ts +++ b/packages/loki/spec/generic/transforms.spec.ts @@ -270,7 +270,7 @@ describe("transforms", () => { { type: "simplesort", property: "a", - desc: true + options: true }, { type: "limit", diff --git a/packages/loki/src/collection.ts b/packages/loki/src/collection.ts index e863e011..eedc90c0 100644 --- a/packages/loki/src/collection.ts +++ b/packages/loki/src/collection.ts @@ -2170,7 +2170,7 @@ export namespace Collection { } | { type: "simplesort"; property: keyof (TData & TNested); - desc?: boolean; + options?: boolean | ResultSet.SimpleSortOptions; } | { type: "compoundsort"; value: (keyof (TData & TNested) | [keyof (TData & TNested), boolean])[]; diff --git a/packages/loki/src/dynamic_view.ts b/packages/loki/src/dynamic_view.ts index 18985b5b..4d71891a 100644 --- a/packages/loki/src/dynamic_view.ts +++ b/packages/loki/src/dynamic_view.ts @@ -41,6 +41,7 @@ export class DynamicView, rhs: Doc) => number; private _sortCriteria: (keyof (TData & TNested) | [keyof (TData & TNested), boolean])[]; + private _sortCriteriaSimple: { field: keyof (TData & TNested), options: boolean | ResultSet.SimpleSortOptions }; private _sortByScoring: boolean; private _sortDirty: boolean; @@ -83,6 +84,7 @@ export class DynamicView, rhs: Doc) => number): this { this._sortFunction = comparefun; this._sortCriteria = null; + this._sortCriteriaSimple = null; this._sortByScoring = null; this._queueSortPhase(); return this; @@ -244,17 +249,20 @@ export class DynamicView; _filterPipeline: Filter[]; _sortCriteria: (string | [string, boolean])[]; + _sortCriteriaSimple: { field: string, options: boolean | ResultSet.SimpleSortOptions }; _sortByScoring: boolean; _sortDirty: boolean; } diff --git a/packages/loki/src/result_set.ts b/packages/loki/src/result_set.ts index 783a0b5d..3c333292 100644 --- a/packages/loki/src/result_set.ts +++ b/packages/loki/src/result_set.ts @@ -367,7 +367,7 @@ export class ResultSet) => boolean); break; case "simplesort": - rs.simplesort(step.property, step.desc); + rs.simplesort(step.property, step.options); break; case "compoundsort": rs.compoundsort(step.value); @@ -435,16 +435,63 @@ export class ResultSet { + return io[n]; + }); + + if (options.desc) { + this._filteredRows.reverse(); + } + + return this; + } + } + + if (options.useJavascriptSorting) { + return this.sort((obj1, obj2) => { + if (obj1[propname] === obj2[propname]) return 0; + if (obj1[propname] > obj2[propname]) return 1; + if (obj1[propname] < obj2[propname]) return -1; + }); + } + // if this has no filters applied, just we need to populate filteredRows first if (!this._filterInitialized && this._filteredRows.length === 0) { - //TODO: // if we have a binary index and no other filters applied, we can use that instead of sorting (again) if (this._collection.binaryIndices[propname] !== undefined) { // make sure index is up-to-date @@ -452,7 +499,7 @@ export class ResultSet { - return sortHelper(data[a][propname], data[b][propname], descending); + return sortHelper(data[a][propname], data[b][propname], (options as ResultSet.SimpleSortOptions).desc); }; this._filteredRows.sort(wrappedComparer); @@ -495,7 +542,7 @@ export class ResultSet = { $eq?: R; } | {