@arkiv-network/sdk 0.8.1-dev.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.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
package/src/query/errors.ts
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
import type { TypeTag } from "../
|
|
1
|
+
import type { TypeTag } from "../schema"
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A predicate asked for an operator the query language does not define for that type.
|
|
5
5
|
*
|
|
6
|
-
* The operator × type matrix is part of the language, not a policy: a
|
|
7
|
-
*
|
|
8
|
-
* a round trip and an RPC error code into a stack trace
|
|
6
|
+
* The operator × type matrix is part of the language, not a policy: a prefix test on a type other
|
|
7
|
+
* than `str` is a **type error** at the node (a {@link QueryError} of kind `"type"`), not
|
|
8
|
+
* an empty result. Catching it here turns a round trip and an RPC error code into a stack trace
|
|
9
|
+
* pointing at the call site.
|
|
9
10
|
*
|
|
10
|
-
* | | `=` `!=`
|
|
11
|
-
* | --- | --- | --- |
|
|
12
|
-
* | `
|
|
13
|
-
* |
|
|
14
|
-
* | `str` | yes | no | yes |
|
|
15
|
-
* | `addr` `key` `bytes32` | yes | no | no |
|
|
11
|
+
* | | `=` `!=` `<` `<=` `>` `>=` `BETWEEN` | `STARTSWITH` |
|
|
12
|
+
* | --- | --- | --- |
|
|
13
|
+
* | `str` | yes | yes |
|
|
14
|
+
* | every other indexable type | yes | no |
|
|
16
15
|
*/
|
|
17
16
|
export class UnsupportedOperatorError extends Error {
|
|
18
17
|
/** The attribute the predicate names. */
|
|
@@ -35,9 +34,20 @@ export class UnsupportedOperatorError extends Error {
|
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
/**
|
|
38
|
-
* A predicate could not be expressed in the query language for a reason other than its
|
|
39
|
-
*
|
|
40
|
-
*
|
|
37
|
+
* A predicate or query could not be expressed in the query language for a reason other than its
|
|
38
|
+
* operator. The main causes:
|
|
39
|
+
*
|
|
40
|
+
* - a `$` name that is not a queryable system attribute — one returned in results but never
|
|
41
|
+
* indexed (`$createdAt`, `$updatedAt`, `$creationFlags`), or none at all;
|
|
42
|
+
* - a system attribute compared against the wrong type, or tested with `exists()` / `hasType()`,
|
|
43
|
+
* which on a system attribute would be constants;
|
|
44
|
+
* - a comparison against a `bytes` value, which is never indexed;
|
|
45
|
+
* - a `BETWEEN` whose bounds have different types;
|
|
46
|
+
* - a `hasType()` tag that is not an indexable type;
|
|
47
|
+
* - a combinator with nothing to combine;
|
|
48
|
+
* - a query with no filter at all — a named schema's tag counts as one;
|
|
49
|
+
* - through `.from(schema)`, a filter that does not fit the schema: a name that is not a column, a
|
|
50
|
+
* column that is not indexed, or a value of another type than the column's.
|
|
41
51
|
*/
|
|
42
52
|
export class InvalidPredicateError extends Error {
|
|
43
53
|
/** The attribute the predicate names, where there is one. */
|
|
@@ -58,7 +68,7 @@ export class InvalidPredicateError extends Error {
|
|
|
58
68
|
export type QueryErrorKind =
|
|
59
69
|
/** The query string does not parse. `data` locates it: `{ position, expected, got }`. */
|
|
60
70
|
| "parse"
|
|
61
|
-
/** A predicate is well-formed but ill-typed — a
|
|
71
|
+
/** A predicate is well-formed but ill-typed — `STARTSWITH` on a type other than `str`, `BETWEEN` bounds of different types, an unknown tag. */
|
|
62
72
|
| "type"
|
|
63
73
|
/** A literal failed validation — an `i32` out of range, a bad EIP-55 checksum, more than 18 decimal places. */
|
|
64
74
|
| "literal"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test"
|
|
2
|
-
import { addr, bytes32, dec, i32, key, str, u64, u256 } from "../
|
|
3
|
-
import { InvalidAttributeNameError } from "../
|
|
2
|
+
import { addr, bytes, bytes32, dec, defineSchema, i32, key, str, u64, u256 } from "../schema"
|
|
3
|
+
import { InvalidAttributeNameError } from "../schema/errors"
|
|
4
4
|
import { InvalidPredicateError, UnsupportedOperatorError } from "./errors"
|
|
5
5
|
import {
|
|
6
6
|
and,
|
|
7
|
+
between,
|
|
8
|
+
checkAgainstSchema,
|
|
7
9
|
eq,
|
|
8
10
|
exists,
|
|
9
11
|
gt,
|
|
@@ -72,30 +74,29 @@ describe("comparisons", () => {
|
|
|
72
74
|
expect(String(lte("a", 1))).toBe("a <= i32(1)")
|
|
73
75
|
})
|
|
74
76
|
|
|
75
|
-
it("allows range operators
|
|
77
|
+
it("allows range operators on every indexable type", () => {
|
|
76
78
|
expect(String(gt("level", i32(1)))).toBe("level > i32(1)")
|
|
77
79
|
expect(String(gt("balance", u256(1n)))).toBe("balance > u256(1)")
|
|
78
80
|
expect(String(gt("score", dec("1.5")))).toBe("score > dec(1.5)")
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
expect(() => lte("name", "Bob")).toThrow(/does not define <= for a str/)
|
|
81
|
+
// Ordered as the index orders them: false < true, and unsigned bytes for the rest.
|
|
82
|
+
expect(String(gte("flagged", true))).toBe("flagged >= true")
|
|
83
|
+
expect(String(lte("name", "Bob"))).toBe("name <= str('Bob')")
|
|
84
|
+
expect(String(lt("who", addr(ACCOUNT)))).toBe(`who < addr(${ACCOUNT})`)
|
|
85
|
+
expect(String(gt("parent", key(ENTITY_KEY)))).toBe(`parent > key(${ENTITY_KEY})`)
|
|
86
|
+
expect(String(gt("hash", bytes32(ENTITY_KEY)))).toBe(`hash > bytes32(${ENTITY_KEY})`)
|
|
86
87
|
})
|
|
87
88
|
|
|
88
89
|
it("carries the offending operator and type on the error", () => {
|
|
89
90
|
try {
|
|
90
|
-
|
|
91
|
+
startsWith("level", i32(1) as never)
|
|
91
92
|
expect.unreachable()
|
|
92
93
|
} catch (error) {
|
|
93
94
|
expect(error).toBeInstanceOf(UnsupportedOperatorError)
|
|
94
95
|
const { attributeName, operator, tag } = error as UnsupportedOperatorError
|
|
95
96
|
expect({ attributeName, operator, tag }).toEqual({
|
|
96
|
-
attributeName: "
|
|
97
|
-
operator: "
|
|
98
|
-
tag: "
|
|
97
|
+
attributeName: "level",
|
|
98
|
+
operator: "STARTSWITH",
|
|
99
|
+
tag: "i32",
|
|
99
100
|
})
|
|
100
101
|
}
|
|
101
102
|
})
|
|
@@ -128,14 +129,16 @@ describe("system attributes", () => {
|
|
|
128
129
|
expect(() => eq("$expiresAt", 1_200_000n)).toThrow(/write u64\(\.\.\.\) around the value/)
|
|
129
130
|
})
|
|
130
131
|
|
|
131
|
-
it("allows range comparisons
|
|
132
|
-
expect((
|
|
133
|
-
expect((
|
|
132
|
+
it("allows range comparisons on every one", () => {
|
|
133
|
+
expect(String(gt("$owner", addr(ACCOUNT)))).toBe(`$owner > addr(${ACCOUNT})`)
|
|
134
|
+
expect(String(lte("$key", key(ENTITY_KEY)))).toBe(`$key <= key(${ENTITY_KEY})`)
|
|
134
135
|
})
|
|
135
136
|
|
|
136
137
|
it("rejects the ones that are returned but not indexed", () => {
|
|
137
|
-
for (const name of ["$createdAt", "$updatedAt", "$creationFlags"
|
|
138
|
+
for (const name of ["$createdAt", "$updatedAt", "$creationFlags"]) {
|
|
138
139
|
expect(() => eq(name, 1)).toThrow(/carries no index, so it cannot be filtered on/)
|
|
140
|
+
// A selection names the entity field, which has no `$`.
|
|
141
|
+
expect(() => eq(name, 1)).toThrow(`Select it as \`${name.slice(1)}\``)
|
|
139
142
|
}
|
|
140
143
|
})
|
|
141
144
|
|
|
@@ -154,6 +157,48 @@ describe("system attributes", () => {
|
|
|
154
157
|
})
|
|
155
158
|
})
|
|
156
159
|
|
|
160
|
+
describe("between", () => {
|
|
161
|
+
it("renders an inclusive range with both bounds tagged", () => {
|
|
162
|
+
expect(String(between("score", dec("3.5"), dec("5")))).toBe("score BETWEEN dec(3.5) AND dec(5)")
|
|
163
|
+
expect(String(between("level", 1, 5))).toBe("level BETWEEN i32(1) AND i32(5)")
|
|
164
|
+
expect(String(between("name", "a", "m"))).toBe("name BETWEEN str('a') AND str('m')")
|
|
165
|
+
expect(String(between("$expiresAt", u64(100n), u64(200n)))).toBe(
|
|
166
|
+
"$expiresAt BETWEEN u64(100) AND u64(200)",
|
|
167
|
+
)
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it("is a leaf: its own AND needs no parentheses", () => {
|
|
171
|
+
expect(String(and(between("a", 1, 5), eq("b", 2)))).toBe(
|
|
172
|
+
"a BETWEEN i32(1) AND i32(5) AND b = i32(2)",
|
|
173
|
+
)
|
|
174
|
+
expect(String(or(between("a", 1, 5), eq("b", 2)))).toBe(
|
|
175
|
+
"a BETWEEN i32(1) AND i32(5) OR b = i32(2)",
|
|
176
|
+
)
|
|
177
|
+
expect(String(not(between("a", 1, 5)))).toBe("NOT a BETWEEN i32(1) AND i32(5)")
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it("rejects bounds of different types", () => {
|
|
181
|
+
// @ts-expect-error - both bounds must have one type
|
|
182
|
+
expect(() => between("score", 1, dec("5"))).toThrow(InvalidPredicateError)
|
|
183
|
+
expect(() => between("score", 1, dec("5") as never)).toThrow(/a i32 and a dec bound/)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it("applies the checks every comparison does", () => {
|
|
187
|
+
expect(() => between("$owner", ACCOUNT, ACCOUNT)).toThrow(/is a addr, but the value is a str/)
|
|
188
|
+
expect(() => between("blob", bytes("0x01") as never, bytes("0x02") as never)).toThrow(
|
|
189
|
+
/bytes are stored but never indexed/,
|
|
190
|
+
)
|
|
191
|
+
expect(() => between("not", 1, 2)).toThrow(InvalidAttributeNameError)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it("is checked against a schema like a comparison", () => {
|
|
195
|
+
const Posts = defineSchema({ score: dec().indexed(), title: str() })
|
|
196
|
+
expect(() => checkAgainstSchema(between("score", dec("1"), dec("2")), Posts)).not.toThrow()
|
|
197
|
+
expect(() => checkAgainstSchema(between("score", 1, 2), Posts)).toThrow(/asserts a i32/)
|
|
198
|
+
expect(() => checkAgainstSchema(between("title", "a", "b"), Posts)).toThrow(/not indexed/)
|
|
199
|
+
})
|
|
200
|
+
})
|
|
201
|
+
|
|
157
202
|
describe("startsWith", () => {
|
|
158
203
|
it("takes a bare string or a str value", () => {
|
|
159
204
|
expect(String(startsWith("desc", "ab"))).toBe("desc STARTSWITH str('ab')")
|
|
@@ -177,8 +222,8 @@ describe("exists and hasType", () => {
|
|
|
177
222
|
})
|
|
178
223
|
|
|
179
224
|
it("rejects a type that cannot be set on an attribute", () => {
|
|
180
|
-
// @ts-expect-error - bytes
|
|
181
|
-
expect(() => hasType("blob", "bytes")).toThrow(/is not
|
|
225
|
+
// @ts-expect-error - bytes is never indexed, so TYPEOF can never see it
|
|
226
|
+
expect(() => hasType("blob", "bytes")).toThrow(/is not an indexable attribute type/)
|
|
182
227
|
// @ts-expect-error - not a type at all
|
|
183
228
|
expect(() => hasType("age", "int")).toThrow(InvalidPredicateError)
|
|
184
229
|
})
|
|
@@ -188,7 +233,7 @@ describe("exists and hasType", () => {
|
|
|
188
233
|
// `TYPEOF(a) = toString` — a query the node can only answer with a parse error.
|
|
189
234
|
for (const inherited of ["constructor", "toString", "valueOf", "hasOwnProperty"]) {
|
|
190
235
|
// @ts-expect-error - not a type tag
|
|
191
|
-
expect(() => hasType("age", inherited)).toThrow(/is not
|
|
236
|
+
expect(() => hasType("age", inherited)).toThrow(/is not an indexable attribute type/)
|
|
192
237
|
}
|
|
193
238
|
})
|
|
194
239
|
|
|
@@ -284,3 +329,66 @@ describe("the expression tree", () => {
|
|
|
284
329
|
expect(`${expression}`).toBe(render(expression))
|
|
285
330
|
})
|
|
286
331
|
})
|
|
332
|
+
|
|
333
|
+
describe("bytes", () => {
|
|
334
|
+
it("cannot be filtered on, bare or tagged — it is never indexed", () => {
|
|
335
|
+
expect(() => eq("body", new Uint8Array([1]) as never)).toThrow(
|
|
336
|
+
/bytes are stored but never indexed/,
|
|
337
|
+
)
|
|
338
|
+
expect(() => ne("body", bytes("0x01") as never)).toThrow(InvalidPredicateError)
|
|
339
|
+
})
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
describe("checkAgainstSchema", () => {
|
|
343
|
+
const Posts = defineSchema({
|
|
344
|
+
author: addr().indexed(),
|
|
345
|
+
category: str().indexed(),
|
|
346
|
+
score: dec().indexed(),
|
|
347
|
+
title: str(),
|
|
348
|
+
body: bytes(),
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
it("accepts indexed columns compared against their own type, and system attributes", () => {
|
|
352
|
+
expect(() =>
|
|
353
|
+
checkAgainstSchema(
|
|
354
|
+
and(
|
|
355
|
+
eq("category", "docs"),
|
|
356
|
+
not(gt("score", dec("4"))),
|
|
357
|
+
or(exists("author"), startsWith("category", "d")),
|
|
358
|
+
hasType("score", "dec"),
|
|
359
|
+
eq("$owner", addr(ACCOUNT)),
|
|
360
|
+
),
|
|
361
|
+
Posts,
|
|
362
|
+
),
|
|
363
|
+
).not.toThrow()
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
it("rejects an unindexed column, saying how to index it", () => {
|
|
367
|
+
expect(() => checkAgainstSchema(eq("title", "x"), Posts)).toThrow(
|
|
368
|
+
/"title" is not indexed.*str\(\)\.indexed\(\)/,
|
|
369
|
+
)
|
|
370
|
+
// Wherever it hides in the tree.
|
|
371
|
+
expect(() =>
|
|
372
|
+
checkAgainstSchema(and(eq("category", "docs"), not(exists("title"))), Posts),
|
|
373
|
+
).toThrow(InvalidPredicateError)
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
it("rejects a bytes column without suggesting it be indexed, which bytes never can be", () => {
|
|
377
|
+
const check = () => checkAgainstSchema(exists("body"), Posts)
|
|
378
|
+
expect(check).toThrow(InvalidPredicateError)
|
|
379
|
+
expect(check).toThrow(/"body" is a bytes column, and bytes are stored but never indexed/)
|
|
380
|
+
expect(check).toThrow(/Index a str, bytes32 or key derived from it instead/)
|
|
381
|
+
expect(check).not.toThrow(/\.indexed\(\)/)
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
it("rejects a name that is not a column", () => {
|
|
385
|
+
expect(() => checkAgainstSchema(eq("nope", 1), Posts)).toThrow(/"nope" is not a column/)
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
it("rejects a comparison against a value of another type, which could never match", () => {
|
|
389
|
+
expect(() => checkAgainstSchema(eq("score", 5), Posts)).toThrow(
|
|
390
|
+
/"score" is a dec column, but the predicate asserts a i32/,
|
|
391
|
+
)
|
|
392
|
+
expect(() => checkAgainstSchema(hasType("score", "i32"), Posts)).toThrow(InvalidPredicateError)
|
|
393
|
+
})
|
|
394
|
+
})
|