@ikeboy003/cloudrest-client 0.0.1 → 0.1.0
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/dist/filter.d.ts +1 -0
- package/dist/filter.d.ts.map +1 -1
- package/dist/filter.js +9 -2
- package/dist/filter.js.map +1 -1
- package/dist/index.d.ts +16 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/mutation.d.ts +10 -0
- package/dist/mutation.d.ts.map +1 -1
- package/dist/mutation.js +38 -6
- package/dist/mutation.js.map +1 -1
- package/dist/query.d.ts +15 -0
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +33 -4
- package/dist/query.js.map +1 -1
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +2 -1
- package/dist/rpc.js.map +1 -1
- package/dist/serialize.d.ts +1 -0
- package/dist/serialize.d.ts.map +1 -1
- package/dist/serialize.js +6 -0
- package/dist/serialize.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -2
- package/src/filter.ts +9 -2
- package/src/index.ts +12 -2
- package/src/mutation.ts +44 -6
- package/src/query.ts +37 -4
- package/src/rpc.ts +2 -1
- package/src/serialize.ts +7 -0
- package/src/types.ts +3 -1
package/dist/filter.d.ts
CHANGED
|
@@ -14,4 +14,5 @@ export declare function fIlike(column: string, pattern: string): FilterEntry;
|
|
|
14
14
|
export declare function fIn(column: string, values: readonly unknown[]): FilterEntry;
|
|
15
15
|
export declare function fIs(column: string, value: IsValue): FilterEntry;
|
|
16
16
|
export declare function fNot(entry: FilterEntry): FilterEntry;
|
|
17
|
+
export declare function fOr(entries: readonly FilterEntry[]): FilterEntry;
|
|
17
18
|
//# sourceMappingURL=filter.d.ts.map
|
package/dist/filter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAE/D;AACD,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAEhE;AACD,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAE/D;AACD,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAEhE;AACD,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAE/D;AACD,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAEhE;AACD,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,CAElE;AACD,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,CAEnE;AACD,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,WAAW,CAE3E;AAED,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAE/D;AAGD,wBAAgB,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAEpD"}
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAE/D;AACD,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAEhE;AACD,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAE/D;AACD,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAEhE;AACD,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAE/D;AACD,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAEhE;AACD,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,CAElE;AACD,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,CAEnE;AACD,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,WAAW,CAE3E;AAED,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAE/D;AAGD,wBAAgB,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAEpD;AAID,wBAAgB,GAAG,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,CAGhE"}
|
package/dist/filter.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Filter ops —
|
|
2
|
-
//
|
|
1
|
+
// Filter ops — equality, comparison, set membership, null checks, pattern match,
|
|
2
|
+
// plus the `or` composite. (`and`, `fts`, `jsonpath` still to come.)
|
|
3
3
|
//
|
|
4
4
|
// Each filter contributes one entry to URLSearchParams as `column=op.value`.
|
|
5
5
|
import { serializeValue } from "./serialize.js";
|
|
@@ -39,4 +39,11 @@ export function fIs(column, value) {
|
|
|
39
39
|
export function fNot(entry) {
|
|
40
40
|
return { column: entry.column, expr: `not.${entry.expr}` };
|
|
41
41
|
}
|
|
42
|
+
// Composite OR: `or=(title.ilike.*x*,author.ilike.*x*)`. Each child is a normal
|
|
43
|
+
// FilterEntry (`column` + `op.value`) re-spelled in the dotted inner grammar
|
|
44
|
+
// `column.op.value`. Compose children from the same f* helpers above.
|
|
45
|
+
export function fOr(entries) {
|
|
46
|
+
const inner = entries.map((e) => `${e.column}.${e.expr}`).join(",");
|
|
47
|
+
return { column: "or", expr: `(${inner})` };
|
|
48
|
+
}
|
|
42
49
|
//# sourceMappingURL=filter.js.map
|
package/dist/filter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,qEAAqE;AACrE,EAAE;AACF,6EAA6E;AAE7E,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAShD,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,KAAc;IAChD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;AACzD,CAAC;AACD,MAAM,UAAU,IAAI,CAAC,MAAc,EAAE,KAAc;IACjD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;AAC1D,CAAC;AACD,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,KAAc;IAChD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;AACzD,CAAC;AACD,MAAM,UAAU,IAAI,CAAC,MAAc,EAAE,KAAc;IACjD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;AAC1D,CAAC;AACD,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,KAAc;IAChD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;AACzD,CAAC;AACD,MAAM,UAAU,IAAI,CAAC,MAAc,EAAE,KAAc;IACjD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;AAC1D,CAAC;AACD,MAAM,UAAU,KAAK,CAAC,MAAc,EAAE,OAAe;IACnD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,cAAc,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;AAC7D,CAAC;AACD,MAAM,UAAU,MAAM,CAAC,MAAc,EAAE,OAAe;IACpD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,cAAc,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;AAC9D,CAAC;AACD,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,MAA0B;IAC5D,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;AAC1D,CAAC;AACD,iFAAiF;AACjF,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,KAAc;IAChD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,EAAE,EAAE,CAAC;AACzC,CAAC;AACD,2EAA2E;AAC3E,gDAAgD;AAChD,MAAM,UAAU,IAAI,CAAC,KAAkB;IACrC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;AAC7D,CAAC;AACD,gFAAgF;AAChF,6EAA6E;AAC7E,sEAAsE;AACtE,MAAM,UAAU,GAAG,CAAC,OAA+B;IACjD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,KAAK,GAAG,EAAE,CAAC;AAC9C,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,20 @@ export { QueryBuilder } from "./query.js";
|
|
|
4
4
|
export { InsertBuilder, UpdateBuilder, DeleteBuilder } from "./mutation.js";
|
|
5
5
|
export { RpcCaller } from "./rpc.js";
|
|
6
6
|
export type { AnyPaths, ClientOptions, RowOf, TableName, TokenGetter, } from "./types.js";
|
|
7
|
-
export type { OrderOptions } from "./query.js";
|
|
8
|
-
export type { IsValue } from "./filter.js";
|
|
7
|
+
export type { OrderOptions, SingleQuery, PagedQuery } from "./query.js";
|
|
8
|
+
export type { IsValue, FilterEntry } from "./filter.js";
|
|
9
|
+
import { fEq, fNeq, fGt, fGte, fLt, fLte, fLike, fIlike, fIn, fIs, fNot } from "./filter.js";
|
|
10
|
+
export declare const cond: {
|
|
11
|
+
readonly eq: typeof fEq;
|
|
12
|
+
readonly neq: typeof fNeq;
|
|
13
|
+
readonly gt: typeof fGt;
|
|
14
|
+
readonly gte: typeof fGte;
|
|
15
|
+
readonly lt: typeof fLt;
|
|
16
|
+
readonly lte: typeof fLte;
|
|
17
|
+
readonly like: typeof fLike;
|
|
18
|
+
readonly ilike: typeof fIlike;
|
|
19
|
+
readonly in: typeof fIn;
|
|
20
|
+
readonly is: typeof fIs;
|
|
21
|
+
readonly not: typeof fNot;
|
|
22
|
+
};
|
|
9
23
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,YAAY,EACV,QAAQ,EACR,aAAa,EACb,KAAK,EACL,SAAS,EACT,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,YAAY,EACV,QAAQ,EACR,aAAa,EACb,KAAK,EACL,SAAS,EACT,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAIxD,OAAO,EACL,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAC/D,MAAM,aAAa,CAAC;AACrB,eAAO,MAAM,IAAI;;;;;;;;;;;;CAGP,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,4 +3,11 @@ export { CloudRestError } from "./errors.js";
|
|
|
3
3
|
export { QueryBuilder } from "./query.js";
|
|
4
4
|
export { InsertBuilder, UpdateBuilder, DeleteBuilder } from "./mutation.js";
|
|
5
5
|
export { RpcCaller } from "./rpc.js";
|
|
6
|
+
// Bare condition builders for composing `.or(...)`. Each returns a FilterEntry:
|
|
7
|
+
// db.from("catalog_public").or(cond.ilike("title","*x*"), cond.ilike("author","*x*"))
|
|
8
|
+
import { fEq, fNeq, fGt, fGte, fLt, fLte, fLike, fIlike, fIn, fIs, fNot, } from "./filter.js";
|
|
9
|
+
export const cond = {
|
|
10
|
+
eq: fEq, neq: fNeq, gt: fGt, gte: fGte, lt: fLt, lte: fLte,
|
|
11
|
+
like: fLike, ilike: fIlike, in: fIn, is: fIs, not: fNot,
|
|
12
|
+
};
|
|
6
13
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAWrC,gFAAgF;AAChF,wFAAwF;AACxF,OAAO,EACL,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,GAC/D,MAAM,aAAa,CAAC;AACrB,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI;IAC1D,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI;CAC/C,CAAC"}
|
package/dist/mutation.d.ts
CHANGED
|
@@ -19,9 +19,19 @@ export declare class InsertBuilder<P extends AnyPaths, T extends TableName<P>, R
|
|
|
19
19
|
private readonly table;
|
|
20
20
|
private rows;
|
|
21
21
|
private returnRows;
|
|
22
|
+
private files;
|
|
22
23
|
constructor(ctx: ExecContext, table: T, rows: Partial<Row> | Partial<Row>[]);
|
|
23
24
|
/** Return inserted rows (adds Prefer: return=representation). */
|
|
24
25
|
returning(): this;
|
|
26
|
+
/**
|
|
27
|
+
* Attach a file for a media column. Switches the insert to a multipart
|
|
28
|
+
* write: the row's scalar columns ride as a `payload` JSON part and each
|
|
29
|
+
* file as a part named after its column. The server's media stage stores
|
|
30
|
+
* the bytes and puts a reference in the column. Single-row inserts only.
|
|
31
|
+
*/
|
|
32
|
+
attach(column: string, file: Blob): this;
|
|
33
|
+
private hasFiles;
|
|
34
|
+
private formBody;
|
|
25
35
|
then<R1 = Row[], R2 = never>(onfulfilled?: ((value: Row[]) => R1 | PromiseLike<R1>) | null, onrejected?: ((reason: unknown) => R2 | PromiseLike<R2>) | null): PromiseLike<R1 | R2>;
|
|
26
36
|
}
|
|
27
37
|
export declare class UpdateBuilder<P extends AnyPaths, T extends TableName<P>, Row = RowOf<P, T>> extends FilterableMutation<Row> implements PromiseLike<Row[]> {
|
package/dist/mutation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation.d.ts","sourceRoot":"","sources":["../src/mutation.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAEL,KAAK,WAAW,EAAE,KAAK,OAAO,EAC/B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"mutation.d.ts","sourceRoot":"","sources":["../src/mutation.ts"],"names":[],"mappings":"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"}
|
package/dist/mutation.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// - DELETE /table?filters → delete
|
|
5
5
|
// - Prefer: return=representation header makes the server return rows.
|
|
6
6
|
import { fEq, fNeq, fGt, fGte, fLt, fLte, fLike, fIlike, fIn, fIs, } from "./filter.js";
|
|
7
|
+
import { joinUrl } from "./serialize.js";
|
|
7
8
|
class FilterableMutation {
|
|
8
9
|
filters = [];
|
|
9
10
|
eq(col, v) { this.filters.push(fEq(col, v)); return this; }
|
|
@@ -18,9 +19,12 @@ class FilterableMutation {
|
|
|
18
19
|
is(col, v) { this.filters.push(fIs(col, v)); return this; }
|
|
19
20
|
}
|
|
20
21
|
async function send(ctx, method, url, body, returnRepresentation) {
|
|
22
|
+
// A FormData body is a multipart media write — let the runtime set the
|
|
23
|
+
// multipart Content-Type (with boundary); don't JSON-encode or force a type.
|
|
24
|
+
const isForm = typeof FormData !== "undefined" && body instanceof FormData;
|
|
21
25
|
const headers = {
|
|
22
26
|
Accept: "application/json",
|
|
23
|
-
"Content-Type": "application/json",
|
|
27
|
+
...(isForm ? {} : { "Content-Type": "application/json" }),
|
|
24
28
|
...ctx.headers,
|
|
25
29
|
};
|
|
26
30
|
if (returnRepresentation)
|
|
@@ -31,7 +35,9 @@ async function send(ctx, method, url, body, returnRepresentation) {
|
|
|
31
35
|
const res = await ctx.fetch(url, {
|
|
32
36
|
method,
|
|
33
37
|
headers,
|
|
34
|
-
...(body !== undefined
|
|
38
|
+
...(body !== undefined
|
|
39
|
+
? { body: isForm ? body : JSON.stringify(body) }
|
|
40
|
+
: {}),
|
|
35
41
|
});
|
|
36
42
|
if (!res.ok) {
|
|
37
43
|
const errBody = await res.json().catch(() => null);
|
|
@@ -47,6 +53,7 @@ export class InsertBuilder {
|
|
|
47
53
|
table;
|
|
48
54
|
rows;
|
|
49
55
|
returnRows = false;
|
|
56
|
+
files = {};
|
|
50
57
|
constructor(ctx, table, rows) {
|
|
51
58
|
this.ctx = ctx;
|
|
52
59
|
this.table = table;
|
|
@@ -57,9 +64,34 @@ export class InsertBuilder {
|
|
|
57
64
|
this.returnRows = true;
|
|
58
65
|
return this;
|
|
59
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Attach a file for a media column. Switches the insert to a multipart
|
|
69
|
+
* write: the row's scalar columns ride as a `payload` JSON part and each
|
|
70
|
+
* file as a part named after its column. The server's media stage stores
|
|
71
|
+
* the bytes and puts a reference in the column. Single-row inserts only.
|
|
72
|
+
*/
|
|
73
|
+
attach(column, file) {
|
|
74
|
+
this.files[column] = file;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
hasFiles() {
|
|
78
|
+
return Object.keys(this.files).length > 0;
|
|
79
|
+
}
|
|
80
|
+
formBody() {
|
|
81
|
+
if (this.rows.length !== 1) {
|
|
82
|
+
throw new Error("cloudrest: multipart insert (attach) supports a single row");
|
|
83
|
+
}
|
|
84
|
+
const fd = new FormData();
|
|
85
|
+
fd.append("payload", new Blob([JSON.stringify(this.rows[0])], { type: "application/json" }));
|
|
86
|
+
for (const [column, file] of Object.entries(this.files)) {
|
|
87
|
+
fd.append(column, file);
|
|
88
|
+
}
|
|
89
|
+
return fd;
|
|
90
|
+
}
|
|
60
91
|
then(onfulfilled, onrejected) {
|
|
61
|
-
const url = `${this.ctx.baseUrl
|
|
62
|
-
|
|
92
|
+
const url = `${joinUrl(this.ctx.baseUrl, String(this.table))}`;
|
|
93
|
+
const body = this.hasFiles() ? this.formBody() : this.rows;
|
|
94
|
+
return send(this.ctx, "POST", url, body, this.returnRows)
|
|
63
95
|
.then((v) => v)
|
|
64
96
|
.then(onfulfilled, onrejected);
|
|
65
97
|
}
|
|
@@ -84,7 +116,7 @@ export class UpdateBuilder extends FilterableMutation {
|
|
|
84
116
|
for (const f of this.filters)
|
|
85
117
|
params.append(f.column, f.expr);
|
|
86
118
|
const qs = params.toString();
|
|
87
|
-
return `${this.ctx.baseUrl
|
|
119
|
+
return `${joinUrl(this.ctx.baseUrl, String(this.table))}${qs ? `?${qs}` : ""}`;
|
|
88
120
|
}
|
|
89
121
|
then(onfulfilled, onrejected) {
|
|
90
122
|
return send(this.ctx, "PATCH", this.url(), this.patch, this.returnRows)
|
|
@@ -110,7 +142,7 @@ export class DeleteBuilder extends FilterableMutation {
|
|
|
110
142
|
for (const f of this.filters)
|
|
111
143
|
params.append(f.column, f.expr);
|
|
112
144
|
const qs = params.toString();
|
|
113
|
-
return `${this.ctx.baseUrl
|
|
145
|
+
return `${joinUrl(this.ctx.baseUrl, String(this.table))}${qs ? `?${qs}` : ""}`;
|
|
114
146
|
}
|
|
115
147
|
then(onfulfilled, onrejected) {
|
|
116
148
|
return send(this.ctx, "DELETE", this.url(), undefined, this.returnRows)
|
package/dist/mutation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation.js","sourceRoot":"","sources":["../src/mutation.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,6CAA6C;AAC7C,kCAAkC;AAClC,mCAAmC;AACnC,uEAAuE;AAGvE,OAAO,EACL,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAEzD,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"mutation.js","sourceRoot":"","sources":["../src/mutation.ts"],"names":[],"mappings":"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"}
|
package/dist/query.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export declare class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Ro
|
|
|
22
22
|
private rangeFrom?;
|
|
23
23
|
private rangeTo?;
|
|
24
24
|
private singleMode;
|
|
25
|
+
private wantCount;
|
|
25
26
|
constructor(ctx: ExecContext, table: T);
|
|
26
27
|
select(columns: string): this;
|
|
27
28
|
eq(col: string, v: unknown): this;
|
|
@@ -36,6 +37,7 @@ export declare class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Ro
|
|
|
36
37
|
is(col: string, v: IsValue): this;
|
|
37
38
|
notIs(col: string, v: IsValue): this;
|
|
38
39
|
not(entry: FilterEntry): this;
|
|
40
|
+
or(...entries: FilterEntry[]): this;
|
|
39
41
|
order(column: string, opts?: OrderOptions): this;
|
|
40
42
|
limit(n: number): this;
|
|
41
43
|
offset(n: number): this;
|
|
@@ -45,7 +47,15 @@ export declare class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Ro
|
|
|
45
47
|
* Throws if 0 or >1 rows match.
|
|
46
48
|
*/
|
|
47
49
|
single(): SingleQuery<Row>;
|
|
50
|
+
/**
|
|
51
|
+
* Page-aware terminal: returns the rows AND the exact total row count via
|
|
52
|
+
* `Prefer: count=exact` + the `Content-Range` response header. Use with
|
|
53
|
+
* `.range(from,to)` for paginated lists that need a total/page count.
|
|
54
|
+
*/
|
|
55
|
+
withCount(): PagedQuery<Row>;
|
|
48
56
|
private buildUrl;
|
|
57
|
+
private request;
|
|
58
|
+
private execPaged;
|
|
49
59
|
private exec;
|
|
50
60
|
then<TResult1 = Row[], TResult2 = never>(onfulfilled?: ((value: Row[]) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: CloudRestError) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
|
|
51
61
|
catch<TResult = never>(onrejected?: ((reason: CloudRestError) => TResult | PromiseLike<TResult>) | null): Promise<Row[] | TResult>;
|
|
@@ -53,4 +63,9 @@ export declare class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Ro
|
|
|
53
63
|
}
|
|
54
64
|
export interface SingleQuery<Row> extends PromiseLike<Row> {
|
|
55
65
|
}
|
|
66
|
+
export interface PagedQuery<Row> extends PromiseLike<{
|
|
67
|
+
rows: Row[];
|
|
68
|
+
count: number;
|
|
69
|
+
}> {
|
|
70
|
+
}
|
|
56
71
|
//# sourceMappingURL=query.d.ts.map
|
package/dist/query.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAEL,KAAK,WAAW,EAAE,KAAK,OAAO,EAC/B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
|
package/dist/query.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// awaitable directly:
|
|
4
4
|
//
|
|
5
5
|
// const rows = await db.from("x").select("a,b").eq("a", 1);
|
|
6
|
-
import { fEq, fNeq, fGt, fGte, fLt, fLte, fLike, fIlike, fIn, fIs, fNot, } from "./filter.js";
|
|
6
|
+
import { fEq, fNeq, fGt, fGte, fLt, fLte, fLike, fIlike, fIn, fIs, fNot, fOr, } from "./filter.js";
|
|
7
|
+
import { joinUrl } from "./serialize.js";
|
|
7
8
|
export class QueryBuilder {
|
|
8
9
|
ctx;
|
|
9
10
|
table;
|
|
@@ -15,6 +16,7 @@ export class QueryBuilder {
|
|
|
15
16
|
rangeFrom;
|
|
16
17
|
rangeTo;
|
|
17
18
|
singleMode = false;
|
|
19
|
+
wantCount = false;
|
|
18
20
|
constructor(ctx, table) {
|
|
19
21
|
this.ctx = ctx;
|
|
20
22
|
this.table = table;
|
|
@@ -39,6 +41,9 @@ export class QueryBuilder {
|
|
|
39
41
|
notIs(col, v) { this.filters.push(fNot(fIs(col, v))); return this; }
|
|
40
42
|
// Generic negation: pass the column + a non-negated filter helper output.
|
|
41
43
|
not(entry) { this.filters.push(fNot(entry)); return this; }
|
|
44
|
+
// Composite OR — pass bare condition helpers (e.g. `cond.ilike("title","*x*")`).
|
|
45
|
+
// Emits `or=(title.ilike.*x*,author.ilike.*x*)`.
|
|
46
|
+
or(...entries) { this.filters.push(fOr(entries)); return this; }
|
|
42
47
|
// ── ordering / paging ───────────────────────────────────────────────────
|
|
43
48
|
order(column, opts = {}) {
|
|
44
49
|
const { ascending = true, nullsFirst } = opts;
|
|
@@ -60,6 +65,15 @@ export class QueryBuilder {
|
|
|
60
65
|
this.singleMode = true;
|
|
61
66
|
return this;
|
|
62
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Page-aware terminal: returns the rows AND the exact total row count via
|
|
70
|
+
* `Prefer: count=exact` + the `Content-Range` response header. Use with
|
|
71
|
+
* `.range(from,to)` for paginated lists that need a total/page count.
|
|
72
|
+
*/
|
|
73
|
+
withCount() {
|
|
74
|
+
this.wantCount = true;
|
|
75
|
+
return { then: (f, r) => this.execPaged().then(f, r) };
|
|
76
|
+
}
|
|
63
77
|
// ── build + execute ─────────────────────────────────────────────────────
|
|
64
78
|
buildUrl() {
|
|
65
79
|
const params = new URLSearchParams();
|
|
@@ -74,9 +88,10 @@ export class QueryBuilder {
|
|
|
74
88
|
if (this.offsetN !== undefined)
|
|
75
89
|
params.set("offset", String(this.offsetN));
|
|
76
90
|
const qs = params.toString();
|
|
77
|
-
return `${this.ctx.baseUrl
|
|
91
|
+
return `${joinUrl(this.ctx.baseUrl, String(this.table))}${qs ? `?${qs}` : ""}`;
|
|
78
92
|
}
|
|
79
|
-
|
|
93
|
+
// Shared request path for every terminal (then / single / withCount).
|
|
94
|
+
async request() {
|
|
80
95
|
const url = this.buildUrl();
|
|
81
96
|
const headers = {
|
|
82
97
|
Accept: "application/json",
|
|
@@ -86,6 +101,8 @@ export class QueryBuilder {
|
|
|
86
101
|
headers["Range-Unit"] = "items";
|
|
87
102
|
headers["Range"] = `${this.rangeFrom}-${this.rangeTo}`;
|
|
88
103
|
}
|
|
104
|
+
if (this.wantCount)
|
|
105
|
+
headers["Prefer"] = "count=exact";
|
|
89
106
|
const token = await this.ctx.getToken?.();
|
|
90
107
|
if (token)
|
|
91
108
|
headers["Authorization"] = `Bearer ${token}`;
|
|
@@ -95,7 +112,19 @@ export class QueryBuilder {
|
|
|
95
112
|
const { CloudRestError } = await import("./errors.js");
|
|
96
113
|
throw new CloudRestError(res.status, res.statusText, body);
|
|
97
114
|
}
|
|
98
|
-
|
|
115
|
+
return { res, rows: (await res.json()) };
|
|
116
|
+
}
|
|
117
|
+
// Total count lives in the `Content-Range` trailer: `0-19/348` → 348.
|
|
118
|
+
// `*` (server declined to count) falls back to the rows already returned.
|
|
119
|
+
async execPaged() {
|
|
120
|
+
const { res, rows } = await this.request();
|
|
121
|
+
const cr = res.headers.get("content-range");
|
|
122
|
+
const m = cr ? /\/(\d+|\*)$/.exec(cr) : null;
|
|
123
|
+
const count = m && m[1] !== "*" ? Number(m[1]) : rows.length;
|
|
124
|
+
return { rows, count: Number.isFinite(count) ? count : rows.length };
|
|
125
|
+
}
|
|
126
|
+
async exec() {
|
|
127
|
+
const { rows } = await this.request();
|
|
99
128
|
if (this.singleMode) {
|
|
100
129
|
if (rows.length !== 1) {
|
|
101
130
|
const { CloudRestError } = await import("./errors.js");
|
package/dist/query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,6EAA6E;AAC7E,sBAAsB;AACtB,EAAE;AACF,8DAA8D;AAG9D,OAAO,EACL,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
|
package/dist/rpc.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,qBAAa,SAAS,CAAC,MAAM,GAAG,OAAO,CAAE,YAAW,WAAW,CAAC,MAAM,CAAC;IAEnE,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAFJ,GAAG,EAAE,WAAW,EAChB,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;YAGvC,IAAI;IA4BlB,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,EAAE,GAAG,KAAK,EAC1B,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,EAC9D,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,GAC9D,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC;CAGxB"}
|
package/dist/rpc.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// - POST /rpc/<fn> body = { argName: value, ... }
|
|
8
8
|
// - Response is the function return — scalar, row, or set-of rows.
|
|
9
9
|
import { CloudRestError } from "./errors.js";
|
|
10
|
+
import { joinUrl } from "./serialize.js";
|
|
10
11
|
export class RpcCaller {
|
|
11
12
|
ctx;
|
|
12
13
|
fn;
|
|
@@ -17,7 +18,7 @@ export class RpcCaller {
|
|
|
17
18
|
this.args = args;
|
|
18
19
|
}
|
|
19
20
|
async exec() {
|
|
20
|
-
const url =
|
|
21
|
+
const url = joinUrl(this.ctx.baseUrl, `rpc/${this.fn}`);
|
|
21
22
|
const headers = {
|
|
22
23
|
Accept: "application/json",
|
|
23
24
|
"Content-Type": "application/json",
|
package/dist/rpc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,0EAA0E;AAC1E,EAAE;AACF,sFAAsF;AACtF,EAAE;AACF,4BAA4B;AAC5B,qDAAqD;AACrD,qEAAqE;AAGrE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,0EAA0E;AAC1E,EAAE;AACF,sFAAsF;AACtF,EAAE;AACF,4BAA4B;AAC5B,qDAAqD;AACrD,qEAAqE;AAGrE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,MAAM,OAAO,SAAS;IAED;IACA;IACA;IAHnB,YACmB,GAAgB,EAChB,EAAU,EACV,OAAgC,EAAE;QAFlC,QAAG,GAAH,GAAG,CAAa;QAChB,OAAE,GAAF,EAAE,CAAQ;QACV,SAAI,GAAJ,IAAI,CAA8B;IAClD,CAAC;IAEI,KAAK,CAAC,IAAI;QAChB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACxD,MAAM,OAAO,GAA2B;YACtC,MAAM,EAAE,kBAAkB;YAC1B,cAAc,EAAE,kBAAkB;YAClC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO;SACpB,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;QAC1C,IAAI,KAAK;YAAE,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,KAAK,EAAE,CAAC;QAExD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE;YACpC,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;SAChC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,MAAM,IAAI,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC7D,CAAC;QAED,sEAAsE;QACtE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,SAAmB,CAAC;QACnD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,IAAI;YAAE,OAAO,SAAmB,CAAC;QACtC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAW,CAAC;IACpC,CAAC;IAED,IAAI,CACF,WAA8D,EAC9D,UAA+D;QAE/D,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,UAAmB,CAAC,CAAC;IAC5D,CAAC;CACF"}
|
package/dist/serialize.d.ts
CHANGED
package/dist/serialize.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAmBA,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAOjD"}
|
package/dist/serialize.js
CHANGED
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
const SCALAR_SPECIAL = /[,"]/;
|
|
13
13
|
// List items are inside `(a,b,c)`, so `(`, `)`, and `,` all need quoting.
|
|
14
14
|
const LIST_SPECIAL = /[(),."]/;
|
|
15
|
+
// Join the client baseUrl with a table/route, tolerant of trailing/leading
|
|
16
|
+
// slashes on either side, so `baseUrl="http://h:3005"` + `table="catalog_public"`
|
|
17
|
+
// (or "/catalog_public") both yield exactly one separating slash.
|
|
18
|
+
export function joinUrl(base, path) {
|
|
19
|
+
return `${base.replace(/\/+$/, "")}/${String(path).replace(/^\/+/, "")}`;
|
|
20
|
+
}
|
|
15
21
|
export function serializeValue(v) {
|
|
16
22
|
if (v === null || v === undefined)
|
|
17
23
|
return "null";
|
package/dist/serialize.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,+DAA+D;AAC/D,EAAE;AACF,SAAS;AACT,0DAA0D;AAC1D,uBAAuB;AACvB,4EAA4E;AAC5E,0EAA0E;AAE1E,uEAAuE;AACvE,sEAAsE;AACtE,+CAA+C;AAC/C,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,0EAA0E;AAC1E,MAAM,YAAY,GAAG,SAAS,CAAC;AAE/B,MAAM,UAAU,cAAc,CAAC,CAAU;IACvC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACjD,IAAI,CAAC,YAAY,IAAI;QAAE,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACvE,IAAI,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IACxD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACrE,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAU;IACnC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACjD,IAAI,CAAC,YAAY,IAAI;QAAE,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IACxD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACrE,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,cAAc,CAAC,CAAS,EAAE,OAAe;IAChD,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;AAC9D,CAAC"}
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,+DAA+D;AAC/D,EAAE;AACF,SAAS;AACT,0DAA0D;AAC1D,uBAAuB;AACvB,4EAA4E;AAC5E,0EAA0E;AAE1E,uEAAuE;AACvE,sEAAsE;AACtE,+CAA+C;AAC/C,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,0EAA0E;AAC1E,MAAM,YAAY,GAAG,SAAS,CAAC;AAE/B,2EAA2E;AAC3E,kFAAkF;AAClF,kEAAkE;AAClE,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,IAAY;IAChD,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,CAAU;IACvC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACjD,IAAI,CAAC,YAAY,IAAI;QAAE,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACvE,IAAI,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IACxD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACrE,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAU;IACnC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACjD,IAAI,CAAC,YAAY,IAAI;QAAE,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IACxD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACrE,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,cAAc,CAAC,CAAS,EAAE,OAAe;IAChD,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;AAC9D,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export type RowOf<P extends AnyPaths, T extends keyof P> = P[T] extends {
|
|
|
9
9
|
};
|
|
10
10
|
};
|
|
11
11
|
};
|
|
12
|
-
} ? Body extends ReadonlyArray<infer Item> ? Item : Body :
|
|
12
|
+
} ? Body extends ReadonlyArray<infer Item> ? Item : Body : Record<string, unknown>;
|
|
13
13
|
export type TableName<P extends AnyPaths> = Extract<keyof P, string>;
|
|
14
14
|
export type TokenGetter = () => string | null | Promise<string | null>;
|
|
15
15
|
export interface ClientOptions {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAK3C,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,MAAM,CAAC,IACrD,CAAC,CAAC,CAAC,CAAC,SAAS;IAAE,GAAG,EAAE;QAAE,SAAS,EAAE;YAAE,GAAG,EAAE;gBAAE,OAAO,EAAE;oBAAE,kBAAkB,EAAE,MAAM,IAAI,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,GACzF,IAAI,SAAS,aAAa,CAAC,MAAM,IAAI,CAAC,GACpC,IAAI,GACJ,IAAI,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAK3C,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,MAAM,CAAC,IACrD,CAAC,CAAC,CAAC,CAAC,SAAS;IAAE,GAAG,EAAE;QAAE,SAAS,EAAE;YAAE,GAAG,EAAE;gBAAE,OAAO,EAAE;oBAAE,kBAAkB,EAAE,MAAM,IAAI,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,GACzF,IAAI,SAAS,aAAa,CAAC,MAAM,IAAI,CAAC,GACpC,IAAI,GACJ,IAAI,GAGN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAG9B,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AAGrE,MAAM,MAAM,WAAW,GAAG,MAAM,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAEvE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ikeboy003/cloudrest-client",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Typed query builder for cloudrest. PostgREST-grammar compatible.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
-
"files": [
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
15
19
|
"scripts": {
|
|
16
20
|
"build": "tsc -p tsconfig.json",
|
|
17
21
|
"dev": "tsc -p tsconfig.json --watch"
|
package/src/filter.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Filter ops —
|
|
2
|
-
//
|
|
1
|
+
// Filter ops — equality, comparison, set membership, null checks, pattern match,
|
|
2
|
+
// plus the `or` composite. (`and`, `fts`, `jsonpath` still to come.)
|
|
3
3
|
//
|
|
4
4
|
// Each filter contributes one entry to URLSearchParams as `column=op.value`.
|
|
5
5
|
|
|
@@ -48,3 +48,10 @@ export function fIs(column: string, value: IsValue): FilterEntry {
|
|
|
48
48
|
export function fNot(entry: FilterEntry): FilterEntry {
|
|
49
49
|
return { column: entry.column, expr: `not.${entry.expr}` };
|
|
50
50
|
}
|
|
51
|
+
// Composite OR: `or=(title.ilike.*x*,author.ilike.*x*)`. Each child is a normal
|
|
52
|
+
// FilterEntry (`column` + `op.value`) re-spelled in the dotted inner grammar
|
|
53
|
+
// `column.op.value`. Compose children from the same f* helpers above.
|
|
54
|
+
export function fOr(entries: readonly FilterEntry[]): FilterEntry {
|
|
55
|
+
const inner = entries.map((e) => `${e.column}.${e.expr}`).join(",");
|
|
56
|
+
return { column: "or", expr: `(${inner})` };
|
|
57
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -10,5 +10,15 @@ export type {
|
|
|
10
10
|
TableName,
|
|
11
11
|
TokenGetter,
|
|
12
12
|
} from "./types.js";
|
|
13
|
-
export type { OrderOptions } from "./query.js";
|
|
14
|
-
export type { IsValue } from "./filter.js";
|
|
13
|
+
export type { OrderOptions, SingleQuery, PagedQuery } from "./query.js";
|
|
14
|
+
export type { IsValue, FilterEntry } from "./filter.js";
|
|
15
|
+
|
|
16
|
+
// Bare condition builders for composing `.or(...)`. Each returns a FilterEntry:
|
|
17
|
+
// db.from("catalog_public").or(cond.ilike("title","*x*"), cond.ilike("author","*x*"))
|
|
18
|
+
import {
|
|
19
|
+
fEq, fNeq, fGt, fGte, fLt, fLte, fLike, fIlike, fIn, fIs, fNot,
|
|
20
|
+
} from "./filter.js";
|
|
21
|
+
export const cond = {
|
|
22
|
+
eq: fEq, neq: fNeq, gt: fGt, gte: fGte, lt: fLt, lte: fLte,
|
|
23
|
+
like: fLike, ilike: fIlike, in: fIn, is: fIs, not: fNot,
|
|
24
|
+
} as const;
|
package/src/mutation.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type FilterEntry, type IsValue,
|
|
11
11
|
} from "./filter.js";
|
|
12
12
|
import type { ExecContext } from "./query.js";
|
|
13
|
+
import { joinUrl } from "./serialize.js";
|
|
13
14
|
|
|
14
15
|
class FilterableMutation<Row> {
|
|
15
16
|
protected filters: FilterEntry[] = [];
|
|
@@ -32,9 +33,12 @@ async function send(
|
|
|
32
33
|
body: unknown | undefined,
|
|
33
34
|
returnRepresentation: boolean,
|
|
34
35
|
): Promise<unknown> {
|
|
36
|
+
// A FormData body is a multipart media write — let the runtime set the
|
|
37
|
+
// multipart Content-Type (with boundary); don't JSON-encode or force a type.
|
|
38
|
+
const isForm = typeof FormData !== "undefined" && body instanceof FormData;
|
|
35
39
|
const headers: Record<string, string> = {
|
|
36
40
|
Accept: "application/json",
|
|
37
|
-
"Content-Type": "application/json",
|
|
41
|
+
...(isForm ? {} : { "Content-Type": "application/json" }),
|
|
38
42
|
...ctx.headers,
|
|
39
43
|
};
|
|
40
44
|
if (returnRepresentation) headers["Prefer"] = "return=representation";
|
|
@@ -44,7 +48,9 @@ async function send(
|
|
|
44
48
|
const res = await ctx.fetch(url, {
|
|
45
49
|
method,
|
|
46
50
|
headers,
|
|
47
|
-
...(body !== undefined
|
|
51
|
+
...(body !== undefined
|
|
52
|
+
? { body: isForm ? (body as FormData) : JSON.stringify(body) }
|
|
53
|
+
: {}),
|
|
48
54
|
});
|
|
49
55
|
if (!res.ok) {
|
|
50
56
|
const errBody = await res.json().catch(() => null);
|
|
@@ -60,6 +66,7 @@ export class InsertBuilder<P extends AnyPaths, T extends TableName<P>, Row = Row
|
|
|
60
66
|
{
|
|
61
67
|
private rows: Partial<Row>[];
|
|
62
68
|
private returnRows = false;
|
|
69
|
+
private files: Record<string, Blob> = {};
|
|
63
70
|
|
|
64
71
|
constructor(
|
|
65
72
|
private readonly ctx: ExecContext,
|
|
@@ -75,12 +82,43 @@ export class InsertBuilder<P extends AnyPaths, T extends TableName<P>, Row = Row
|
|
|
75
82
|
return this;
|
|
76
83
|
}
|
|
77
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Attach a file for a media column. Switches the insert to a multipart
|
|
87
|
+
* write: the row's scalar columns ride as a `payload` JSON part and each
|
|
88
|
+
* file as a part named after its column. The server's media stage stores
|
|
89
|
+
* the bytes and puts a reference in the column. Single-row inserts only.
|
|
90
|
+
*/
|
|
91
|
+
attach(column: string, file: Blob): this {
|
|
92
|
+
this.files[column] = file;
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private hasFiles(): boolean {
|
|
97
|
+
return Object.keys(this.files).length > 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private formBody(): FormData {
|
|
101
|
+
if (this.rows.length !== 1) {
|
|
102
|
+
throw new Error("cloudrest: multipart insert (attach) supports a single row");
|
|
103
|
+
}
|
|
104
|
+
const fd = new FormData();
|
|
105
|
+
fd.append(
|
|
106
|
+
"payload",
|
|
107
|
+
new Blob([JSON.stringify(this.rows[0])], { type: "application/json" }),
|
|
108
|
+
);
|
|
109
|
+
for (const [column, file] of Object.entries(this.files)) {
|
|
110
|
+
fd.append(column, file);
|
|
111
|
+
}
|
|
112
|
+
return fd;
|
|
113
|
+
}
|
|
114
|
+
|
|
78
115
|
then<R1 = Row[], R2 = never>(
|
|
79
116
|
onfulfilled?: ((value: Row[]) => R1 | PromiseLike<R1>) | null,
|
|
80
117
|
onrejected?: ((reason: unknown) => R2 | PromiseLike<R2>) | null,
|
|
81
118
|
): PromiseLike<R1 | R2> {
|
|
82
|
-
const url = `${this.ctx.baseUrl
|
|
83
|
-
|
|
119
|
+
const url = `${joinUrl(this.ctx.baseUrl, String(this.table))}`;
|
|
120
|
+
const body = this.hasFiles() ? this.formBody() : this.rows;
|
|
121
|
+
return send(this.ctx, "POST", url, body, this.returnRows)
|
|
84
122
|
.then((v) => v as Row[])
|
|
85
123
|
.then(onfulfilled, onrejected as never);
|
|
86
124
|
}
|
|
@@ -109,7 +147,7 @@ export class UpdateBuilder<P extends AnyPaths, T extends TableName<P>, Row = Row
|
|
|
109
147
|
const params = new URLSearchParams();
|
|
110
148
|
for (const f of this.filters) params.append(f.column, f.expr);
|
|
111
149
|
const qs = params.toString();
|
|
112
|
-
return `${this.ctx.baseUrl
|
|
150
|
+
return `${joinUrl(this.ctx.baseUrl, String(this.table))}${qs ? `?${qs}` : ""}`;
|
|
113
151
|
}
|
|
114
152
|
|
|
115
153
|
then<R1 = Row[], R2 = never>(
|
|
@@ -144,7 +182,7 @@ export class DeleteBuilder<P extends AnyPaths, T extends TableName<P>, Row = Row
|
|
|
144
182
|
const params = new URLSearchParams();
|
|
145
183
|
for (const f of this.filters) params.append(f.column, f.expr);
|
|
146
184
|
const qs = params.toString();
|
|
147
|
-
return `${this.ctx.baseUrl
|
|
185
|
+
return `${joinUrl(this.ctx.baseUrl, String(this.table))}${qs ? `?${qs}` : ""}`;
|
|
148
186
|
}
|
|
149
187
|
|
|
150
188
|
then<R1 = Row[], R2 = never>(
|
package/src/query.ts
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
import type { AnyPaths, RowOf, TableName } from "./types.js";
|
|
8
8
|
import {
|
|
9
|
-
fEq, fNeq, fGt, fGte, fLt, fLte, fLike, fIlike, fIn, fIs, fNot,
|
|
9
|
+
fEq, fNeq, fGt, fGte, fLt, fLte, fLike, fIlike, fIn, fIs, fNot, fOr,
|
|
10
10
|
type FilterEntry, type IsValue,
|
|
11
11
|
} from "./filter.js";
|
|
12
12
|
import type { CloudRestError } from "./errors.js";
|
|
13
|
+
import { joinUrl } from "./serialize.js";
|
|
13
14
|
|
|
14
15
|
export interface ExecContext {
|
|
15
16
|
baseUrl: string;
|
|
@@ -34,6 +35,7 @@ export class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Row = RowO
|
|
|
34
35
|
private rangeFrom?: number;
|
|
35
36
|
private rangeTo?: number;
|
|
36
37
|
private singleMode = false;
|
|
38
|
+
private wantCount = false;
|
|
37
39
|
|
|
38
40
|
constructor(
|
|
39
41
|
private readonly ctx: ExecContext,
|
|
@@ -61,6 +63,9 @@ export class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Row = RowO
|
|
|
61
63
|
notIs(col: string, v: IsValue): this { this.filters.push(fNot(fIs(col, v))); return this; }
|
|
62
64
|
// Generic negation: pass the column + a non-negated filter helper output.
|
|
63
65
|
not(entry: FilterEntry): this { this.filters.push(fNot(entry)); return this; }
|
|
66
|
+
// Composite OR — pass bare condition helpers (e.g. `cond.ilike("title","*x*")`).
|
|
67
|
+
// Emits `or=(title.ilike.*x*,author.ilike.*x*)`.
|
|
68
|
+
or(...entries: FilterEntry[]): this { this.filters.push(fOr(entries)); return this; }
|
|
64
69
|
|
|
65
70
|
// ── ordering / paging ───────────────────────────────────────────────────
|
|
66
71
|
order(column: string, opts: OrderOptions = {}): this {
|
|
@@ -84,6 +89,16 @@ export class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Row = RowO
|
|
|
84
89
|
return this as unknown as SingleQuery<Row>;
|
|
85
90
|
}
|
|
86
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Page-aware terminal: returns the rows AND the exact total row count via
|
|
94
|
+
* `Prefer: count=exact` + the `Content-Range` response header. Use with
|
|
95
|
+
* `.range(from,to)` for paginated lists that need a total/page count.
|
|
96
|
+
*/
|
|
97
|
+
withCount(): PagedQuery<Row> {
|
|
98
|
+
this.wantCount = true;
|
|
99
|
+
return { then: (f, r) => this.execPaged().then(f as never, r as never) };
|
|
100
|
+
}
|
|
101
|
+
|
|
87
102
|
// ── build + execute ─────────────────────────────────────────────────────
|
|
88
103
|
private buildUrl(): string {
|
|
89
104
|
const params = new URLSearchParams();
|
|
@@ -93,10 +108,11 @@ export class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Row = RowO
|
|
|
93
108
|
if (this.limitN !== undefined) params.set("limit", String(this.limitN));
|
|
94
109
|
if (this.offsetN !== undefined) params.set("offset", String(this.offsetN));
|
|
95
110
|
const qs = params.toString();
|
|
96
|
-
return `${this.ctx.baseUrl
|
|
111
|
+
return `${joinUrl(this.ctx.baseUrl, String(this.table))}${qs ? `?${qs}` : ""}`;
|
|
97
112
|
}
|
|
98
113
|
|
|
99
|
-
|
|
114
|
+
// Shared request path for every terminal (then / single / withCount).
|
|
115
|
+
private async request(): Promise<{ res: Response; rows: Row[] }> {
|
|
100
116
|
const url = this.buildUrl();
|
|
101
117
|
const headers: Record<string, string> = {
|
|
102
118
|
Accept: "application/json",
|
|
@@ -106,6 +122,7 @@ export class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Row = RowO
|
|
|
106
122
|
headers["Range-Unit"] = "items";
|
|
107
123
|
headers["Range"] = `${this.rangeFrom}-${this.rangeTo}`;
|
|
108
124
|
}
|
|
125
|
+
if (this.wantCount) headers["Prefer"] = "count=exact";
|
|
109
126
|
const token = await this.ctx.getToken?.();
|
|
110
127
|
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
111
128
|
|
|
@@ -115,7 +132,21 @@ export class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Row = RowO
|
|
|
115
132
|
const { CloudRestError } = await import("./errors.js");
|
|
116
133
|
throw new CloudRestError(res.status, res.statusText, body);
|
|
117
134
|
}
|
|
118
|
-
|
|
135
|
+
return { res, rows: (await res.json()) as Row[] };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Total count lives in the `Content-Range` trailer: `0-19/348` → 348.
|
|
139
|
+
// `*` (server declined to count) falls back to the rows already returned.
|
|
140
|
+
private async execPaged(): Promise<{ rows: Row[]; count: number }> {
|
|
141
|
+
const { res, rows } = await this.request();
|
|
142
|
+
const cr = res.headers.get("content-range");
|
|
143
|
+
const m = cr ? /\/(\d+|\*)$/.exec(cr) : null;
|
|
144
|
+
const count = m && m[1] !== "*" ? Number(m[1]) : rows.length;
|
|
145
|
+
return { rows, count: Number.isFinite(count) ? count : rows.length };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private async exec(): Promise<Row[]> {
|
|
149
|
+
const { rows } = await this.request();
|
|
119
150
|
if (this.singleMode) {
|
|
120
151
|
if (rows.length !== 1) {
|
|
121
152
|
const { CloudRestError } = await import("./errors.js");
|
|
@@ -150,3 +181,5 @@ export class QueryBuilder<P extends AnyPaths, T extends TableName<P>, Row = RowO
|
|
|
150
181
|
|
|
151
182
|
// Phantom type alias for `.single()` — narrows the awaited type from Row[] to Row.
|
|
152
183
|
export interface SingleQuery<Row> extends PromiseLike<Row> {}
|
|
184
|
+
// `.withCount()` awaits to rows + total count instead of a bare Row[].
|
|
185
|
+
export interface PagedQuery<Row> extends PromiseLike<{ rows: Row[]; count: number }> {}
|
package/src/rpc.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import type { ExecContext } from "./query.js";
|
|
11
11
|
import { CloudRestError } from "./errors.js";
|
|
12
|
+
import { joinUrl } from "./serialize.js";
|
|
12
13
|
|
|
13
14
|
export class RpcCaller<Result = unknown> implements PromiseLike<Result> {
|
|
14
15
|
constructor(
|
|
@@ -18,7 +19,7 @@ export class RpcCaller<Result = unknown> implements PromiseLike<Result> {
|
|
|
18
19
|
) {}
|
|
19
20
|
|
|
20
21
|
private async exec(): Promise<Result> {
|
|
21
|
-
const url =
|
|
22
|
+
const url = joinUrl(this.ctx.baseUrl, `rpc/${this.fn}`);
|
|
22
23
|
const headers: Record<string, string> = {
|
|
23
24
|
Accept: "application/json",
|
|
24
25
|
"Content-Type": "application/json",
|
package/src/serialize.ts
CHANGED
|
@@ -14,6 +14,13 @@ const SCALAR_SPECIAL = /[,"]/;
|
|
|
14
14
|
// List items are inside `(a,b,c)`, so `(`, `)`, and `,` all need quoting.
|
|
15
15
|
const LIST_SPECIAL = /[(),."]/;
|
|
16
16
|
|
|
17
|
+
// Join the client baseUrl with a table/route, tolerant of trailing/leading
|
|
18
|
+
// slashes on either side, so `baseUrl="http://h:3005"` + `table="catalog_public"`
|
|
19
|
+
// (or "/catalog_public") both yield exactly one separating slash.
|
|
20
|
+
export function joinUrl(base: string, path: string): string {
|
|
21
|
+
return `${base.replace(/\/+$/, "")}/${String(path).replace(/^\/+/, "")}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
17
24
|
export function serializeValue(v: unknown): string {
|
|
18
25
|
if (v === null || v === undefined) return "null";
|
|
19
26
|
if (v instanceof Date) return v.toISOString();
|
package/src/types.ts
CHANGED
|
@@ -15,7 +15,9 @@ export type RowOf<P extends AnyPaths, T extends keyof P> =
|
|
|
15
15
|
? Body extends ReadonlyArray<infer Item>
|
|
16
16
|
? Item
|
|
17
17
|
: Body
|
|
18
|
-
|
|
18
|
+
// Loosely-typed clients (e.g. `createClient<Record<string, unknown>>`) have no
|
|
19
|
+
// openapi shape per path; fall back to an open row so insert/update stay usable.
|
|
20
|
+
: Record<string, unknown>;
|
|
19
21
|
|
|
20
22
|
// Tables = path keys that look like top-level table routes ("/foo", not "/rpc/...").
|
|
21
23
|
export type TableName<P extends AnyPaths> = Extract<keyof P, string>;
|