@linabase/js 0.3.1 → 0.4.1
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/index.cjs +89 -10
- package/dist/index.d.cts +46 -4
- package/dist/index.d.ts +46 -4
- package/dist/index.js +89 -10
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -57,10 +57,11 @@ var DatabaseClient = class {
|
|
|
57
57
|
if (options?.count) this.preferHeaders.push(`count=${options.count}`);
|
|
58
58
|
return this;
|
|
59
59
|
}
|
|
60
|
-
insert(data) {
|
|
60
|
+
insert(data, options) {
|
|
61
61
|
this.method = "POST";
|
|
62
62
|
this.body = data;
|
|
63
63
|
this.preferHeaders.push("return=representation");
|
|
64
|
+
if (options?.defaultToNull === false) this.preferHeaders.push("missing=default");
|
|
64
65
|
return this;
|
|
65
66
|
}
|
|
66
67
|
/** Upsert: insert or update on conflict. Uses merge-duplicates by default. */
|
|
@@ -74,6 +75,7 @@ var DatabaseClient = class {
|
|
|
74
75
|
if (options?.onConflict) {
|
|
75
76
|
this.params.set("on_conflict", options.onConflict);
|
|
76
77
|
}
|
|
78
|
+
if (options?.defaultToNull === false) this.preferHeaders.push("missing=default");
|
|
77
79
|
return this;
|
|
78
80
|
}
|
|
79
81
|
update(data) {
|
|
@@ -82,8 +84,28 @@ var DatabaseClient = class {
|
|
|
82
84
|
this.preferHeaders.push("return=representation");
|
|
83
85
|
return this;
|
|
84
86
|
}
|
|
85
|
-
delete() {
|
|
87
|
+
delete(options) {
|
|
86
88
|
this.method = "DELETE";
|
|
89
|
+
if (options?.count) this.preferHeaders.push(`count=${options.count}`);
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
/** Specify return=minimal to skip returning data on mutations (better performance). */
|
|
93
|
+
returning(mode = "representation") {
|
|
94
|
+
this.preferHeaders = this.preferHeaders.filter((h) => !h.startsWith("return="));
|
|
95
|
+
this.preferHeaders.push(`return=${mode}`);
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
/** Get the query execution plan (EXPLAIN). */
|
|
99
|
+
explain(options) {
|
|
100
|
+
const parts = ["plan"];
|
|
101
|
+
if (options?.analyze) parts.push("analyze");
|
|
102
|
+
if (options?.verbose) parts.push("verbose");
|
|
103
|
+
if (options?.settings) parts.push("settings");
|
|
104
|
+
if (options?.buffers) parts.push("buffers");
|
|
105
|
+
if (options?.wal) parts.push("wal");
|
|
106
|
+
if (options?.format) parts.push(`format:${options.format}`);
|
|
107
|
+
this.preferHeaders = this.preferHeaders.filter((h) => !h.startsWith("plan"));
|
|
108
|
+
this.preferHeaders.push(parts.join("|"));
|
|
87
109
|
return this;
|
|
88
110
|
}
|
|
89
111
|
// ─── Comparison Filters ─────────────────────────────────
|
|
@@ -167,6 +189,32 @@ var DatabaseClient = class {
|
|
|
167
189
|
this.params.set(column, `isdistinct.${value}`);
|
|
168
190
|
return this;
|
|
169
191
|
}
|
|
192
|
+
// ─── Range Type Filters ──────────────────────────────────
|
|
193
|
+
/** Strictly left of: [a,b] << [c,d] */
|
|
194
|
+
rangeLt(column, range) {
|
|
195
|
+
this.params.set(column, `sl.${range}`);
|
|
196
|
+
return this;
|
|
197
|
+
}
|
|
198
|
+
/** Strictly right of: [a,b] >> [c,d] */
|
|
199
|
+
rangeGt(column, range) {
|
|
200
|
+
this.params.set(column, `sr.${range}`);
|
|
201
|
+
return this;
|
|
202
|
+
}
|
|
203
|
+
/** Does not extend to the left of */
|
|
204
|
+
rangeGte(column, range) {
|
|
205
|
+
this.params.set(column, `nxl.${range}`);
|
|
206
|
+
return this;
|
|
207
|
+
}
|
|
208
|
+
/** Does not extend to the right of */
|
|
209
|
+
rangeLte(column, range) {
|
|
210
|
+
this.params.set(column, `nxr.${range}`);
|
|
211
|
+
return this;
|
|
212
|
+
}
|
|
213
|
+
/** Range is adjacent to */
|
|
214
|
+
rangeAdjacent(column, range) {
|
|
215
|
+
this.params.set(column, `adj.${range}`);
|
|
216
|
+
return this;
|
|
217
|
+
}
|
|
170
218
|
// ─── Negation ───────────────────────────────────────────
|
|
171
219
|
/** Negate a filter: not.eq, not.in, not.is, etc. */
|
|
172
220
|
not(column, operator, value) {
|
|
@@ -175,29 +223,53 @@ var DatabaseClient = class {
|
|
|
175
223
|
}
|
|
176
224
|
// ─── Logical ────────────────────────────────────────────
|
|
177
225
|
/** OR filter: or("age.gt.20,name.eq.John") */
|
|
178
|
-
or(filters) {
|
|
179
|
-
|
|
226
|
+
or(filters, options) {
|
|
227
|
+
const key = options?.foreignTable ? `${options.foreignTable}.or` : "or";
|
|
228
|
+
this.params.set(key, `(${filters})`);
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
/** AND filter: and("age.gt.20,name.eq.John") */
|
|
232
|
+
and(filters, options) {
|
|
233
|
+
const key = options?.foreignTable ? `${options.foreignTable}.and` : "and";
|
|
234
|
+
this.params.set(key, `(${filters})`);
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
237
|
+
/** Generic filter: filter("column", "operator", "value") */
|
|
238
|
+
filter(column, operator, value) {
|
|
239
|
+
this.params.set(column, `${operator}.${value}`);
|
|
180
240
|
return this;
|
|
181
241
|
}
|
|
182
242
|
// ─── Full-Text Search ───────────────────────────────────
|
|
183
|
-
/** to_tsquery */
|
|
243
|
+
/** Full-text search (to_tsquery, plainto_tsquery, phraseto_tsquery, or websearch_to_tsquery) */
|
|
184
244
|
textSearch(column, query, options) {
|
|
185
245
|
const op = options?.type === "plain" ? "plfts" : options?.type === "phrase" ? "phfts" : options?.type === "websearch" ? "wfts" : "fts";
|
|
186
|
-
|
|
246
|
+
const config = options?.config ? `(${options.config})` : "";
|
|
247
|
+
this.params.set(column, `${op}${config}.${query}`);
|
|
187
248
|
return this;
|
|
188
249
|
}
|
|
189
250
|
// ─── Ordering & Pagination ──────────────────────────────
|
|
190
251
|
order(column, options) {
|
|
191
252
|
const dir = options?.ascending === false ? "desc" : "asc";
|
|
192
253
|
const nulls = options?.nullsFirst === true ? ".nullsfirst" : options?.nullsFirst === false ? ".nullslast" : "";
|
|
193
|
-
const
|
|
254
|
+
const key = options?.foreignTable ? `${options.foreignTable}.order` : "order";
|
|
255
|
+
const existing = this.params.get(key);
|
|
194
256
|
if (existing) {
|
|
195
|
-
this.params.set(
|
|
257
|
+
this.params.set(key, `${existing},${column}.${dir}${nulls}`);
|
|
196
258
|
} else {
|
|
197
|
-
this.params.set(
|
|
259
|
+
this.params.set(key, `${column}.${dir}${nulls}`);
|
|
198
260
|
}
|
|
199
261
|
return this;
|
|
200
262
|
}
|
|
263
|
+
/** Limit results on a foreign table */
|
|
264
|
+
limitForeignTable(count, foreignTable) {
|
|
265
|
+
this.params.set(`${foreignTable}.limit`, String(count));
|
|
266
|
+
return this;
|
|
267
|
+
}
|
|
268
|
+
/** Offset results on a foreign table */
|
|
269
|
+
offsetForeignTable(count, foreignTable) {
|
|
270
|
+
this.params.set(`${foreignTable}.offset`, String(count));
|
|
271
|
+
return this;
|
|
272
|
+
}
|
|
201
273
|
limit(count) {
|
|
202
274
|
this.params.set("limit", String(count));
|
|
203
275
|
return this;
|
|
@@ -622,6 +694,8 @@ var BucketClient = class {
|
|
|
622
694
|
var AuthClient = class {
|
|
623
695
|
request;
|
|
624
696
|
listeners = [];
|
|
697
|
+
/** Promise that resolves when session restore from storage is complete. */
|
|
698
|
+
_restorePromise = Promise.resolve();
|
|
625
699
|
currentSession = null;
|
|
626
700
|
/**
|
|
627
701
|
* Callback that the parent LinabaseClient can set to update the Authorization
|
|
@@ -992,6 +1066,11 @@ var AuthClient = class {
|
|
|
992
1066
|
// ─── Auth State Listener ───────────────────────────────────
|
|
993
1067
|
onAuthStateChange(callback) {
|
|
994
1068
|
this.listeners.push(callback);
|
|
1069
|
+
this._restorePromise.then(() => {
|
|
1070
|
+
if (this.listeners.includes(callback)) {
|
|
1071
|
+
callback("INITIAL_SESSION", this.currentSession);
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
995
1074
|
return {
|
|
996
1075
|
unsubscribe: () => {
|
|
997
1076
|
this.listeners = this.listeners.filter((l) => l !== callback);
|
|
@@ -1089,7 +1168,7 @@ function createClient(config) {
|
|
|
1089
1168
|
sessionStorage.removeItem(sessionKey);
|
|
1090
1169
|
}
|
|
1091
1170
|
});
|
|
1092
|
-
Promise.resolve(sessionStorage.getItem(sessionKey)).then((raw) => {
|
|
1171
|
+
authClient._restorePromise = Promise.resolve(sessionStorage.getItem(sessionKey)).then((raw) => {
|
|
1093
1172
|
if (raw) {
|
|
1094
1173
|
try {
|
|
1095
1174
|
authClient.setSession(JSON.parse(raw));
|
package/dist/index.d.cts
CHANGED
|
@@ -39,14 +39,30 @@ declare class DatabaseClient {
|
|
|
39
39
|
count?: "exact" | "estimated" | "planned";
|
|
40
40
|
head?: boolean;
|
|
41
41
|
}): this;
|
|
42
|
-
insert(data: Record<string, any> | Record<string, any>[]
|
|
42
|
+
insert(data: Record<string, any> | Record<string, any>[], options?: {
|
|
43
|
+
defaultToNull?: boolean;
|
|
44
|
+
}): this;
|
|
43
45
|
/** Upsert: insert or update on conflict. Uses merge-duplicates by default. */
|
|
44
46
|
upsert(data: Record<string, any> | Record<string, any>[], options?: {
|
|
45
47
|
ignoreDuplicates?: boolean;
|
|
46
48
|
onConflict?: string;
|
|
49
|
+
defaultToNull?: boolean;
|
|
47
50
|
}): this;
|
|
48
51
|
update(data: Record<string, any>): this;
|
|
49
|
-
delete(
|
|
52
|
+
delete(options?: {
|
|
53
|
+
count?: "exact" | "estimated" | "planned";
|
|
54
|
+
}): this;
|
|
55
|
+
/** Specify return=minimal to skip returning data on mutations (better performance). */
|
|
56
|
+
returning(mode?: "minimal" | "representation"): this;
|
|
57
|
+
/** Get the query execution plan (EXPLAIN). */
|
|
58
|
+
explain(options?: {
|
|
59
|
+
analyze?: boolean;
|
|
60
|
+
verbose?: boolean;
|
|
61
|
+
settings?: boolean;
|
|
62
|
+
buffers?: boolean;
|
|
63
|
+
wal?: boolean;
|
|
64
|
+
format?: "json" | "text";
|
|
65
|
+
}): this;
|
|
50
66
|
eq(column: string, value: any): this;
|
|
51
67
|
neq(column: string, value: any): this;
|
|
52
68
|
gt(column: string, value: any): this;
|
|
@@ -69,18 +85,42 @@ declare class DatabaseClient {
|
|
|
69
85
|
is(column: string, value: "null" | "true" | "false" | null | boolean): this;
|
|
70
86
|
/** IS DISTINCT FROM */
|
|
71
87
|
isDistinct(column: string, value: any): this;
|
|
88
|
+
/** Strictly left of: [a,b] << [c,d] */
|
|
89
|
+
rangeLt(column: string, range: string): this;
|
|
90
|
+
/** Strictly right of: [a,b] >> [c,d] */
|
|
91
|
+
rangeGt(column: string, range: string): this;
|
|
92
|
+
/** Does not extend to the left of */
|
|
93
|
+
rangeGte(column: string, range: string): this;
|
|
94
|
+
/** Does not extend to the right of */
|
|
95
|
+
rangeLte(column: string, range: string): this;
|
|
96
|
+
/** Range is adjacent to */
|
|
97
|
+
rangeAdjacent(column: string, range: string): this;
|
|
72
98
|
/** Negate a filter: not.eq, not.in, not.is, etc. */
|
|
73
99
|
not(column: string, operator: string, value: any): this;
|
|
74
100
|
/** OR filter: or("age.gt.20,name.eq.John") */
|
|
75
|
-
or(filters: string
|
|
76
|
-
|
|
101
|
+
or(filters: string, options?: {
|
|
102
|
+
foreignTable?: string;
|
|
103
|
+
}): this;
|
|
104
|
+
/** AND filter: and("age.gt.20,name.eq.John") */
|
|
105
|
+
and(filters: string, options?: {
|
|
106
|
+
foreignTable?: string;
|
|
107
|
+
}): this;
|
|
108
|
+
/** Generic filter: filter("column", "operator", "value") */
|
|
109
|
+
filter(column: string, operator: string, value: any): this;
|
|
110
|
+
/** Full-text search (to_tsquery, plainto_tsquery, phraseto_tsquery, or websearch_to_tsquery) */
|
|
77
111
|
textSearch(column: string, query: string, options?: {
|
|
78
112
|
type?: "plain" | "phrase" | "websearch";
|
|
113
|
+
config?: string;
|
|
79
114
|
}): this;
|
|
80
115
|
order(column: string, options?: {
|
|
81
116
|
ascending?: boolean;
|
|
82
117
|
nullsFirst?: boolean;
|
|
118
|
+
foreignTable?: string;
|
|
83
119
|
}): this;
|
|
120
|
+
/** Limit results on a foreign table */
|
|
121
|
+
limitForeignTable(count: number, foreignTable: string): this;
|
|
122
|
+
/** Offset results on a foreign table */
|
|
123
|
+
offsetForeignTable(count: number, foreignTable: string): this;
|
|
84
124
|
limit(count: number): this;
|
|
85
125
|
offset(count: number): this;
|
|
86
126
|
/** Request exact, estimated, or planned count via Prefer header */
|
|
@@ -226,6 +266,8 @@ interface AuthUser {
|
|
|
226
266
|
declare class AuthClient {
|
|
227
267
|
private request;
|
|
228
268
|
private listeners;
|
|
269
|
+
/** Promise that resolves when session restore from storage is complete. */
|
|
270
|
+
_restorePromise: Promise<void>;
|
|
229
271
|
private currentSession;
|
|
230
272
|
/**
|
|
231
273
|
* Callback that the parent LinabaseClient can set to update the Authorization
|
package/dist/index.d.ts
CHANGED
|
@@ -39,14 +39,30 @@ declare class DatabaseClient {
|
|
|
39
39
|
count?: "exact" | "estimated" | "planned";
|
|
40
40
|
head?: boolean;
|
|
41
41
|
}): this;
|
|
42
|
-
insert(data: Record<string, any> | Record<string, any>[]
|
|
42
|
+
insert(data: Record<string, any> | Record<string, any>[], options?: {
|
|
43
|
+
defaultToNull?: boolean;
|
|
44
|
+
}): this;
|
|
43
45
|
/** Upsert: insert or update on conflict. Uses merge-duplicates by default. */
|
|
44
46
|
upsert(data: Record<string, any> | Record<string, any>[], options?: {
|
|
45
47
|
ignoreDuplicates?: boolean;
|
|
46
48
|
onConflict?: string;
|
|
49
|
+
defaultToNull?: boolean;
|
|
47
50
|
}): this;
|
|
48
51
|
update(data: Record<string, any>): this;
|
|
49
|
-
delete(
|
|
52
|
+
delete(options?: {
|
|
53
|
+
count?: "exact" | "estimated" | "planned";
|
|
54
|
+
}): this;
|
|
55
|
+
/** Specify return=minimal to skip returning data on mutations (better performance). */
|
|
56
|
+
returning(mode?: "minimal" | "representation"): this;
|
|
57
|
+
/** Get the query execution plan (EXPLAIN). */
|
|
58
|
+
explain(options?: {
|
|
59
|
+
analyze?: boolean;
|
|
60
|
+
verbose?: boolean;
|
|
61
|
+
settings?: boolean;
|
|
62
|
+
buffers?: boolean;
|
|
63
|
+
wal?: boolean;
|
|
64
|
+
format?: "json" | "text";
|
|
65
|
+
}): this;
|
|
50
66
|
eq(column: string, value: any): this;
|
|
51
67
|
neq(column: string, value: any): this;
|
|
52
68
|
gt(column: string, value: any): this;
|
|
@@ -69,18 +85,42 @@ declare class DatabaseClient {
|
|
|
69
85
|
is(column: string, value: "null" | "true" | "false" | null | boolean): this;
|
|
70
86
|
/** IS DISTINCT FROM */
|
|
71
87
|
isDistinct(column: string, value: any): this;
|
|
88
|
+
/** Strictly left of: [a,b] << [c,d] */
|
|
89
|
+
rangeLt(column: string, range: string): this;
|
|
90
|
+
/** Strictly right of: [a,b] >> [c,d] */
|
|
91
|
+
rangeGt(column: string, range: string): this;
|
|
92
|
+
/** Does not extend to the left of */
|
|
93
|
+
rangeGte(column: string, range: string): this;
|
|
94
|
+
/** Does not extend to the right of */
|
|
95
|
+
rangeLte(column: string, range: string): this;
|
|
96
|
+
/** Range is adjacent to */
|
|
97
|
+
rangeAdjacent(column: string, range: string): this;
|
|
72
98
|
/** Negate a filter: not.eq, not.in, not.is, etc. */
|
|
73
99
|
not(column: string, operator: string, value: any): this;
|
|
74
100
|
/** OR filter: or("age.gt.20,name.eq.John") */
|
|
75
|
-
or(filters: string
|
|
76
|
-
|
|
101
|
+
or(filters: string, options?: {
|
|
102
|
+
foreignTable?: string;
|
|
103
|
+
}): this;
|
|
104
|
+
/** AND filter: and("age.gt.20,name.eq.John") */
|
|
105
|
+
and(filters: string, options?: {
|
|
106
|
+
foreignTable?: string;
|
|
107
|
+
}): this;
|
|
108
|
+
/** Generic filter: filter("column", "operator", "value") */
|
|
109
|
+
filter(column: string, operator: string, value: any): this;
|
|
110
|
+
/** Full-text search (to_tsquery, plainto_tsquery, phraseto_tsquery, or websearch_to_tsquery) */
|
|
77
111
|
textSearch(column: string, query: string, options?: {
|
|
78
112
|
type?: "plain" | "phrase" | "websearch";
|
|
113
|
+
config?: string;
|
|
79
114
|
}): this;
|
|
80
115
|
order(column: string, options?: {
|
|
81
116
|
ascending?: boolean;
|
|
82
117
|
nullsFirst?: boolean;
|
|
118
|
+
foreignTable?: string;
|
|
83
119
|
}): this;
|
|
120
|
+
/** Limit results on a foreign table */
|
|
121
|
+
limitForeignTable(count: number, foreignTable: string): this;
|
|
122
|
+
/** Offset results on a foreign table */
|
|
123
|
+
offsetForeignTable(count: number, foreignTable: string): this;
|
|
84
124
|
limit(count: number): this;
|
|
85
125
|
offset(count: number): this;
|
|
86
126
|
/** Request exact, estimated, or planned count via Prefer header */
|
|
@@ -226,6 +266,8 @@ interface AuthUser {
|
|
|
226
266
|
declare class AuthClient {
|
|
227
267
|
private request;
|
|
228
268
|
private listeners;
|
|
269
|
+
/** Promise that resolves when session restore from storage is complete. */
|
|
270
|
+
_restorePromise: Promise<void>;
|
|
229
271
|
private currentSession;
|
|
230
272
|
/**
|
|
231
273
|
* Callback that the parent LinabaseClient can set to update the Authorization
|
package/dist/index.js
CHANGED
|
@@ -25,10 +25,11 @@ var DatabaseClient = class {
|
|
|
25
25
|
if (options?.count) this.preferHeaders.push(`count=${options.count}`);
|
|
26
26
|
return this;
|
|
27
27
|
}
|
|
28
|
-
insert(data) {
|
|
28
|
+
insert(data, options) {
|
|
29
29
|
this.method = "POST";
|
|
30
30
|
this.body = data;
|
|
31
31
|
this.preferHeaders.push("return=representation");
|
|
32
|
+
if (options?.defaultToNull === false) this.preferHeaders.push("missing=default");
|
|
32
33
|
return this;
|
|
33
34
|
}
|
|
34
35
|
/** Upsert: insert or update on conflict. Uses merge-duplicates by default. */
|
|
@@ -42,6 +43,7 @@ var DatabaseClient = class {
|
|
|
42
43
|
if (options?.onConflict) {
|
|
43
44
|
this.params.set("on_conflict", options.onConflict);
|
|
44
45
|
}
|
|
46
|
+
if (options?.defaultToNull === false) this.preferHeaders.push("missing=default");
|
|
45
47
|
return this;
|
|
46
48
|
}
|
|
47
49
|
update(data) {
|
|
@@ -50,8 +52,28 @@ var DatabaseClient = class {
|
|
|
50
52
|
this.preferHeaders.push("return=representation");
|
|
51
53
|
return this;
|
|
52
54
|
}
|
|
53
|
-
delete() {
|
|
55
|
+
delete(options) {
|
|
54
56
|
this.method = "DELETE";
|
|
57
|
+
if (options?.count) this.preferHeaders.push(`count=${options.count}`);
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
/** Specify return=minimal to skip returning data on mutations (better performance). */
|
|
61
|
+
returning(mode = "representation") {
|
|
62
|
+
this.preferHeaders = this.preferHeaders.filter((h) => !h.startsWith("return="));
|
|
63
|
+
this.preferHeaders.push(`return=${mode}`);
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
/** Get the query execution plan (EXPLAIN). */
|
|
67
|
+
explain(options) {
|
|
68
|
+
const parts = ["plan"];
|
|
69
|
+
if (options?.analyze) parts.push("analyze");
|
|
70
|
+
if (options?.verbose) parts.push("verbose");
|
|
71
|
+
if (options?.settings) parts.push("settings");
|
|
72
|
+
if (options?.buffers) parts.push("buffers");
|
|
73
|
+
if (options?.wal) parts.push("wal");
|
|
74
|
+
if (options?.format) parts.push(`format:${options.format}`);
|
|
75
|
+
this.preferHeaders = this.preferHeaders.filter((h) => !h.startsWith("plan"));
|
|
76
|
+
this.preferHeaders.push(parts.join("|"));
|
|
55
77
|
return this;
|
|
56
78
|
}
|
|
57
79
|
// ─── Comparison Filters ─────────────────────────────────
|
|
@@ -135,6 +157,32 @@ var DatabaseClient = class {
|
|
|
135
157
|
this.params.set(column, `isdistinct.${value}`);
|
|
136
158
|
return this;
|
|
137
159
|
}
|
|
160
|
+
// ─── Range Type Filters ──────────────────────────────────
|
|
161
|
+
/** Strictly left of: [a,b] << [c,d] */
|
|
162
|
+
rangeLt(column, range) {
|
|
163
|
+
this.params.set(column, `sl.${range}`);
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
166
|
+
/** Strictly right of: [a,b] >> [c,d] */
|
|
167
|
+
rangeGt(column, range) {
|
|
168
|
+
this.params.set(column, `sr.${range}`);
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
/** Does not extend to the left of */
|
|
172
|
+
rangeGte(column, range) {
|
|
173
|
+
this.params.set(column, `nxl.${range}`);
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
176
|
+
/** Does not extend to the right of */
|
|
177
|
+
rangeLte(column, range) {
|
|
178
|
+
this.params.set(column, `nxr.${range}`);
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
/** Range is adjacent to */
|
|
182
|
+
rangeAdjacent(column, range) {
|
|
183
|
+
this.params.set(column, `adj.${range}`);
|
|
184
|
+
return this;
|
|
185
|
+
}
|
|
138
186
|
// ─── Negation ───────────────────────────────────────────
|
|
139
187
|
/** Negate a filter: not.eq, not.in, not.is, etc. */
|
|
140
188
|
not(column, operator, value) {
|
|
@@ -143,29 +191,53 @@ var DatabaseClient = class {
|
|
|
143
191
|
}
|
|
144
192
|
// ─── Logical ────────────────────────────────────────────
|
|
145
193
|
/** OR filter: or("age.gt.20,name.eq.John") */
|
|
146
|
-
or(filters) {
|
|
147
|
-
|
|
194
|
+
or(filters, options) {
|
|
195
|
+
const key = options?.foreignTable ? `${options.foreignTable}.or` : "or";
|
|
196
|
+
this.params.set(key, `(${filters})`);
|
|
197
|
+
return this;
|
|
198
|
+
}
|
|
199
|
+
/** AND filter: and("age.gt.20,name.eq.John") */
|
|
200
|
+
and(filters, options) {
|
|
201
|
+
const key = options?.foreignTable ? `${options.foreignTable}.and` : "and";
|
|
202
|
+
this.params.set(key, `(${filters})`);
|
|
203
|
+
return this;
|
|
204
|
+
}
|
|
205
|
+
/** Generic filter: filter("column", "operator", "value") */
|
|
206
|
+
filter(column, operator, value) {
|
|
207
|
+
this.params.set(column, `${operator}.${value}`);
|
|
148
208
|
return this;
|
|
149
209
|
}
|
|
150
210
|
// ─── Full-Text Search ───────────────────────────────────
|
|
151
|
-
/** to_tsquery */
|
|
211
|
+
/** Full-text search (to_tsquery, plainto_tsquery, phraseto_tsquery, or websearch_to_tsquery) */
|
|
152
212
|
textSearch(column, query, options) {
|
|
153
213
|
const op = options?.type === "plain" ? "plfts" : options?.type === "phrase" ? "phfts" : options?.type === "websearch" ? "wfts" : "fts";
|
|
154
|
-
|
|
214
|
+
const config = options?.config ? `(${options.config})` : "";
|
|
215
|
+
this.params.set(column, `${op}${config}.${query}`);
|
|
155
216
|
return this;
|
|
156
217
|
}
|
|
157
218
|
// ─── Ordering & Pagination ──────────────────────────────
|
|
158
219
|
order(column, options) {
|
|
159
220
|
const dir = options?.ascending === false ? "desc" : "asc";
|
|
160
221
|
const nulls = options?.nullsFirst === true ? ".nullsfirst" : options?.nullsFirst === false ? ".nullslast" : "";
|
|
161
|
-
const
|
|
222
|
+
const key = options?.foreignTable ? `${options.foreignTable}.order` : "order";
|
|
223
|
+
const existing = this.params.get(key);
|
|
162
224
|
if (existing) {
|
|
163
|
-
this.params.set(
|
|
225
|
+
this.params.set(key, `${existing},${column}.${dir}${nulls}`);
|
|
164
226
|
} else {
|
|
165
|
-
this.params.set(
|
|
227
|
+
this.params.set(key, `${column}.${dir}${nulls}`);
|
|
166
228
|
}
|
|
167
229
|
return this;
|
|
168
230
|
}
|
|
231
|
+
/** Limit results on a foreign table */
|
|
232
|
+
limitForeignTable(count, foreignTable) {
|
|
233
|
+
this.params.set(`${foreignTable}.limit`, String(count));
|
|
234
|
+
return this;
|
|
235
|
+
}
|
|
236
|
+
/** Offset results on a foreign table */
|
|
237
|
+
offsetForeignTable(count, foreignTable) {
|
|
238
|
+
this.params.set(`${foreignTable}.offset`, String(count));
|
|
239
|
+
return this;
|
|
240
|
+
}
|
|
169
241
|
limit(count) {
|
|
170
242
|
this.params.set("limit", String(count));
|
|
171
243
|
return this;
|
|
@@ -590,6 +662,8 @@ var BucketClient = class {
|
|
|
590
662
|
var AuthClient = class {
|
|
591
663
|
request;
|
|
592
664
|
listeners = [];
|
|
665
|
+
/** Promise that resolves when session restore from storage is complete. */
|
|
666
|
+
_restorePromise = Promise.resolve();
|
|
593
667
|
currentSession = null;
|
|
594
668
|
/**
|
|
595
669
|
* Callback that the parent LinabaseClient can set to update the Authorization
|
|
@@ -960,6 +1034,11 @@ var AuthClient = class {
|
|
|
960
1034
|
// ─── Auth State Listener ───────────────────────────────────
|
|
961
1035
|
onAuthStateChange(callback) {
|
|
962
1036
|
this.listeners.push(callback);
|
|
1037
|
+
this._restorePromise.then(() => {
|
|
1038
|
+
if (this.listeners.includes(callback)) {
|
|
1039
|
+
callback("INITIAL_SESSION", this.currentSession);
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
963
1042
|
return {
|
|
964
1043
|
unsubscribe: () => {
|
|
965
1044
|
this.listeners = this.listeners.filter((l) => l !== callback);
|
|
@@ -1057,7 +1136,7 @@ function createClient(config) {
|
|
|
1057
1136
|
sessionStorage.removeItem(sessionKey);
|
|
1058
1137
|
}
|
|
1059
1138
|
});
|
|
1060
|
-
Promise.resolve(sessionStorage.getItem(sessionKey)).then((raw) => {
|
|
1139
|
+
authClient._restorePromise = Promise.resolve(sessionStorage.getItem(sessionKey)).then((raw) => {
|
|
1061
1140
|
if (raw) {
|
|
1062
1141
|
try {
|
|
1063
1142
|
authClient.setSession(JSON.parse(raw));
|