@arkiv-network/sdk 0.8.1 → 0.9.0-next.2
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/README.md +180 -61
- package/dist/chains/index.d.cts +17 -17
- package/dist/chains/index.d.ts +17 -17
- package/dist/changeOwnership-Cy9gfyjN.d.cts +1160 -0
- package/dist/changeOwnership-Cy9gfyjN.d.cts.map +1 -0
- package/dist/changeOwnership-gXf-lBqI.d.ts +1160 -0
- package/dist/changeOwnership-gXf-lBqI.d.ts.map +1 -0
- package/dist/entity/index.cjs +4 -10
- package/dist/entity/index.d.cts +3 -3
- package/dist/entity/index.d.ts +3 -3
- package/dist/entity/index.js +3 -4
- package/dist/entity-BM1unrQf.cjs +41 -0
- package/dist/{entity-DJ0Gml9c.cjs → entity-BgaFJSaV.cjs} +4 -4
- package/dist/entity-CFAI1KyG.js +36 -0
- package/dist/entity-CFAI1KyG.js.map +1 -0
- package/dist/{entity-CniBgBSd.js → entity-CGqx_AU0.js} +4 -4
- package/dist/entity-CGqx_AU0.js.map +1 -0
- package/dist/{payload-AfUfSctb.d.ts → expirationTime-C7PZK49K.d.ts} +8 -37
- package/dist/expirationTime-C7PZK49K.d.ts.map +1 -0
- package/dist/expirationTime-CkIGNAg8.cjs +140 -0
- package/dist/{payload-D167BlJR.d.cts → expirationTime-DOB8V4B8.d.cts} +8 -37
- package/dist/expirationTime-DOB8V4B8.d.cts.map +1 -0
- package/dist/{expiry-Cgdb_dbq.js → expirationTime-UKPuA-LM.js} +62 -27
- package/dist/expirationTime-UKPuA-LM.js.map +1 -0
- package/dist/expiry-B48I-yTA.d.cts +40 -0
- package/dist/expiry-B48I-yTA.d.cts.map +1 -0
- package/dist/expiry-S2PUL8Hg.d.ts +40 -0
- package/dist/expiry-S2PUL8Hg.d.ts.map +1 -0
- package/dist/index-C-mMF5WZ.d.cts +735 -0
- package/dist/index-C-mMF5WZ.d.cts.map +1 -0
- package/dist/{index-BkqSnGJH.d.ts → index-C4zZqJ9S.d.ts} +5 -27
- package/dist/index-C4zZqJ9S.d.ts.map +1 -0
- package/dist/{index-CLhsFyVH.d.cts → index-CcVWYB6v.d.cts} +5 -27
- package/dist/index-CcVWYB6v.d.cts.map +1 -0
- package/dist/index-DCx2XC6S.d.ts +489 -0
- package/dist/index-DCx2XC6S.d.ts.map +1 -0
- package/dist/index-DLb7BfIw.d.ts +735 -0
- package/dist/index-DLb7BfIw.d.ts.map +1 -0
- package/dist/index-DzriOUm8.d.cts +489 -0
- package/dist/index-DzriOUm8.d.cts.map +1 -0
- package/dist/index.cjs +162 -146
- package/dist/index.d.cts +180 -133
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +180 -133
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +93 -83
- package/dist/index.js.map +1 -1
- package/dist/params-BuIrJA9a.cjs +45 -0
- package/dist/params-DDJOnsNi.js +22 -0
- package/dist/params-DDJOnsNi.js.map +1 -0
- package/dist/query/index.cjs +9 -4
- package/dist/query/index.d.cts +6 -6
- package/dist/query/index.d.ts +6 -6
- package/dist/query/index.js +4 -5
- package/dist/query-D0KtuFh2.cjs +1625 -0
- package/dist/query-DpRDozmj.js +1417 -0
- package/dist/query-DpRDozmj.js.map +1 -0
- package/dist/schema/index.cjs +46 -0
- package/dist/schema/index.d.cts +2 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +3 -0
- package/dist/{attr-BXTkpnoc.cjs → schema-B9AyXcgU.cjs} +513 -246
- package/dist/{attr-tmyREHtw.js → schema-DY4sqehl.js} +427 -244
- package/dist/schema-DY4sqehl.js.map +1 -0
- package/dist/types/index.cjs +1 -1
- package/dist/types/index.d.cts +5 -5
- package/dist/types/index.d.ts +5 -5
- package/dist/types/index.js +1 -1
- package/dist/utils/index.cjs +3 -5
- package/dist/utils/index.d.cts +3 -3
- package/dist/utils/index.d.ts +3 -3
- package/dist/utils/index.js +3 -3
- package/package.json +9 -12
- package/src/actions/public/getEntity.test.ts +69 -0
- package/src/actions/public/getEntity.ts +34 -20
- package/src/actions/public/predictEntityKeys.ts +8 -7
- package/src/actions/public/query.test.ts +58 -0
- package/src/actions/public/query.ts +41 -13
- package/src/actions/wallet/createEntity.ts +34 -63
- package/src/actions/wallet/executeBatch.test.ts +38 -0
- package/src/actions/wallet/executeBatch.ts +26 -9
- package/src/actions/wallet/extendEntity.ts +9 -8
- package/src/actions/wallet/patchEntity.ts +43 -52
- package/src/clients/createPublicClient.test.ts +10 -2
- package/src/clients/createWalletClient.ts +4 -1
- package/src/clients/decorators/arkivPublic.ts +123 -80
- package/src/clients/decorators/arkivWallet.ts +113 -65
- package/src/entity/create.test.ts +25 -21
- package/src/entity/expiry.ts +8 -6
- package/src/entity/flags.ts +1 -1
- package/src/entity/index.ts +2 -4
- package/src/entity/key.ts +3 -3
- package/src/entity/operations.ts +1 -1
- package/src/errors.ts +2 -11
- package/src/index.ts +18 -6
- package/src/query/builderBase.ts +166 -0
- package/src/query/countBuilder.test.ts +91 -0
- package/src/query/countBuilder.ts +67 -0
- package/src/query/engine.ts +9 -3
- package/src/query/errors.ts +24 -14
- package/src/query/expression.test.ts +129 -21
- package/src/query/expression.ts +323 -94
- package/src/query/index.ts +26 -4
- package/src/query/injection.test.ts +5 -11
- package/src/query/queryBuilder.test.ts +467 -58
- package/src/query/queryBuilder.ts +191 -98
- package/src/query/queryResult.ts +35 -9
- package/src/query/selection.test.ts +278 -24
- package/src/query/selection.ts +427 -86
- package/src/schema/attributes.test.ts +266 -0
- package/src/schema/attributes.ts +212 -0
- package/src/{attr → schema}/codec.test.ts +37 -5
- package/src/{attr → schema}/codec.ts +40 -11
- package/src/schema/column.ts +193 -0
- package/src/{attr → schema}/errors.ts +67 -10
- package/src/schema/index.ts +76 -0
- package/src/{attr → schema}/names.ts +4 -2
- package/src/schema/schema.test.ts +171 -0
- package/src/schema/schema.ts +250 -0
- package/src/{attr → schema}/types.ts +36 -30
- package/src/{attr → schema}/values.test.ts +62 -3
- package/src/{attr → schema}/values.ts +246 -65
- package/src/types/entity.test.ts +1 -44
- package/src/types/entity.ts +9 -55
- package/src/types/events.ts +1 -1
- package/src/types/index.ts +11 -4
- package/src/types/rpcSchema.ts +22 -16
- package/src/utils/arkivTransactions.test.ts +356 -116
- package/src/utils/arkivTransactions.ts +30 -38
- package/src/utils/entities.ts +10 -9
- package/src/utils/expirationTime.ts +5 -5
- package/src/utils/index.ts +0 -1
- package/src/utils/logger.test.ts +45 -0
- package/src/utils/logger.ts +5 -39
- package/src/utils/revert.test.ts +25 -0
- package/src/utils/revert.ts +28 -3
- package/dist/attr/index.cjs +0 -34
- package/dist/attr/index.d.cts +0 -2
- package/dist/attr/index.d.ts +0 -2
- package/dist/attr/index.js +0 -3
- package/dist/attr-tmyREHtw.js.map +0 -1
- package/dist/entity-B0t6sN7F.cjs +0 -71
- package/dist/entity-BIp_df9u.js +0 -67
- package/dist/entity-BIp_df9u.js.map +0 -1
- package/dist/entity-CniBgBSd.js.map +0 -1
- package/dist/expiry-BxOlvVWC.d.ts +0 -79
- package/dist/expiry-BxOlvVWC.d.ts.map +0 -1
- package/dist/expiry-CG9GhVXv.cjs +0 -135
- package/dist/expiry-Cgdb_dbq.js.map +0 -1
- package/dist/expiry-DRV29F1r.d.cts +0 -79
- package/dist/expiry-DRV29F1r.d.cts.map +0 -1
- package/dist/flags-DCD26uhe.cjs +0 -43
- package/dist/flags-DUT2gHEU.js +0 -33
- package/dist/flags-DUT2gHEU.js.map +0 -1
- package/dist/index-BkqSnGJH.d.ts.map +0 -1
- package/dist/index-C7fbakoI.d.cts +0 -278
- package/dist/index-C7fbakoI.d.cts.map +0 -1
- package/dist/index-CIcHPx2j.d.cts +0 -424
- package/dist/index-CIcHPx2j.d.cts.map +0 -1
- package/dist/index-CLhsFyVH.d.cts.map +0 -1
- package/dist/index-Cd2aaWme.d.ts +0 -424
- package/dist/index-Cd2aaWme.d.ts.map +0 -1
- package/dist/index-Cq6fa8AI.d.ts +0 -278
- package/dist/index-Cq6fa8AI.d.ts.map +0 -1
- package/dist/index-DaNeJUw8.d.ts +0 -955
- package/dist/index-DaNeJUw8.d.ts.map +0 -1
- package/dist/index-Dv16LO2s.d.cts +0 -955
- package/dist/index-Dv16LO2s.d.cts.map +0 -1
- package/dist/payload-AfUfSctb.d.ts.map +0 -1
- package/dist/payload-D167BlJR.d.cts.map +0 -1
- package/dist/payload-DE7wMztL.js +0 -92
- package/dist/payload-DE7wMztL.js.map +0 -1
- package/dist/payload-DqFweqiO.cjs +0 -108
- package/dist/query-9oojUdM7.cjs +0 -1128
- package/dist/query-Ber-lOJQ.js +0 -968
- package/dist/query-Ber-lOJQ.js.map +0 -1
- package/src/actions/public/getEntityCount.ts +0 -10
- package/src/attr/attributes.test.ts +0 -120
- package/src/attr/attributes.ts +0 -196
- package/src/attr/index.ts +0 -50
- package/src/types/mimeTypes.ts +0 -27
- package/src/utils/compression.test.ts +0 -32
- package/src/utils/compression.ts +0 -102
- package/src/utils/payload.ts +0 -36
- /package/src/{attr → schema}/decimal.ts +0 -0
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test"
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
addr,
|
|
4
|
+
bytes,
|
|
5
|
+
dec,
|
|
6
|
+
defineSchema,
|
|
7
|
+
InvalidAttributeNameError,
|
|
8
|
+
i32,
|
|
9
|
+
SchemaMismatchError,
|
|
10
|
+
str,
|
|
11
|
+
u256,
|
|
12
|
+
} from "../schema"
|
|
13
|
+
import { Entity } from "../types/entity"
|
|
14
|
+
import { projectSelection, toRow, toRpcSelect } from "./selection"
|
|
3
15
|
|
|
4
16
|
const EVERY_FIELD = {
|
|
5
17
|
key: true,
|
|
@@ -9,22 +21,25 @@ const EVERY_FIELD = {
|
|
|
9
21
|
updatedAt: true,
|
|
10
22
|
expiresAt: true,
|
|
11
23
|
creationFlags: true,
|
|
12
|
-
|
|
13
|
-
payload: true,
|
|
14
|
-
attributeSchema: true,
|
|
24
|
+
attributeSchema: false,
|
|
15
25
|
attributes: true,
|
|
16
26
|
}
|
|
17
27
|
|
|
18
28
|
describe("toRpcSelect", () => {
|
|
19
|
-
it("selects
|
|
29
|
+
it("selects every field and attribute for no argument or a star, but not the schema", () => {
|
|
30
|
+
// The attribute schema describes an entity's shape rather than the entity, so it is only
|
|
31
|
+
// returned when asked for by name.
|
|
20
32
|
expect(toRpcSelect()).toEqual(EVERY_FIELD)
|
|
21
33
|
expect(toRpcSelect("*")).toEqual(EVERY_FIELD)
|
|
34
|
+
expect(toRpcSelect({ $key: true, $attributeSchema: true })).toMatchObject({
|
|
35
|
+
attributeSchema: true,
|
|
36
|
+
})
|
|
22
37
|
})
|
|
23
38
|
|
|
24
39
|
it("sends every field, so what was asked for is legible in the request", () => {
|
|
25
40
|
// The node defaults everything but `key` to off. Spelling out the false ones costs nothing and
|
|
26
41
|
// pins the answer even if those defaults move.
|
|
27
|
-
expect(toRpcSelect({ owner: true })).toEqual({
|
|
42
|
+
expect(toRpcSelect({ $owner: true })).toEqual({
|
|
28
43
|
key: false,
|
|
29
44
|
owner: true,
|
|
30
45
|
creator: false,
|
|
@@ -32,39 +47,278 @@ describe("toRpcSelect", () => {
|
|
|
32
47
|
updatedAt: false,
|
|
33
48
|
expiresAt: false,
|
|
34
49
|
creationFlags: false,
|
|
35
|
-
contentType: false,
|
|
36
|
-
payload: false,
|
|
37
50
|
attributeSchema: false,
|
|
38
51
|
attributes: false,
|
|
39
52
|
})
|
|
40
53
|
})
|
|
41
54
|
|
|
42
|
-
it("
|
|
43
|
-
expect(
|
|
44
|
-
toRpcSelect({ key: true, attributes: { projectId: true, version: true } }),
|
|
45
|
-
).toMatchObject({
|
|
55
|
+
it("asks for any name without a $ as an attribute, by name", () => {
|
|
56
|
+
expect(toRpcSelect({ $key: true, title: true, body: true })).toMatchObject({
|
|
46
57
|
key: true,
|
|
47
|
-
attributes: {
|
|
58
|
+
attributes: { title: true, body: true },
|
|
48
59
|
})
|
|
60
|
+
expect(toRpcSelect({ title: true, body: false })).toMatchObject({ attributes: { title: true } })
|
|
61
|
+
expect(() => toRpcSelect({ "not a name": true })).toThrow(InvalidAttributeNameError)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it("reads a name an entity field has, written without the $, as an attribute", () => {
|
|
65
|
+
// `owner` and `attributes` are ordinary attribute names; only `$owner` is the entity field.
|
|
66
|
+
expect(toRpcSelect({ owner: true, attributes: true })).toMatchObject({
|
|
67
|
+
owner: false,
|
|
68
|
+
attributes: { owner: true, attributes: true },
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it("asks for every attribute with $attributes, and their types with $attributeSchema", () => {
|
|
73
|
+
expect(toRpcSelect({ $key: true, $attributes: true, $attributeSchema: true })).toMatchObject({
|
|
74
|
+
key: true,
|
|
75
|
+
attributes: true,
|
|
76
|
+
attributeSchema: true,
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it("rejects a map for $attributes, pointing at selecting attributes by name", () => {
|
|
81
|
+
expect(() => toRpcSelect({ $attributes: { title: true } } as never)).toThrow(
|
|
82
|
+
/select each by name/,
|
|
83
|
+
)
|
|
49
84
|
})
|
|
50
85
|
|
|
51
|
-
it("
|
|
52
|
-
expect(
|
|
53
|
-
|
|
54
|
-
)
|
|
55
|
-
// An empty subset asks for no attributes, which is what `false` already means.
|
|
56
|
-
expect(toRpcSelect({ key: true, attributes: {} })).toMatchObject({ attributes: false })
|
|
86
|
+
it("rejects a $ name that is not an entity field", () => {
|
|
87
|
+
expect(() => toRpcSelect({ $title: true })).toThrow(/"\$title", which is not an entity field/)
|
|
88
|
+
// The fields are written with the $, so the bare RPC spelling is not one of them either.
|
|
89
|
+
expect(() => toRpcSelect({ $schema: true })).toThrow(/not an entity field/)
|
|
57
90
|
})
|
|
58
91
|
|
|
59
92
|
it("rejects a selection that asks for nothing", () => {
|
|
60
|
-
// @ts-expect-error - AtLeastOne rejects this at compile time too
|
|
61
93
|
expect(() => toRpcSelect({})).toThrow(/at least one field/)
|
|
62
94
|
// The type system permits an explicit `false`; the node would answer it with empty rows.
|
|
63
|
-
expect(() => toRpcSelect({ key: false })).toThrow(/at least one field/)
|
|
64
|
-
expect(() => toRpcSelect({ key: false,
|
|
95
|
+
expect(() => toRpcSelect({ $key: false })).toThrow(/at least one field/)
|
|
96
|
+
expect(() => toRpcSelect({ $key: false, title: false })).toThrow(/at least one field/)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it("counts an attribute alone as a selection", () => {
|
|
100
|
+
expect(() => toRpcSelect({ title: true })).not.toThrow()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it("treats a field set to undefined as not selected", () => {
|
|
104
|
+
expect(toRpcSelect({ $key: true, $owner: undefined })).toMatchObject({
|
|
105
|
+
key: true,
|
|
106
|
+
owner: false,
|
|
107
|
+
})
|
|
108
|
+
expect(() => toRpcSelect({ $key: undefined })).toThrow(/at least one field/)
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
const Posts = defineSchema({
|
|
113
|
+
author: addr().indexed(),
|
|
114
|
+
score: dec().indexed(),
|
|
115
|
+
title: str(),
|
|
116
|
+
body: bytes(),
|
|
117
|
+
thumbnail: bytes().optional(),
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const KEY = `0x${"ab".repeat(32)}` as const
|
|
121
|
+
const AUTHOR = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
|
|
122
|
+
|
|
123
|
+
describe("projectSelection", () => {
|
|
124
|
+
it("asks for the selected entity fields, and the selected columns by name", () => {
|
|
125
|
+
const projection = projectSelection(
|
|
126
|
+
{ $key: true, title: true, body: true, score: false },
|
|
127
|
+
Posts,
|
|
128
|
+
)
|
|
129
|
+
expect(projection.select).toEqual({
|
|
130
|
+
key: true,
|
|
131
|
+
owner: false,
|
|
132
|
+
creator: false,
|
|
133
|
+
createdAt: false,
|
|
134
|
+
updatedAt: false,
|
|
135
|
+
expiresAt: false,
|
|
136
|
+
creationFlags: false,
|
|
137
|
+
attributeSchema: false,
|
|
138
|
+
attributes: { title: true, body: true },
|
|
139
|
+
})
|
|
140
|
+
expect(projection.fields).toEqual(["$key"])
|
|
141
|
+
expect(projection.columns.map(([name]) => name)).toEqual(["title", "body"])
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it("selects every entity field and every column for nothing or a star", () => {
|
|
145
|
+
for (const selection of [undefined, "*"] as const) {
|
|
146
|
+
const { select } = projectSelection(selection, Posts)
|
|
147
|
+
expect(select).toMatchObject({ key: true, owner: true, creationFlags: true })
|
|
148
|
+
// Named, not `true`: attributes beyond the schema stay on the node.
|
|
149
|
+
expect(select.attributes).toEqual({
|
|
150
|
+
author: true,
|
|
151
|
+
score: true,
|
|
152
|
+
title: true,
|
|
153
|
+
body: true,
|
|
154
|
+
thumbnail: true,
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it("asks for no attributes when only entity fields are selected", () => {
|
|
160
|
+
expect(projectSelection({ $owner: true }, Posts).select.attributes).toBe(false)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it("rejects a name that is not a column", () => {
|
|
164
|
+
expect(() => projectSelection({ $key: true, nope: true }, Posts)).toThrow(
|
|
165
|
+
/"nope", which is not a column/,
|
|
166
|
+
)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it("reads attributes as a whole the same way through a schema as without one", () => {
|
|
170
|
+
const projection = projectSelection({ $key: true, title: true, $attributes: true }, Posts)
|
|
171
|
+
expect(projection.select.attributes).toBe(true)
|
|
172
|
+
const entity = new Entity({ key: KEY, attributes: { title: str("Hi"), extra: i32(1) } })
|
|
173
|
+
expect(toRow(entity, projection)).toEqual({
|
|
174
|
+
$key: KEY,
|
|
175
|
+
title: str("Hi"),
|
|
176
|
+
$attributes: { title: str("Hi"), extra: i32(1) },
|
|
177
|
+
})
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it("rejects a selection that asks for nothing, or a map where a boolean belongs", () => {
|
|
181
|
+
expect(() => projectSelection({ $key: false }, Posts)).toThrow(/at least one field/)
|
|
182
|
+
expect(() => projectSelection({ title: { x: true } } as never, Posts)).toThrow(/true or false/)
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
describe("toRow", () => {
|
|
187
|
+
const projection = projectSelection(
|
|
188
|
+
{ $key: true, author: true, title: true, thumbnail: true },
|
|
189
|
+
Posts,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
it("lays out the selected fields and columns side by side", () => {
|
|
193
|
+
const row = toRow(
|
|
194
|
+
new Entity({
|
|
195
|
+
key: KEY,
|
|
196
|
+
owner: AUTHOR,
|
|
197
|
+
attributes: {
|
|
198
|
+
author: addr(AUTHOR),
|
|
199
|
+
title: str("Hi"),
|
|
200
|
+
thumbnail: bytes("0x01"),
|
|
201
|
+
extra: i32(1),
|
|
202
|
+
},
|
|
203
|
+
}),
|
|
204
|
+
projection,
|
|
205
|
+
)
|
|
206
|
+
expect(row).toEqual({
|
|
207
|
+
$key: KEY,
|
|
208
|
+
author: addr(AUTHOR),
|
|
209
|
+
title: str("Hi"),
|
|
210
|
+
thumbnail: bytes("0x01"),
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it("keeps a column named like an entity field apart from the field", () => {
|
|
215
|
+
const Owned = defineSchema({ owner: addr(), attributes: str() })
|
|
216
|
+
const row = toRow(
|
|
217
|
+
new Entity({
|
|
218
|
+
key: KEY,
|
|
219
|
+
owner: AUTHOR,
|
|
220
|
+
attributes: { owner: addr(KEY.slice(0, 42)), attributes: str("mine") },
|
|
221
|
+
}),
|
|
222
|
+
projectSelection({ $owner: true, owner: true, attributes: true }, Owned),
|
|
223
|
+
)
|
|
224
|
+
expect(row).toEqual({
|
|
225
|
+
$owner: AUTHOR,
|
|
226
|
+
owner: addr(KEY.slice(0, 42)),
|
|
227
|
+
attributes: str("mine"),
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it("gives an optional column the entity lacks as undefined", () => {
|
|
232
|
+
const row = toRow(
|
|
233
|
+
new Entity({ key: KEY, attributes: { author: addr(AUTHOR), title: str("Hi") } }),
|
|
234
|
+
projection,
|
|
235
|
+
)
|
|
236
|
+
expect(row).toHaveProperty("thumbnail", undefined)
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
it("rejects an entity missing a required column, naming the entity", () => {
|
|
240
|
+
const decode = () =>
|
|
241
|
+
toRow(new Entity({ key: KEY, attributes: { author: addr(AUTHOR) } }), projection)
|
|
242
|
+
expect(decode).toThrow(SchemaMismatchError)
|
|
243
|
+
expect(decode).toThrow(new RegExp(`"title".*entity ${KEY} has no value`))
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it("rejects an entity whose column holds another type than the schema declares", () => {
|
|
247
|
+
const decode = () =>
|
|
248
|
+
toRow(
|
|
249
|
+
new Entity({ key: KEY, attributes: { author: addr(AUTHOR), title: i32(1) } }),
|
|
250
|
+
projection,
|
|
251
|
+
)
|
|
252
|
+
expect(decode).toThrow(/holds a i32, not the str the schema declares/)
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
it("reads a column named after an Object.prototype key as absent when the entity lacks it", () => {
|
|
256
|
+
const Odd = defineSchema({ constructor: str().optional(), toString: str().optional() })
|
|
257
|
+
const row = toRow(new Entity({ key: KEY, attributes: {} }), projectSelection("*", Odd))
|
|
258
|
+
expect(row).toHaveProperty("constructor", undefined)
|
|
259
|
+
expect(row).toHaveProperty("toString", undefined)
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
describe("a named schema", () => {
|
|
264
|
+
const Tagged = defineSchema("posts", { title: str(), score: dec().optional() })
|
|
265
|
+
const projection = projectSelection({ $key: true, title: true }, Tagged)
|
|
266
|
+
|
|
267
|
+
it("fetches the tag alongside the columns, even when no column is selected", () => {
|
|
268
|
+
expect(projection.select.attributes).toEqual({ title: true, "arkiv.schema": true })
|
|
269
|
+
expect(projectSelection({ $key: true }, Tagged).select.attributes).toEqual({
|
|
270
|
+
"arkiv.schema": true,
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
it("checks the tag, but leaves it out of the row", () => {
|
|
275
|
+
const row = toRow(
|
|
276
|
+
new Entity({ key: KEY, attributes: { title: str("Hi"), "arkiv.schema": str("posts") } }),
|
|
277
|
+
projection,
|
|
278
|
+
)
|
|
279
|
+
expect(row).toEqual({ $key: KEY, title: str("Hi") })
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
it("rejects an entity tagged by another schema, or not tagged at all", () => {
|
|
283
|
+
const other = () =>
|
|
284
|
+
toRow(
|
|
285
|
+
new Entity({ key: KEY, attributes: { title: str("Hi"), "arkiv.schema": str("comments") } }),
|
|
286
|
+
projection,
|
|
287
|
+
)
|
|
288
|
+
expect(other).toThrow(SchemaMismatchError)
|
|
289
|
+
expect(other).toThrow(/tagged "comments", not "posts"/)
|
|
290
|
+
expect(() =>
|
|
291
|
+
toRow(new Entity({ key: KEY, attributes: { title: str("Hi") } }), projection),
|
|
292
|
+
).toThrow(/not tagged with a schema/)
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
it("leaves the tag out of the attributes map and the attribute schema too", () => {
|
|
296
|
+
const whole = projectSelection(
|
|
297
|
+
{ $key: true, $attributes: true, $attributeSchema: true },
|
|
298
|
+
Tagged,
|
|
299
|
+
)
|
|
300
|
+
const entity = new Entity({
|
|
301
|
+
key: KEY,
|
|
302
|
+
attributes: { title: str("Hi"), "arkiv.schema": str("posts") },
|
|
303
|
+
attributeSchema: {
|
|
304
|
+
title: { type: "str", indexed: false },
|
|
305
|
+
"arkiv.schema": { type: "str", indexed: true },
|
|
306
|
+
},
|
|
307
|
+
})
|
|
308
|
+
expect(toRow(entity, whole)).toEqual({
|
|
309
|
+
$key: KEY,
|
|
310
|
+
$attributes: { title: str("Hi") },
|
|
311
|
+
$attributeSchema: { title: { type: "str", indexed: false } },
|
|
312
|
+
})
|
|
65
313
|
})
|
|
66
314
|
|
|
67
|
-
it("
|
|
68
|
-
|
|
315
|
+
it("rejects an entity whose tag is not a str, whatever its type", () => {
|
|
316
|
+
const decode = () =>
|
|
317
|
+
toRow(
|
|
318
|
+
new Entity({ key: KEY, attributes: { title: str("Hi"), "arkiv.schema": u256(5n) } }),
|
|
319
|
+
projection,
|
|
320
|
+
)
|
|
321
|
+
expect(decode).toThrow(SchemaMismatchError)
|
|
322
|
+
expect(decode).toThrow(/tagged with a value of type u256, not "posts"/)
|
|
69
323
|
})
|
|
70
324
|
})
|