UNPKG

@minatojs/tests

Version:
1,144 lines (1,138 loc) 197 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // src/shape.ts import { Binary, deepEqual, isNullable } from "cosmokit"; import { inspect } from "util"; function flag(obj, key, value) { var flags = obj.__flags || (obj.__flags = /* @__PURE__ */ Object.create(null)); if (arguments.length === 3) { flags[key] = value; } else { return flags[key]; } } __name(flag, "flag"); function isSubsetOf(subset, superset, cmp, contains, ordered) { if (!contains) { if (subset.length !== superset.length) return false; superset = superset.slice(); } return subset.every(function(elem, idx) { if (ordered) return cmp ? cmp(elem, superset[idx]) : elem === superset[idx]; if (!cmp) { var matchIdx = superset.indexOf(elem); if (matchIdx === -1) return false; if (!contains) superset.splice(matchIdx, 1); return true; } return superset.some(function(elem2, matchIdx2) { if (!cmp(elem, elem2)) return false; if (!contains) superset.splice(matchIdx2, 1); return true; }); }); } __name(isSubsetOf, "isSubsetOf"); var shape_default = /* @__PURE__ */ __name((({ Assertion }) => { function checkShape(expect12, actual, path, ordered) { if (actual === expect12 || Number.isNaN(expect12) && Number.isNaN(actual)) return; function formatError(expect13, actual2) { return `expected to have ${expect13} but got ${actual2} at path ${path}`; } __name(formatError, "formatError"); if (isNullable(expect12) && isNullable(actual)) return; if (!expect12 || ["string", "number", "boolean", "bigint"].includes(typeof expect12)) { return formatError(inspect(expect12), inspect(actual)); } if (expect12 instanceof Date) { if (!(actual instanceof Date) || +expect12 !== +actual) { return formatError(inspect(expect12), inspect(actual)); } return; } if (Binary.is(expect12)) { if (!Binary.is(actual) || !deepEqual(actual, expect12)) { return formatError(inspect(expect12), inspect(actual)); } return; } if (actual === null) { const type2 = Object.prototype.toString.call(expect12).slice(8, -1).toLowerCase(); return formatError(`a ${type2}`, "null"); } if (!ordered && Array.isArray(expect12) && Array.isArray(actual)) { if (!isSubsetOf(expect12, actual, (x, y) => !checkShape(x, y, `${path}/`, ordered), false, false)) { return `expected same shape of members`; } return; } for (const prop in expect12) { if (isNullable(actual[prop]) && !isNullable(expect12[prop])) { return `expected "${prop}" field to be defined at path ${path}`; } const message = checkShape(expect12[prop], actual[prop], `${path}${prop}/`, ordered); if (message) return message; } } __name(checkShape, "checkShape"); Assertion.addMethod("shape", function(expect12) { var ordered = flag(this, "ordered"); const message = checkShape(expect12, this._obj, "/", ordered); if (message) this.assert(false, message, "", expect12, this._obj); }); }), "default"); // src/index.ts import { Database as Database10 } from "minato"; // src/model.ts import { mapValues, isNullable as isNullable2, deduplicate, omit } from "cosmokit"; import { $, getCell, Type, unravel } from "minato"; import { expect } from "chai"; function toBinary(source) { return new TextEncoder().encode(source).buffer; } __name(toBinary, "toBinary"); function fromBinary(source) { return new TextDecoder().decode(source); } __name(fromBinary, "fromBinary"); function flatten(type2, prefix) { if (typeof type2 === "object" && type2?.type === "object") { const result = {}; for (const key in type2.inner) { Object.assign(result, flatten(type2.inner[key], `${prefix}.${key}`)); } return result; } else { return { [prefix]: type2 }; } } __name(flatten, "flatten"); function ModelOperations(database) { before(() => { database.define("bigint2", { type: "string", dump: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : value.toString(), "dump"), load: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : BigInt(value), "load"), initial: 123n }); database.define("custom", { type: "string", dump: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : `${value.a}|${value.b}`, "dump"), load: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : { a: value.split("|")[0], b: +value.split("|")[1] }, "load") }); const bnum = database.define({ type: "binary", dump: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : toBinary(String(value)), "dump"), load: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : +fromBinary(value), "load"), initial: 0 }); const bstr = database.define({ type: "custom", dump: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : { a: value, b: 1 }, "dump"), load: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : value.a, "load"), initial: "pooo" }); database.define("string2", { type: "string", dump: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : `AAA${value}`, "dump"), load: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : value.slice(3), "load"), initial: "" }); database.define("recurx", { type: "object", inner: { id: "unsigned", y: "recury" } }); database.define("recury", { type: "object", inner: { id: "unsigned", x: "recurx" } }); const baseFields = { id: "unsigned", text: { type: "string", initial: "he`l\"'\\lo" }, num: { type: "integer", initial: 233 }, double: { type: "double", initial: 3.14 }, decimal: { type: "decimal", scale: 3, initial: 12413 }, int64: { type: "bigint", initial: 1n }, bool: { type: "boolean", initial: true }, list: { type: "list", initial: ["a`a", 'b"b', "c'c", "d\\d"] }, array: "array", object: { type: "object", inner: { num: "unsigned", text: "string", json: "object", embed: { type: "object", inner: { bool: { type: "boolean", initial: false }, int64: "bigint", bigint: "bigint2", custom: { type: "custom" }, bstr } } } }, // dot defined object "object2.num": { type: "unsigned", initial: 1 }, "object2.text": { type: "string", initial: "2" }, "object2.embed.bool": { type: "boolean", initial: true }, "object2.embed.bigint": "bigint2", timestamp: { type: "timestamp", initial: /* @__PURE__ */ new Date("1970-01-01 00:00:00") }, date: { type: "date", initial: /* @__PURE__ */ new Date("1970-01-01") }, time: { type: "time", initial: /* @__PURE__ */ new Date("1970-01-01 12:00:00") }, binary: { type: "binary", initial: toBinary("initial buffer") }, bigint: "bigint2", bnum, bnum2: { type: "binary", dump: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : toBinary(String(value)), "dump"), load: /* @__PURE__ */ __name((value) => isNullable2(value) ? value : +Buffer.from(value), "load"), initial: 0 }, text2: "string2" }; const baseObject = { type: "object", inner: { nested: { type: "object", inner: baseFields } }, initial: { nested: { id: 1 } } }; database.extend("dtypes", { ...baseFields }, { autoInc: true }); database.extend("dobjects", { id: "unsigned", foo: baseObject, ...flatten(baseObject, "bar"), baz: { type: "array", inner: baseObject, initial: [] } }, { autoInc: true }); database.extend("recurxs", { id: "unsigned", y: "recury" }, { autoInc: true }); }); } __name(ModelOperations, "ModelOperations"); ((ModelOperations2) => { const magicBorn = /* @__PURE__ */ new Date("1970/08/17"); const dtypeTable = [ { id: 1, bool: false }, { id: 2, text: "pku" }, { id: 3, num: 1989 }, { id: 4, list: ["1", "1", "4"], array: [1, 1, 4] }, { id: 5, object: { num: 10, text: "ab", embed: { bool: true, bigint: 90n, int64: 100n, bstr: "world" } } }, { id: 6, object2: { num: 10, text: "ab", embed: { bool: false, bigint: 90n } } }, { id: 7, timestamp: magicBorn }, { id: 8, date: magicBorn }, { id: 9, time: /* @__PURE__ */ new Date("1999-10-01 15:40:00") }, { id: 10, binary: toBinary("hello") }, { id: 11, bigint: BigInt(1e63) }, { id: 12, decimal: 2.432, int64: 9223372036854775806n }, { id: 13, bnum: 114514, bnum2: 12345 }, { id: 14, object: { embed: { custom: { a: "abc", b: 123 } } } } ]; const dobjectTable = [ { id: 1 }, { id: 2, foo: { nested: { id: 1, int64: 123n, list: ["1", "1", "4"], array: [1, 1, 4], object: { num: 10, text: "ab", embed: { bool: false, bigint: BigInt(1e163), custom: { a: "?", b: 8 }, bstr: "wo" } }, bigint: BigInt(1e63), bnum: 114514, bnum2: 12345 } } }, { id: 3, bar: { nested: { id: 1, list: ["1", "1", "4"], array: [1, 1, 4], object: { num: 10, text: "ab", embed: { bool: false, bigint: BigInt(1e163), custom: { a: "?", b: 8 }, bstr: "wo" } }, bigint: BigInt(1e63), bnum: 114514, bnum2: 12345 } } }, { id: 4, baz: [{ nested: { id: 1, list: ["1", "1", "4"], array: [1, 1, 4], object: { num: 10, text: "ab", embed: { bool: false, bigint: BigInt(1e163), custom: { a: "?", b: 8 }, bstr: "wo" } }, bigint: BigInt(1e63), bnum: 114514, bnum2: 12345 } }, { nested: { id: 2 } }] }, { id: 5, foo: { nested: { id: 1, list: ["1", "1", "4"], array: [1, 1, 4], object2: { num: 10, text: "ab", embed: { bool: false, bigint: BigInt(1e163) } }, bigint: BigInt(1e63), bnum: 114514, bnum2: 12345 } } }, { id: 6, bar: { nested: { id: 1, list: ["1", "1", "4"], array: [1, 1, 4], object2: { num: 10, text: "ab", embed: { bool: false, bigint: BigInt(1e163) } }, bigint: BigInt(1e63), bnum: 114514, bnum2: 12345 } } }, { id: 7, baz: [{ nested: { id: 1, list: ["1", "1", "4"], array: [1, 1, 4], object2: { num: 10, text: "ab", embed: { bool: false, bigint: BigInt(1e163) } }, bigint: BigInt(1e63), bnum: 114514, bnum2: 12345 } }, { nested: { id: 2 } }] } ]; async function setup2(database, name, table) { await database.remove(name, {}); const result = []; for (const item of table) { result.push(await database.create(name, item)); } return result; } __name(setup2, "setup"); ModelOperations2.fields = /* @__PURE__ */ __name(function Fields(database, options = {}) { const { cast = true, typeModel = true } = options; it("basic", async () => { const table = await setup2(database, "dtypes", dtypeTable); table.forEach((row, i) => expect(row).to.have.shape(omit(dtypeTable[i], ["date", "time"]))); await expect(database.get("dtypes", {})).to.eventually.have.deep.members(table); await database.remove("dtypes", {}); await database.upsert("dtypes", dtypeTable); await expect(database.get("dtypes", {})).to.eventually.have.deep.members(table); }); typeModel && it("pass view to binary", async () => { const table = await setup2(database, "dtypes", dtypeTable); table[0].binary = toBinary("this is Buffer"); await database.set("dtypes", table[0].id, { binary: Buffer.from("this is Buffer") }); await expect(database.get("dtypes", {})).to.eventually.have.deep.members(table); }); it("modifier", async () => { const table = await setup2(database, "dtypes", dtypeTable); await database.remove("dtypes", {}); await database.upsert("dtypes", dtypeTable.map(({ id }) => ({ id }))); await Promise.all(table.map(({ id, ...x }) => database.set("dtypes", id, x))); await expect(database.get("dtypes", {})).to.eventually.have.deep.members(table); }); it("dot notation in modifier", async () => { const table = await setup2(database, "dtypes", dtypeTable); table[0].object = {}; await database.set("dtypes", table[0].id, (row) => ({ object: {} })); await expect(database.get("dtypes", table[0].id)).to.eventually.deep.eq([table[0]]); table[0].object = { num: 123, json: { num: 456 }, embed: { bool: true, bigint: 123n, custom: { a: "a", b: 1 } } }; await database.set("dtypes", table[0].id, (row) => ({ "object.num": 123, "object.json.num": 456, "object.embed.bool": true, "object.embed.bigint": 123n, "object.embed.custom": { a: "a", b: 1 } })); await expect(database.get("dtypes", table[0].id)).to.eventually.deep.eq([table[0]]); }); it("using expressions in modifier", async () => { const table = await setup2(database, "dtypes", dtypeTable); table[0].object.json.num = 543 + (table[0].object.json.num ?? 0); table[0].object.embed.bool = !table[0].object.embed.bool; table[0].object.embed.bigint = 999n; await database.set("dtypes", table[0].id, (row) => ({ "object.json.num": $.add($.ifNull(row.object.json.num, 0), 543), "object.embed.bool": $.not(row.object.embed.bool), "object.embed.bigint": 999n })); await expect(database.get("dtypes", {})).to.eventually.have.deep.members(table); table[0].object.embed.bool = false; await database.set("dtypes", table[0].id, { "object.embed.bool": false }); await expect(database.get("dtypes", {})).to.eventually.have.deep.members(table); table[0].object.embed.bool = true; await database.set("dtypes", table[0].id, { "object.embed.bool": true }); await expect(database.get("dtypes", {})).to.eventually.have.deep.members(table); }); it("primitive", async () => { expect(Type.fromTerm($.literal(123)).type).to.equal(Type.Number.type); expect(Type.fromTerm($.literal("abc")).type).to.equal(Type.String.type); expect(Type.fromTerm($.literal(true)).type).to.equal(Type.Boolean.type); expect(Type.fromTerm($.literal(/* @__PURE__ */ new Date("1970-01-01"))).type).to.equal("timestamp"); expect(Type.fromTerm($.literal(toBinary("hello"))).type).to.equal("binary"); expect(Type.fromTerm($.literal([1, 2, 3])).type).to.equal("json"); expect(Type.fromTerm($.literal({ a: 1 })).type).to.equal("json"); }); cast && it("cast newtype", async () => { await setup2(database, "dtypes", dtypeTable); await expect(database.get("dtypes", (row) => $.eq(row.bigint, $.literal(234n, "bigint2")))).to.eventually.have.length(0); await expect(database.get("dtypes", (row) => $.eq(row.bigint, $.literal(BigInt(1e63), "bigint2")))).to.eventually.have.length(1); }); typeModel && it("$.object encoding", async () => { const table = await setup2(database, "dtypes", dtypeTable); await expect(database.eval("dtypes", (row) => $.array($.object(row)))).to.eventually.have.deep.members(table); }); typeModel && it("$.object decoding", async () => { const table = await setup2(database, "dtypes", dtypeTable); await expect( database.select("dtypes").project({ obj: /* @__PURE__ */ __name((row) => $.object(row), "obj") }).project(mapValues(database.tables["dtypes"].fields, (field, key) => (row) => row.obj[key])).execute() ).to.eventually.have.deep.members(table); }); typeModel && it("$.array encoding on cell", async () => { const table = await setup2(database, "dtypes", dtypeTable); await expect(database.eval("dtypes", (row) => $.array(row.object))).to.eventually.have.deep.members(table.map((x) => x.object)); await expect(database.eval("dtypes", (row) => $.array(row.object2))).to.eventually.have.deep.members(table.map((x) => x.object2)); }); it("$.array encoding", async () => { const table = await setup2(database, "dtypes", dtypeTable); await Promise.all(Object.keys(database.tables["dtypes"].fields).map( (key) => expect(database.eval("dtypes", (row) => $.array(row[key]))).to.eventually.have.deep.members(table.map((x) => getCell(x, key))) )); }); it("subquery encoding", async () => { const table = await setup2(database, "dtypes", dtypeTable); await Promise.all(Object.keys(database.tables["dtypes"].fields).map( (key) => expect( database.select("dtypes", 1).project({ x: /* @__PURE__ */ __name((row) => database.select("dtypes").evaluate(key), "x") }).execute() ).to.eventually.have.shape([{ x: table.map((x) => getCell(x, key)) }]) )); }); it("object query", async () => { const table = await setup2(database, "dtypes", dtypeTable); await expect(database.get("dtypes", { "object.embed.bool": true })).to.eventually.have.shape([table[4]]); await expect(database.get("dtypes", { "object.num": { $gte: 10 } })).to.eventually.have.shape([table[4]]); table[4].object.embed.bool = false; await expect(database.set("dtypes", { object: { embed: { int64: 100n } } }, { "object.embed.bool": false })).to.eventually.fulfilled; await expect(database.get("dtypes", { object: { embed: { int64: 100n } } })).to.eventually.deep.equal([table[4]]); await expect(database.get("dtypes", { $or: [ { object: { num: 10 } }, { object2: { num: { $gte: 10 } } } ] })).to.eventually.have.deep.members([table[4], table[5]]); }); it("recursive type", async () => { const table = await setup2(database, "recurxs", [{ id: 1, y: { id: 2, x: { id: 3, y: { id: 4, x: { id: 5 } } } } }]); await expect(database.get("recurxs", {})).to.eventually.have.deep.members(table); }); it("customized string type", async () => { await setup2(database, "dtypes", dtypeTable); await database.set("dtypes", 1, { text2: "foo" }); await expect(database.eval("dtypes", (row) => $.array(row.text2))).to.eventually.contain("foo"); await expect(database.get("dtypes", (row) => $.eq(row.text2, $.literal("foo", "string2")))).to.eventually.have.length(1); }); }, "Fields"); ModelOperations2.object = /* @__PURE__ */ __name(function ObjectFields(database, options = {}) { const { aggregateNull = true, nullableComparator = true, typeModel = true } = options; it("basic", async () => { const table = await setup2(database, "dobjects", dobjectTable); await expect(database.get("dobjects", {})).to.eventually.have.deep.members(table); await database.remove("dobjects", {}); await database.upsert("dobjects", dobjectTable); await expect(database.get("dobjects", {})).to.eventually.have.deep.members(table); }); it("modifier", async () => { const table = await setup2(database, "dobjects", dobjectTable); await database.remove("dobjects", {}); await database.upsert("dobjects", dobjectTable.map(({ id }) => ({ id }))); await Promise.all(table.map(({ id, ...x }) => database.set("dobjects", id, x))); await expect(database.get("dobjects", {})).to.eventually.have.deep.members(table); }); it("dot notation in modifier", async () => { const table = await setup2(database, "dobjects", dobjectTable); table[0].foo.nested = { id: 1 }; await database.set("dobjects", table[0].id, (row) => ({ "foo.nested": { id: 1 } })); await expect(database.get("dobjects", table[0].id)).to.eventually.deep.eq([table[0]]); table[0].foo.nested = { id: 1, timestamp: /* @__PURE__ */ new Date("2009/10/01 15:40:00"), date: /* @__PURE__ */ new Date("1999/10/01"), binary: toBinary("boom") }; table[0].bar.nested = { ...table[0].bar?.nested, id: 9, timestamp: /* @__PURE__ */ new Date("2009/10/01 15:40:00"), date: /* @__PURE__ */ new Date("1999/10/01"), binary: toBinary("boom") }; await database.set("dobjects", table[0].id, { "foo.nested.timestamp": /* @__PURE__ */ new Date("2009/10/01 15:40:00"), "foo.nested.date": /* @__PURE__ */ new Date("1999/10/01"), "foo.nested.binary": toBinary("boom"), "bar.nested.id": 9, "bar.nested.timestamp": /* @__PURE__ */ new Date("2009/10/01 15:40:00"), "bar.nested.date": /* @__PURE__ */ new Date("1999/10/01"), "bar.nested.binary": toBinary("boom") }); await expect(database.get("dobjects", table[0].id)).to.eventually.deep.eq([table[0]]); table[0].baz = [{}, {}]; await database.set("dobjects", table[0].id, { baz: [{}, {}] }); await expect(database.get("dobjects", table[0].id)).to.eventually.deep.eq([table[0]]); }); typeModel && it("$.object encoding", async () => { const table = await setup2(database, "dobjects", dobjectTable); await expect(database.eval("dobjects", (row) => $.array($.object(row)))).to.eventually.have.deep.members(table); }); typeModel && it("$.object decoding", async () => { const table = await setup2(database, "dobjects", dobjectTable); await expect( database.select("dobjects").project({ obj: /* @__PURE__ */ __name((row) => $.object(row), "obj") }).project(mapValues(database.tables["dobjects"].fields, (field, key) => (row) => row.obj[key])).execute() ).to.eventually.have.deep.members(table); }); aggregateNull && it("$.array encoding", async () => { const table = await setup2(database, "dobjects", dobjectTable); await Promise.all(Object.keys(database.tables["dobjects"].fields).map( (key) => expect(database.eval("dobjects", (row) => $.array(row[key]))).to.eventually.have.deep.members(table.map((x) => getCell(x, key))) )); }); it("$.array encoding boxed", async () => { const table = await setup2(database, "dobjects", dobjectTable); await Promise.all(Object.keys(database.tables["dobjects"].fields).map( (key) => expect(database.eval("dobjects", (row) => $.array($.object({ x: row[key] })))).to.eventually.have.deep.members(table.map((x) => ({ x: getCell(x, key) }))) )); }); it("subquery encoding", async () => { const table = await setup2(database, "dobjects", dobjectTable); await Promise.all(["baz"].map( (key) => expect( database.select("dobjects", 1).project({ x: /* @__PURE__ */ __name((row) => database.select("dobjects").evaluate(key), "x") }).execute() ).to.eventually.have.shape([{ x: table.map((x) => getCell(x, key)) }]) )); }); it("project with dot notation", async () => { const table = await setup2(database, "dobjects", dobjectTable); const keys = deduplicate([ "foo.nested.object", "foo.nested.object.embed", ...Object.keys(database.tables["dobjects"].fields).flatMap((k) => k.split(".").reduce((arr, c) => arr.length ? [`${arr[0]}.${c}`, ...arr] : [c], [])) ]); await Promise.all(keys.map( (key) => expect(database.select("dobjects").project([key]).execute()).to.eventually.have.deep.members(table.map((row) => unravel({ [key]: getCell(row, key) }))) )); }); it("bitwise ops on bigint", async () => { await setup2(database, "dobjects", dobjectTable); await expect(database.get("dobjects", (row) => $.eq($.and(row.foo.nested.int64, 5n), 1n))).to.eventually.have.length(1); await expect(database.get("dobjects", (row) => $.eq($.or(row.foo.nested.int64, 4n), 127n))).to.eventually.have.length(1); await expect(database.get("dobjects", (row) => $.eq($.xor(row.foo.nested.int64, 2n), 121n))).to.eventually.have.length(1); await expect(database.eval("dobjects", (row) => $.max($.or(row.foo.nested.int64, 9223372036854775701n)))).eventually.to.deep.equal(9223372036854775807n); }); nullableComparator && it("nested $get", async () => { await setup2(database, "dobjects", dobjectTable); await expect(database.get("dobjects", (row) => $.eq(row.baz[0].nested.id, 1))).to.eventually.have.length(2); await expect(database.get("dobjects", (row) => $.eq(row.baz[0].nested.array[0], 1))).to.eventually.have.length(2); }); }, "ObjectFields"); })(ModelOperations || (ModelOperations = {})); var model_default = ModelOperations; // src/query.ts import { $ as $2 } from "minato"; import { expect as expect2 } from "chai"; function QueryOperators(database) { before(() => { database.extend("temp1", { id: "unsigned", text: "string", value: "integer", bool: "boolean", list: "list", timestamp: "timestamp", date: "date", time: "time", regex: "string" }, { autoInc: true }); }); } __name(QueryOperators, "QueryOperators"); ((QueryOperators2) => { QueryOperators2.comparison = /* @__PURE__ */ __name(function Comparison(database, options = {}) { const { nullableComparator = true } = options; before(async () => { await database.remove("temp1", {}); await database.create("temp1", { text: "awesome foo", timestamp: /* @__PURE__ */ new Date("2000-01-01"), date: /* @__PURE__ */ new Date("2020-01-01"), time: /* @__PURE__ */ new Date("2020-01-01 12:00:00") }); await database.create("temp1", { text: "awesome bar" }); await database.create("temp1", { text: "awesome baz" }); }); it("basic support", async () => { await expect2(database.get("temp1", { id: { $eq: 2 } })).eventually.to.have.length(1).with.nested.property("0.text").equal("awesome bar"); await expect2(database.get("temp1", { id: { $ne: 3 } })).eventually.to.have.length(2).with.nested.property("0.text").equal("awesome foo"); await expect2(database.get("temp1", { id: { $gt: 1 } })).eventually.to.have.length(2).with.nested.property("1.text").equal("awesome baz"); await expect2(database.get("temp1", { id: { $gte: 3 } })).eventually.to.have.length(1).with.nested.property("0.text").equal("awesome baz"); await expect2(database.get("temp1", { id: { $lt: 1 } })).eventually.to.have.length(0); await expect2(database.get("temp1", { id: { $lte: 2 } })).eventually.to.have.length(2).with.nested.property("0.text").equal("awesome foo"); }); it("timestamp comparisons", async () => { await expect2(database.get("temp1", { timestamp: { $gt: /* @__PURE__ */ new Date("1999-01-01") } })).eventually.to.have.length(1).with.nested.property("0.text").equal("awesome foo"); await expect2(database.get("temp1", { timestamp: { $lte: /* @__PURE__ */ new Date("1999-01-01") } })).eventually.to.have.length(0); nullableComparator && await expect2(database.get( "temp1", (row) => $2.gt(row.timestamp, /* @__PURE__ */ new Date("1999-01-01")) )).eventually.to.have.length(1).with.nested.property("0.text").equal("awesome foo"); }); it("date comparisons", async () => { await expect2(database.get("temp1", { date: { $gt: /* @__PURE__ */ new Date("1999-01-01") } })).eventually.to.have.length(1).with.nested.property("0.text").equal("awesome foo"); await expect2(database.get("temp1", { date: { $lte: /* @__PURE__ */ new Date("1999-01-01") } })).eventually.to.have.length(0); }); it("time comparisons", async () => { await expect2(database.get("temp1", { // date should not matter time: { $gt: /* @__PURE__ */ new Date("1970-01-01 11:00:00") } })).eventually.to.have.length(1).with.nested.property("0.text").equal("awesome foo"); await expect2(database.get("temp1", { time: { $lte: /* @__PURE__ */ new Date("1970-01-01 11:00:00") } })).eventually.to.have.length(0); }); it("shorthand syntax", async () => { await expect2(database.get("temp1", { id: 2 })).eventually.to.have.length(1).with.nested.property("0.text").equal("awesome bar"); await expect2(database.get("temp1", { timestamp: /* @__PURE__ */ new Date("2000-01-01") })).eventually.to.have.length(1).with.nested.property("0.text").equal("awesome foo"); }); }, "Comparison"); QueryOperators2.existence = /* @__PURE__ */ __name(function Existence(database) { before(async () => { await database.remove("temp1", {}); await database.create("temp1", { date: /* @__PURE__ */ new Date("2010-01-01") }); await database.create("temp1", { date: /* @__PURE__ */ new Date("2020-01-01") }); await database.create("temp1", {}); }); it("basic support", async () => { await expect2(database.get("temp1", { date: { $exists: true } })).eventually.to.have.length(2); await expect2(database.get("temp1", { date: { $exists: false } })).eventually.to.have.length(1); }); it("shorthand syntax", async () => { await expect2(database.get("temp1", { date: null })).eventually.to.have.length(1); }); }, "Existence"); QueryOperators2.membership = /* @__PURE__ */ __name(function Membership(database) { before(async () => { await database.remove("temp1", {}); await database.create("temp1", { value: 3 }); await database.create("temp1", { value: 4 }); await database.create("temp1", { value: 7 }); }); it("edge cases", async () => { await expect2(database.get("temp1", { value: { $in: [] } })).eventually.to.have.length(0); await expect2(database.get("temp1", { value: { $nin: [] } })).eventually.to.have.length(3); }); it("basic support", async () => { await expect2(database.get("temp1", { value: { $in: [3, 4, 5] } })).eventually.to.have.length(2); await expect2(database.get("temp1", (row) => { return $2.in(row.value, [3, 4, 5]); })).eventually.to.have.length(2); await expect2(database.get("temp1", { value: { $nin: [4, 5, 6] } })).eventually.to.have.length(2); }); it("shorthand syntax", async () => { await expect2(database.get("temp1", { value: [] })).eventually.to.have.length(0); await expect2(database.get("temp1", { value: [3, 4, 5] })).eventually.to.have.length(2); }); }, "Membership"); QueryOperators2.regexp = /* @__PURE__ */ __name(function RegularExpression(database, options = {}) { const { regexBy = true, regexFor = true } = options; before(async () => { await database.remove("temp1", {}); await database.create("temp1", { text: "awesome foo", regex: "foo" }); await database.create("temp1", { text: "awesome bar", regex: "bar" }); await database.create("temp1", { text: "awesome foo bar", regex: "baz" }); await database.create("temp1", { text: "xxx", regex: "bAz" }); }); regexFor && it("$regexFor", async () => { await expect2(database.get("temp1", { regex: { $regexFor: "foo bar" } })).eventually.to.have.length(2); await expect2(database.get("temp1", { regex: { $regexFor: "baz" } })).eventually.to.have.length(1); await expect2(database.get("temp1", { regex: { $regexFor: "bAr" } })).eventually.to.have.length(0); await expect2(database.get("temp1", { regex: { $regexFor: { input: "foo bar" } } })).eventually.to.have.length(2); await expect2(database.get("temp1", { regex: { $regexFor: { input: "bAr", flags: "i" } } })).eventually.to.have.length(1); }); regexBy && it("$regexBy", async () => { await expect2(database.get("temp1", { text: { $regex: /^.*foo.*$/ } })).eventually.to.have.length(2); await expect2(database.get("temp1", { text: { $regex: /^.*bar$/ } })).eventually.to.have.length(2); await expect2(database.get("temp1", { text: { $regex: /^.*bAr$/ } })).eventually.to.have.length(0); await expect2(database.get("temp1", { text: { $regex: /^.*bAr$/i } })).eventually.to.have.length(2); await expect2(database.get("temp1", { text: { $regex: { source: "^.*foo.*$" } } })).eventually.to.have.length(2); }); regexBy && it("shorthand syntax", async () => { await expect2(database.get("temp1", { text: /^.*foo$/ })).eventually.to.have.length(1).with.nested.property("[0].text").equal("awesome foo"); }); regexBy && regexFor && it("$.regex", async () => { await expect2(database.get("temp1", (row) => $2.regex("foo bar", row.regex))).eventually.to.have.length(2); await expect2(database.get("temp1", (row) => $2.regex("baz", row.regex))).eventually.to.have.length(1); await expect2(database.get("temp1", (row) => $2.regex(row.text, /^.*foo.*$/))).eventually.to.have.length(2); await expect2(database.get("temp1", (row) => $2.regex(row.text, /^.*bar.*$/))).eventually.to.have.length(2); await expect2(database.get("temp1", (row) => $2.regex(row.text, row.regex))).eventually.to.have.length(2); await expect2(database.get("temp1", (row) => $2.regex(row.text, /^.*bAr.*$/i))).eventually.to.have.length(2); await expect2(database.get("temp1", (row) => $2.regex(row.text, /^.*bAr.*$/))).eventually.to.have.length(0); await expect2(database.get("temp1", (row) => $2.regex(row.text, "^.*bAr.*$", "i"))).eventually.to.have.length(2); }); }, "RegularExpression"); QueryOperators2.bitwise = /* @__PURE__ */ __name(function Bitwise(database) { before(async () => { await database.remove("temp1", {}); await database.create("temp1", { value: 3 }); await database.create("temp1", { value: 4 }); await database.create("temp1", { value: 7 }); }); it("basic support", async () => { await expect2(database.get("temp1", { value: { $bitsAllSet: 3 } })).eventually.to.have.shape([{ value: 3 }, { value: 7 }]); await expect2(database.get("temp1", { value: { $bitsAllClear: 9 } })).eventually.to.have.shape([{ value: 4 }]); await expect2(database.get("temp1", { value: { $bitsAnySet: 4 } })).eventually.to.have.shape([{ value: 4 }, { value: 7 }]); await expect2(database.get("temp1", { value: { $bitsAnyClear: 6 } })).eventually.to.have.shape([{ value: 3 }, { value: 4 }]); }); it("using expressions", async () => { await expect2(database.get( "temp1", (row) => $2.eq($2.and(row.value, 1, 1), 1) )).eventually.to.have.shape([{ value: 3 }, { value: 7 }]); await expect2(database.get( "temp1", (row) => $2.eq($2.or(row.value, 3, 3), 7) )).eventually.to.have.shape([{ value: 4 }, { value: 7 }]); await expect2(database.get( "temp1", (row) => $2.eq($2.and(row.value, $2.not(4)), 3) )).eventually.to.have.shape([{ value: 3 }, { value: 7 }]); await expect2(database.get( "temp1", (row) => $2.eq($2.xor(0, row.value, 3), 7) )).eventually.to.have.shape([{ value: 4 }]); await expect2(database.eval("temp1", (_) => $2.max($2.not(2 ** 30)))).eventually.to.deep.equal(-(2 ** 30) - 1); await expect2(database.eval("temp1", (_) => $2.max($2.not(-(2 ** 30))))).eventually.to.deep.equal(2 ** 30 - 1); await expect2(database.eval("temp1", (_) => $2.max($2.or(-(2 ** 30), 1)))).eventually.to.deep.equal(-(2 ** 30) + 1); await expect2(database.eval("temp1", (_) => $2.max($2.xor(2, 3, 6)))).eventually.to.deep.equal(7); await expect2(database.eval("temp1", (_) => $2.array($2.xor(true, false)))).eventually.to.include.members([true]); await expect2(database.eval("temp1", (_) => $2.array($2.xor(true, false, true)))).eventually.to.include.members([false]); await expect2(database.eval("temp1", (_) => $2.max($2.not(BigInt(2 ** 40))))).eventually.to.deep.equal(BigInt(-(2 ** 40) - 1)); await expect2(database.eval("temp1", (_) => $2.max($2.and(9223372036854775701n, 9223372036854775702n)))).eventually.to.deep.equal(9223372036854775700n); await expect2(database.eval("temp1", (_) => $2.max($2.or(9223372036854775701n, 1n)))).eventually.to.deep.equal(9223372036854775701n); await expect2(database.eval("temp1", (_) => $2.max($2.xor(9223372036854775701n, 9223372036854775702n)))).eventually.to.deep.equal(3n); await expect2(database.eval("temp1", (_) => $2.max($2.not(9223372036854775701n)))).eventually.to.deep.equal(-9223372036854775702n); }); }, "Bitwise"); QueryOperators2.list = /* @__PURE__ */ __name(function List(database, options = {}) { const { size = true, element = true, elementQuery = element } = options; before(async () => { await database.remove("temp1", {}); await database.create("temp1", { id: 1, list: [] }); await database.create("temp1", { id: 2, list: [23] }); await database.create("temp1", { id: 3, list: [233] }); await database.create("temp1", { id: 4, list: [233, 332] }); }); size && it("$size", async () => { await expect2(database.get("temp1", { list: { $size: 1 } })).eventually.to.have.length(2).with.shape([{ id: 2 }, { id: 3 }]); await expect2(database.get("temp1", { list: { $size: 0 } })).eventually.to.have.length(1).with.shape([{ id: 1 }]); }); size && it("$.length", async () => { await expect2( database.select("temp1").project({ x: /* @__PURE__ */ __name((row) => $2.length(row.list), "x") }).orderBy((row) => row.x).execute() ).eventually.to.deep.equal([ { x: 0 }, { x: 1 }, { x: 1 }, { x: 2 } ]); }); element && it("$el shorthand", async () => { await expect2(database.get("temp1", { list: { $el: 233 } })).eventually.to.have.length(2).with.shape([{ id: 3 }, { id: 4 }]); }); elementQuery && it("$el with field temp1", async () => { await expect2(database.get("temp1", { list: { $el: { $lt: 50 } } })).eventually.to.have.shape([{ id: 2 }]); }); }, "List"); QueryOperators2.evaluation = /* @__PURE__ */ __name(function Evaluation(database) { before(async () => { await database.remove("temp1", {}); await database.create("temp1", { id: 1, value: 8 }); await database.create("temp1", { id: 2, value: 7 }); await database.create("temp1", { id: 3, value: 9 }); }); it("arithmetic operators", async () => { await expect2(database.get("temp1", (row) => { return $2.eq(9, $2.add(row.id, row.value)); })).eventually.to.have.length(2).with.shape([{ id: 1 }, { id: 2 }]); }); }, "Evaluation"); let Logical; ((Logical2) => { Logical2.queryLevel = /* @__PURE__ */ __name(function LogicalQueryLevel(database) { before(async () => { await database.remove("temp1", {}); await database.create("temp1", { id: 1 }); await database.create("temp1", { id: 2 }); await database.create("temp1", { id: 3 }); }); it("edge cases", async () => { await expect2(database.get("temp1", {})).eventually.to.have.length(3); await expect2(database.get("temp1", { $and: [] })).eventually.to.have.length(3); await expect2(database.get("temp1", { $or: [] })).eventually.to.have.length(0); await expect2(database.get("temp1", { $not: {} })).eventually.to.have.length(0); await expect2(database.get("temp1", { $not: { $and: [] } })).eventually.to.have.length(0); await expect2(database.get("temp1", { $not: { $or: [] } })).eventually.to.have.length(3); }); it("$or", async () => { await expect2(database.get("temp1", { $or: [{ id: 1 }, { id: { $ne: 2 } }] })).eventually.to.have.length(2).with.shape([{ id: 1 }, { id: 3 }]); await expect2(database.get("temp1", { $or: [{ id: 1 }, { id: { $eq: 2 } }] })).eventually.to.have.length(2).with.shape([{ id: 1 }, { id: 2 }]); await expect2(database.get("temp1", { $or: [{ id: { $ne: 1 } }, { id: { $ne: 2 } }] })).eventually.to.have.length(3).with.shape([{ id: 1 }, { id: 2 }, { id: 3 }]); }); it("$and", async () => { await expect2(database.get("temp1", { $and: [{ id: 1 }, { id: { $ne: 2 } }] })).eventually.to.have.length(1).with.shape([{ id: 1 }]); await expect2(database.get("temp1", { $and: [{ id: 1 }, { id: { $eq: 2 } }] })).eventually.to.have.length(0); await expect2(database.get("temp1", { $and: [{ id: { $ne: 1 } }, { id: { $ne: 2 } }] })).eventually.to.have.length(1).with.shape([{ id: 3 }]); }); it("$not", async () => { await expect2(database.get("temp1", { $not: { id: 1 } })).eventually.to.have.length(2).with.shape([{ id: 2 }, { id: 3 }]); await expect2(database.get("temp1", { $not: { id: { $ne: 1 } } })).eventually.to.have.length(1).with.shape([{ id: 1 }]); }); }, "LogicalQueryLevel"); Logical2.fieldLevel = /* @__PURE__ */ __name(function LogicalFieldLevel(database) { before(async () => { await database.remove("temp1", {}); await database.create("temp1", { id: 1 }); await database.create("temp1", { id: 2 }); await database.create("temp1", { id: 3 }); }); it("edge cases", async () => { await expect2(database.get("temp1", { id: {} })).eventually.to.have.length(3); await expect2(database.get("temp1", { id: { $and: [] } })).eventually.to.have.length(3); await expect2(database.get("temp1", { id: { $or: [] } })).eventually.to.have.length(0); await expect2(database.get("temp1", { id: { $not: {} } })).eventually.to.have.length(0); await expect2(database.get("temp1", { id: { $not: { $and: [] } } })).eventually.to.have.length(0); await expect2(database.get("temp1", { id: { $not: { $or: [] } } })).eventually.to.have.length(3); }); it("$or", async () => { await expect2(database.get("temp1", { id: { $or: [1, { $gt: 2 }] } })).eventually.to.have.length(2).with.shape([{ id: 1 }, { id: 3 }]); await expect2(database.get("temp1", { id: { $or: [1, { $gt: 2 }], $ne: 3 } })).eventually.to.have.length(1).with.shape([{ id: 1 }]); }); it("$and", async () => { await expect2(database.get("temp1", { id: { $and: [[1, 2], { $lt: 2 }] } })).eventually.to.have.length(1).with.shape([{ id: 1 }]); await expect2(database.get("temp1", { id: { $and: [[1, 2], { $lt: 2 }], $eq: 2 } })).eventually.to.have.length(0); }); it("$not", async () => { await expect2(database.get("temp1", { id: { $not: 1 } })).eventually.to.have.length(2).with.shape([{ id: 2 }, { id: 3 }]); await expect2(database.get("temp1", { id: { $not: 1, $lt: 3 } })).eventually.to.have.length(1).with.shape([{ id: 2 }]); }); }, "LogicalFieldLevel"); })(Logical || (Logical = {})); QueryOperators2.logical = Logical; })(QueryOperators || (QueryOperators = {})); var query_default = QueryOperators; // src/update.ts import { $ as $3 } from "minato"; import { deepEqual as deepEqual2, omit as omit2 } from "cosmokit"; import { expect as expect3 } from "chai"; function OrmOperations(database) { before(() => { database.extend("temp2", { id: "unsigned", text: "string", num: "integer", double: "double", bool: "boolean", list: "list", timestamp: "timestamp", date: "date", time: "time", bigtext: "text", binary: "binary", bigint: { type: "string", dump: /* @__PURE__ */ __name((value) => value ? value.toString() : value, "dump"), load: /* @__PURE__ */ __name((value) => value ? BigInt(value) : value, "load") } }, { autoInc: true, indexes: ["text"] }); database.extend("temp3", { ida: "unsigned", idb: "string", value: "string" }, { primary: ["ida", "idb"], unique: ["value"] }); }); } __name(OrmOperations, "OrmOperations"); ((OrmOperations2) => { const merge = /* @__PURE__ */ __name((a, b) => ({ ...a, ...b }), "merge"); const magicBorn = /* @__PURE__ */ new Date("1970/08/17"); const toBinary2 = /* @__PURE__ */ __name((source) => new TextEncoder().encode(source).buffer, "toBinary"); const barTable = [ { id: 1, bool: true }, { id: 2, text: "pku" }, { id: 3, num: 1989 }, { id: 4, list: ["1", "1", "4"] }, { id: 5, timestamp: magicBorn }, { id: 6, date: magicBorn }, { id: 7, time: /* @__PURE__ */ new Date("1970-01-01 12:00:00") }, { id: 8, binary: toBinary2("hello") }, { id: 9, bigint: BigInt(1e63) }, { id: 10, text: "a\b \f\n\r'\"\\`b", list: ["a\b \f\n\r'\"\\`b"] } ]; const bazTable = [ { ida: 1, idb: "a", value: "a" }, { ida: 2, idb: "a", value: "b" }, { ida: 1, idb: "b", value: "c" }, { ida: 2, idb: "b", value: "d" } ]; async function setup2(database, name, table) { await database.remove(name, {}); const result = []; for (const item of table) { result.push(await database.create(name, item)); } return result; } __name(setup2, "setup"); OrmOperations2.create = /* @__PURE__ */ __name(function Create(database) { it("auto increment primary key", async () => { const table = barTable.map((bar) => merge(database.tables.temp2.create(), bar)); for (const index2 in barTable) { const bar = await database.create("temp2", omit2(barTable[index2], ["id"])); barTable[index2].id = bar.id; expect3(bar).to.have.shape(table[index2]); } for (const obj of table) { await expect3(database.get("temp2", { id: obj.id })).to.eventually.have.shape([obj]); } await expect3(database.get("temp2", {})).to.eventually.have.shape(table); await database.remove("temp2", { id: table.length }); await expect3(database.create("temp2", {})).to.eventually.have.shape({ id: table.length + 1 }); }); it("specify primary key", async () => { for (const obj of bazTable) { await expect3(database.create("temp3", obj)).eventually.shape(obj); } for (const obj of bazTable) { await expect3(database.get("temp3", { ida: obj.ida, idb: obj.idb })).eventually.shape([obj]); } }); it("missing primary key", async () => { await expect3(database.create("temp3", { ida: 1 })).eventually.rejected; }); it("duplicate primary key", async () => { await expect3(database.create("temp2", { id: barTable[0].id })).eventually.rejected; await expect3(database.create("temp3", { ida: 1, idb: "a" })).eventually.rejected; }); it("parallel create", async () => { await database.remove("temp2", {}); await Promise.all([...Array(5)].map(() => database.create("temp2", {}))); const result = await database.get("temp2", {}); expect3(result).length(5); const ids = result.map((e) => e.id).sort((a, b) => a - b); const min = Math.min(...ids); expect3(ids.map((id) => id - min + 1)).shape([1, 2, 3, 4, 5]); await database.remove("temp2", {}); }); it("enormous field", async () => { const row = { id: 100, bigtext: Array(1e6).fill("a").join("") }; await database.create("temp2", row); await expect3(database.get("temp2", 100)).to.eventually.have.nested.property("0.bigtext", row.bigtext); }); it("advanced type", async () => { await setup2(database, "temp2", barTable); await expect3(database.create("temp2", { binary: toBinary2("world") })).to.eventually.have.shape({ binary: toBinary2("world") }); await expect3(database.get("temp2", { binary: { $exists: true } })).to.eventually.have.shape([ { binary: toBinary2("hello") }, { binary: toBinary2("world") } ]); await expect3(database.create("temp2", { bigint: 1234567891011121314151617181920n })).to.eventually.have.shape({ bigint: 1234567891011121314151617181920n }); await expect3(database.get("temp2", { bigint: { $exists: true } })).to.eventually.have.shape([ { bigint: BigInt(1e63) }, { bigint: 1234567891011121314151617181920n } ]); }); }, "Create"); OrmOperations2.set = /* @__PURE__ */ __name(function Set2(database) { it("basic support", async () => { const table = await setup2(database, "temp2", barTable); const data = table.find((bar) => bar.timestamp); data.list = ["2", "3", "3"]; data.text = `$'"%~\``; const magicIds = table.slice(2, 4).map((data2) => { data2.list = ["2", "3", "3"]; data2.text = `$'"%~\``; return data2.id; });