@primate/core 0.9.10 → 0.9.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/private/db/test.js +49 -13
- package/lib/private/store/Store.d.ts +3 -6
- package/lib/private/store.d.ts +3 -1
- package/package.json +1 -1
package/lib/private/db/test.js
CHANGED
|
@@ -132,6 +132,29 @@ export default (db) => {
|
|
|
132
132
|
name: p.string.default("Donald"),
|
|
133
133
|
},
|
|
134
134
|
});
|
|
135
|
+
test.case("insert type accepts explicit undefined for write-optional fields", assert => {
|
|
136
|
+
const insert = {
|
|
137
|
+
age: undefined,
|
|
138
|
+
id: undefined,
|
|
139
|
+
name: undefined,
|
|
140
|
+
lastname: undefined,
|
|
141
|
+
};
|
|
142
|
+
assert(insert).type();
|
|
143
|
+
User.insert({
|
|
144
|
+
age: undefined,
|
|
145
|
+
id: undefined,
|
|
146
|
+
name: undefined,
|
|
147
|
+
lastname: undefined,
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
test.case("insert type survives omit", assert => {
|
|
151
|
+
const insert = {
|
|
152
|
+
age: undefined,
|
|
153
|
+
id: undefined,
|
|
154
|
+
lastname: undefined,
|
|
155
|
+
};
|
|
156
|
+
assert(insert).type();
|
|
157
|
+
});
|
|
135
158
|
const UserN = store({
|
|
136
159
|
table: "user_n",
|
|
137
160
|
db,
|
|
@@ -317,7 +340,9 @@ export default (db) => {
|
|
|
317
340
|
});
|
|
318
341
|
}
|
|
319
342
|
function bad_where(label, mk, expected) {
|
|
320
|
-
return security_pair("where", label, mk, base => User.find({ where: base }), w => Author.find({
|
|
343
|
+
return security_pair("where", label, mk, base => User.find({ where: base }), w => Author.find({
|
|
344
|
+
with: { articles: { store: Article, where: w } },
|
|
345
|
+
}), expected);
|
|
321
346
|
}
|
|
322
347
|
function bad_select(label, mk, expected) {
|
|
323
348
|
return security_pair("find", label, mk, base => User.find({ select: base }), w => Author.find({ with: { articles: { store: Article, select: w } } }), expected);
|
|
@@ -1084,7 +1109,9 @@ export default (db) => {
|
|
|
1084
1109
|
//const missing = `missing-${Date.now()}-${Math.random()}`;
|
|
1085
1110
|
const missing = "00000000-0000-4000-8000-000000000000";
|
|
1086
1111
|
await throws(assert, Code.record_not_found, () => Article.get(missing, { with: { author: Author } }));
|
|
1087
|
-
assert(await Article.try(missing, {
|
|
1112
|
+
assert(await Article.try(missing, {
|
|
1113
|
+
with: { author: Author },
|
|
1114
|
+
})).undefined();
|
|
1088
1115
|
});
|
|
1089
1116
|
$rel("get/try: missing id (+ parent)", async (assert) => {
|
|
1090
1117
|
const missing = "00000000-0000-4000-8000-000000000000";
|
|
@@ -1287,7 +1314,8 @@ export default (db) => {
|
|
|
1287
1314
|
assert(rows.length).equals(1);
|
|
1288
1315
|
assert(rows[0].id).equals(u.id);
|
|
1289
1316
|
});
|
|
1290
|
-
/*$store("json column: inferred type on insert", AuthorWithJSON,
|
|
1317
|
+
/*$store("json column: inferred type on insert", AuthorWithJSON,
|
|
1318
|
+
async assert => {
|
|
1291
1319
|
const author = await AuthorWithJSON.insert({
|
|
1292
1320
|
name: "John",
|
|
1293
1321
|
articles: [{ title: "First", published: new Date() }],
|
|
@@ -1322,7 +1350,9 @@ export default (db) => {
|
|
|
1322
1350
|
});
|
|
1323
1351
|
const author = await AuthorWithJSON.get(a.id);
|
|
1324
1352
|
|
|
1325
|
-
assert(author.articles).type<{
|
|
1353
|
+
assert(author.articles).type<{
|
|
1354
|
+
title: string; published: Date
|
|
1355
|
+
}[] | undefined>();
|
|
1326
1356
|
assert(author.meta).type<{ views: number; tags: string[] } | undefined>();
|
|
1327
1357
|
assert(author.notes).type<JSONValue | undefined>();
|
|
1328
1358
|
|
|
@@ -1331,7 +1361,8 @@ export default (db) => {
|
|
|
1331
1361
|
assert(author.articles?.[0].published).type<Date | undefined>();
|
|
1332
1362
|
});
|
|
1333
1363
|
|
|
1334
|
-
$store("json column: roundtrip preserves types", AuthorWithJSON,
|
|
1364
|
+
$store("json column: roundtrip preserves types", AuthorWithJSON,
|
|
1365
|
+
async assert => {
|
|
1335
1366
|
const now = new Date();
|
|
1336
1367
|
const a = await AuthorWithJSON.insert({
|
|
1337
1368
|
name: "John",
|
|
@@ -1354,7 +1385,9 @@ export default (db) => {
|
|
|
1354
1385
|
await AuthorWithJSON.find({ where: { meta: { tags: { $like: "%ts%" } } } });
|
|
1355
1386
|
|
|
1356
1387
|
// $contains always available, untyped
|
|
1357
|
-
await AuthorWithJSON.find({ where: {
|
|
1388
|
+
await AuthorWithJSON.find({ where: {
|
|
1389
|
+
articles: { $contains: { title: "First" } } },
|
|
1390
|
+
});
|
|
1358
1391
|
});*/
|
|
1359
1392
|
$user("where: null matches unset via update", async (assert) => {
|
|
1360
1393
|
const [paul] = await User.find({ where: { name: "Paul" } });
|
|
@@ -1571,7 +1604,7 @@ export default (db) => {
|
|
|
1571
1604
|
select: ["name"],
|
|
1572
1605
|
with: {
|
|
1573
1606
|
articles: {
|
|
1574
|
-
store: Article, select: ["title"], sort: { title: "asc" }
|
|
1607
|
+
store: Article, select: ["title"], sort: { title: "asc" },
|
|
1575
1608
|
},
|
|
1576
1609
|
},
|
|
1577
1610
|
sort: { name: "asc" },
|
|
@@ -1622,7 +1655,9 @@ export default (db) => {
|
|
|
1622
1655
|
id: key.primary(p.uuid),
|
|
1623
1656
|
parent_id: key.foreign(p.uuid),
|
|
1624
1657
|
url: p.url.optional(),
|
|
1625
|
-
parent: relation.one({
|
|
1658
|
+
parent: relation.one({
|
|
1659
|
+
table: "j_parent", by: "parent_id", reverse: true,
|
|
1660
|
+
}),
|
|
1626
1661
|
},
|
|
1627
1662
|
});
|
|
1628
1663
|
await Parent.create();
|
|
@@ -1636,7 +1671,7 @@ export default (db) => {
|
|
|
1636
1671
|
parent_id: p0.id,
|
|
1637
1672
|
url: new URL("https://example.com/joined"),
|
|
1638
1673
|
});
|
|
1639
|
-
//
|
|
1674
|
+
// force joined path + projection that omits pk, but still must join
|
|
1640
1675
|
const [got] = await Parent.find({
|
|
1641
1676
|
where: { id: p0.id },
|
|
1642
1677
|
select: ["url"],
|
|
@@ -1645,11 +1680,12 @@ export default (db) => {
|
|
|
1645
1680
|
assert(got).defined();
|
|
1646
1681
|
// pk must not leak
|
|
1647
1682
|
assert("id" in got).false();
|
|
1648
|
-
//
|
|
1683
|
+
// base assertion (should fail if joined base isn't unbound/decoded)
|
|
1649
1684
|
assert(got.url).type();
|
|
1650
1685
|
assert(got.url instanceof URL).true();
|
|
1651
1686
|
assert(got.url.href).equals("https://example.com/parent");
|
|
1652
|
-
//
|
|
1687
|
+
// relation assertion (should fail if joined relation isn't
|
|
1688
|
+
// unbound/decoded)
|
|
1653
1689
|
assert(Array.isArray(got.children)).true();
|
|
1654
1690
|
assert(got.children.length).equals(1);
|
|
1655
1691
|
const c0 = got.children[0];
|
|
@@ -1912,7 +1948,7 @@ export default (db) => {
|
|
|
1912
1948
|
$user("find: offset skips records", async (assert) => {
|
|
1913
1949
|
const all = await User.find({ sort: { name: "asc" } });
|
|
1914
1950
|
const offset = await User.find({
|
|
1915
|
-
sort: { name: "asc" }, offset: 2, limit: all.length - 2
|
|
1951
|
+
sort: { name: "asc" }, offset: 2, limit: all.length - 2,
|
|
1916
1952
|
});
|
|
1917
1953
|
assert(offset.length).equals(all.length - 2);
|
|
1918
1954
|
assert(offset[0].name).equals(all[2].name);
|
|
@@ -1920,7 +1956,7 @@ export default (db) => {
|
|
|
1920
1956
|
$user("find: offset 0 is same as no offset", async (assert) => {
|
|
1921
1957
|
const without = await User.find({ sort: { name: "asc" } });
|
|
1922
1958
|
const with_zero = await User.find({
|
|
1923
|
-
sort: { name: "asc" }, offset: 0, limit: without.length
|
|
1959
|
+
sort: { name: "asc" }, offset: 0, limit: without.length,
|
|
1924
1960
|
});
|
|
1925
1961
|
assert(with_zero.length).equals(without.length);
|
|
1926
1962
|
assert(with_zero.map(r => r.name)).equals(without.map(r => r.name));
|
|
@@ -8,7 +8,7 @@ import type Init from "#store/Init";
|
|
|
8
8
|
import type PrimaryKey from "#store/PrimaryKey";
|
|
9
9
|
import type { ManyRelation, OneRelation, Relation } from "#store/relation";
|
|
10
10
|
import type StoreInput from "#store/StoreInput";
|
|
11
|
-
import type { Dict, Serializable } from "@rcompat/type";
|
|
11
|
+
import type { Dict, Serializable, Unpack } from "@rcompat/type";
|
|
12
12
|
import type { DefaultType, InferStore, Storable } from "pema";
|
|
13
13
|
import StoreType from "pema/StoreType";
|
|
14
14
|
declare const brand: unique symbol;
|
|
@@ -18,9 +18,6 @@ type X<T> = {
|
|
|
18
18
|
type OrNull<T> = {
|
|
19
19
|
[P in keyof T]?: null | T[P] | undefined;
|
|
20
20
|
};
|
|
21
|
-
type Optional<T> = {
|
|
22
|
-
[P in keyof T]?: T[P] | undefined;
|
|
23
|
-
};
|
|
24
21
|
type StringOperators = {
|
|
25
22
|
$like?: string;
|
|
26
23
|
$ilike?: string;
|
|
@@ -62,7 +59,7 @@ type Projected<T, S extends Select<T> | undefined> = S extends readonly (keyof T
|
|
|
62
59
|
type DefaultFields<T extends StoreInput> = {
|
|
63
60
|
[K in keyof InferRecord<T>]: T[K] extends DefaultType<any, any> ? K : never;
|
|
64
61
|
}[keyof InferRecord<T>];
|
|
65
|
-
type Insertable<T extends StoreInput> =
|
|
62
|
+
type Insertable<T extends StoreInput> = Omit<InferRecord<T>, PrimaryKeyField<T> | DefaultFields<T>> & Partial<Pick<InferRecord<T>, PrimaryKeyField<T> | DefaultFields<T>>>;
|
|
66
63
|
type PrimaryKeyField<T extends StoreInput> = {
|
|
67
64
|
[K in keyof T]: T[K] extends PrimaryKey<any> ? K : never;
|
|
68
65
|
}[keyof T] & keyof InferRecord<T>;
|
|
@@ -100,7 +97,7 @@ type ReadSort = Dict<"asc" | "desc">;
|
|
|
100
97
|
export default class Store<T extends StoreInput, N extends string = string> implements Serializable {
|
|
101
98
|
#private;
|
|
102
99
|
[brand]: boolean;
|
|
103
|
-
readonly Insert: Insertable<T
|
|
100
|
+
readonly Insert: Unpack<Insertable<T>>;
|
|
104
101
|
readonly Schema: Schema<T>;
|
|
105
102
|
static is(x: unknown): x is Store<any, any>;
|
|
106
103
|
constructor(init: Init<T, N>);
|
package/lib/private/store.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ import key from "#store/key";
|
|
|
3
3
|
import relation from "#store/relation";
|
|
4
4
|
import Store from "#store/Store";
|
|
5
5
|
import type StoreInput from "#store/StoreInput";
|
|
6
|
-
declare function store<T extends StoreInput, const N extends string = string>(init: Init<T, N>
|
|
6
|
+
declare function store<T extends StoreInput, const N extends string = string>(init: Omit<Init<T, N>, "schema"> & {
|
|
7
|
+
schema: T;
|
|
8
|
+
}): Store<T, N>;
|
|
7
9
|
declare namespace store {
|
|
8
10
|
export { key };
|
|
9
11
|
export { relation };
|