@aiao/rxdb-adapter-supabase 0.0.7
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/LICENSE +21 -0
- package/README.md +91 -0
- package/dist/RxDBAdapterSupabase.d.ts +105 -0
- package/dist/RxDBAdapterSupabase.d.ts.map +1 -0
- package/dist/RxDBAdapterSupabase.utils.d.ts +18 -0
- package/dist/RxDBAdapterSupabase.utils.d.ts.map +1 -0
- package/dist/SupabaseRepository.d.ts +52 -0
- package/dist/SupabaseRepository.d.ts.map +1 -0
- package/dist/SupabaseTreeRepository.d.ts +62 -0
- package/dist/SupabaseTreeRepository.d.ts.map +1 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/handle_supabase_change.d.ts +10 -0
- package/dist/handle_supabase_change.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +858 -0
- package/dist/rule_group_builder.d.ts +11 -0
- package/dist/rule_group_builder.d.ts.map +1 -0
- package/dist/supabase.interface.d.ts +18 -0
- package/dist/supabase.interface.d.ts.map +1 -0
- package/dist/transform.d.ts +6 -0
- package/dist/transform.d.ts.map +1 -0
- package/package.json +36 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,858 @@
|
|
|
1
|
+
import { EntityRemoteRemovedEvent as M, EntityRemoteUpdatedEvent as j, EntityRemoteCreatedEvent as O, getEntityMetadata as b, isRuleGroup as x, PropertyType as E, RepositoryBase as W, RxDBAdapterRemoteBase as U } from "@aiao/rxdb";
|
|
2
|
+
import { createClient as K } from "@supabase/supabase-js";
|
|
3
|
+
class S extends Error {
|
|
4
|
+
constructor(t, e) {
|
|
5
|
+
super(t), this.code = e, this.name = "SupabaseSyncError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
class q extends S {
|
|
9
|
+
constructor(t) {
|
|
10
|
+
super(t, "CONFIG_ERROR"), this.name = "SupabaseConfigError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
class tt extends S {
|
|
14
|
+
constructor(t) {
|
|
15
|
+
super(t, "NETWORK_ERROR"), this.name = "SupabaseNetworkError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
class g extends S {
|
|
19
|
+
constructor(t) {
|
|
20
|
+
super(t, "DATA_ERROR"), this.name = "SupabaseDataError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const z = {
|
|
24
|
+
INSERT: O,
|
|
25
|
+
UPDATE: j,
|
|
26
|
+
DELETE: M
|
|
27
|
+
};
|
|
28
|
+
function L(r, t) {
|
|
29
|
+
if (t.table !== "RxDBChange" || t.eventType !== "INSERT") return;
|
|
30
|
+
const e = t.new;
|
|
31
|
+
if (!e) return;
|
|
32
|
+
const { namespace: s, entity: n, entityId: a, type: i, patch: c, clientId: o } = e, l = r.rxdb.context.clientId;
|
|
33
|
+
if (o && l && o === l || !a || !i) return;
|
|
34
|
+
const p = z[i];
|
|
35
|
+
if (!p) return;
|
|
36
|
+
const d = { id: a, ...c };
|
|
37
|
+
r.rxdb.dispatchEvent(
|
|
38
|
+
new p([
|
|
39
|
+
{
|
|
40
|
+
type: i,
|
|
41
|
+
namespace: s || "public",
|
|
42
|
+
entity: n,
|
|
43
|
+
id: a,
|
|
44
|
+
data: d,
|
|
45
|
+
recordAt: e.createdAt ? new Date(e.createdAt) : /* @__PURE__ */ new Date()
|
|
46
|
+
}
|
|
47
|
+
])
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
function D(r) {
|
|
51
|
+
const t = /* @__PURE__ */ new Map();
|
|
52
|
+
for (const e of r) {
|
|
53
|
+
const s = e.constructor;
|
|
54
|
+
t.has(s) || t.set(s, /* @__PURE__ */ new Set()), t.get(s).add(e);
|
|
55
|
+
}
|
|
56
|
+
return t;
|
|
57
|
+
}
|
|
58
|
+
function k(r, t) {
|
|
59
|
+
const e = [];
|
|
60
|
+
for (const [s, n] of r) {
|
|
61
|
+
const a = b(s), i = Array.from(n);
|
|
62
|
+
e.push({
|
|
63
|
+
table: a.name,
|
|
64
|
+
schema: a.namespace,
|
|
65
|
+
data: t ? i.map((c) => ({ ...c, createdBy: t, updatedBy: t })) : i
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return e;
|
|
69
|
+
}
|
|
70
|
+
function Q(r) {
|
|
71
|
+
const t = [];
|
|
72
|
+
for (const [e, s] of r) {
|
|
73
|
+
const n = b(e);
|
|
74
|
+
t.push({
|
|
75
|
+
table: n.name,
|
|
76
|
+
schema: n.namespace,
|
|
77
|
+
ids: Array.from(s).map((a) => a.id)
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return t;
|
|
81
|
+
}
|
|
82
|
+
const V = {
|
|
83
|
+
"=": "eq",
|
|
84
|
+
"!=": "neq",
|
|
85
|
+
"<": "lt",
|
|
86
|
+
"<=": "lte",
|
|
87
|
+
">": "gt",
|
|
88
|
+
">=": "gte",
|
|
89
|
+
in: "in",
|
|
90
|
+
contains: "ilike",
|
|
91
|
+
includes: "ilike",
|
|
92
|
+
startsWith: "ilike",
|
|
93
|
+
endsWith: "ilike"
|
|
94
|
+
};
|
|
95
|
+
function C(r) {
|
|
96
|
+
return r instanceof Date ? r.toISOString() : Array.isArray(r) ? r.map(C) : r;
|
|
97
|
+
}
|
|
98
|
+
function T(r, t, e) {
|
|
99
|
+
return !t || !r.mappedEntity ? e : t.getEntityMetadata(r.mappedEntity, r.mappedNamespace ?? "") ?? e;
|
|
100
|
+
}
|
|
101
|
+
function N(r, t) {
|
|
102
|
+
const e = C(t);
|
|
103
|
+
switch (r) {
|
|
104
|
+
case "=":
|
|
105
|
+
case "!=":
|
|
106
|
+
case "<":
|
|
107
|
+
case "<=":
|
|
108
|
+
case ">":
|
|
109
|
+
case ">=":
|
|
110
|
+
return `${V[r]}.${e}`;
|
|
111
|
+
case "in":
|
|
112
|
+
if (!Array.isArray(e)) throw new Error("IN operator requires array");
|
|
113
|
+
return `in.(${e.join(",")})`;
|
|
114
|
+
case "contains":
|
|
115
|
+
case "includes":
|
|
116
|
+
return `ilike.*${e}*`;
|
|
117
|
+
case "startsWith":
|
|
118
|
+
return `ilike.${e}*`;
|
|
119
|
+
case "endsWith":
|
|
120
|
+
return `ilike.*${e}`;
|
|
121
|
+
default:
|
|
122
|
+
throw new Error(`Unsupported operator: ${r}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function v(r, t, e) {
|
|
126
|
+
const [s, ...n] = r.split(".");
|
|
127
|
+
return n.length === 0 ? { field: r, operator: t, value: e } : {
|
|
128
|
+
field: s,
|
|
129
|
+
operator: "exists",
|
|
130
|
+
where: { combinator: "and", rules: [v(n.join("."), t, e)] }
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function A(r, t, e, s) {
|
|
134
|
+
if (!t?.rules?.length) return r;
|
|
135
|
+
if (t.rules.length === 1) {
|
|
136
|
+
const a = t.rules[0];
|
|
137
|
+
return x(a) ? A(r, a, e, s) : R(r, a, e, s);
|
|
138
|
+
}
|
|
139
|
+
if (t.combinator === "and")
|
|
140
|
+
return t.rules.reduce(
|
|
141
|
+
(a, i) => x(i) ? A(a, i, e, s) : R(a, i, e, s),
|
|
142
|
+
r
|
|
143
|
+
);
|
|
144
|
+
const n = t.rules.map((a) => {
|
|
145
|
+
if (x(a)) throw new Error("Nested OR conditions not supported");
|
|
146
|
+
const { field: i, operator: c, value: o } = a;
|
|
147
|
+
return `${i}.${N(c, o)}`;
|
|
148
|
+
});
|
|
149
|
+
return r.or(n.join(","));
|
|
150
|
+
}
|
|
151
|
+
function R(r, t, e, s) {
|
|
152
|
+
const { field: n, operator: a, value: i } = t;
|
|
153
|
+
return typeof n == "string" && n.includes(".") ? R(r, v(n, a, i), e, s) : a === "exists" || a === "notExists" ? J(r, t, e, s) : B(r, n, a, i);
|
|
154
|
+
}
|
|
155
|
+
function J(r, t, e, s) {
|
|
156
|
+
const { field: n, operator: a } = t, i = t.where, c = String(n), o = e?.relationMap?.get(c);
|
|
157
|
+
if (!o)
|
|
158
|
+
throw new Error(`Relation '${c}' not found in '${e?.name || "unknown"}'`);
|
|
159
|
+
const l = o.mappedEntity;
|
|
160
|
+
if (!i?.rules?.length)
|
|
161
|
+
return a === "exists" ? r.not(l, "is", null) : r.is(l, null);
|
|
162
|
+
const p = e ? T(o, s, e) : void 0;
|
|
163
|
+
if (!p) throw new Error(`Cannot resolve metadata for '${c}'`);
|
|
164
|
+
return I(r, l, i, p, s, l);
|
|
165
|
+
}
|
|
166
|
+
function I(r, t, e, s, n, a = "") {
|
|
167
|
+
if (!e?.rules?.length) return r;
|
|
168
|
+
let i = r;
|
|
169
|
+
for (const c of e.rules) {
|
|
170
|
+
if (x(c)) {
|
|
171
|
+
i = I(i, t, c, s, n, a);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const { field: o, operator: l, value: p } = c;
|
|
175
|
+
if (l === "exists" || l === "notExists") {
|
|
176
|
+
const f = s?.relationMap?.get(String(o));
|
|
177
|
+
if (!f) throw new Error(`Relation '${o}' not found in ${t}`);
|
|
178
|
+
const h = f.mappedEntity, u = c.where, w = T(f, n, s);
|
|
179
|
+
if (u?.rules?.length) {
|
|
180
|
+
const m = a ? `${a}.${h}` : h;
|
|
181
|
+
i = I(i, h, u, w, n, m);
|
|
182
|
+
} else
|
|
183
|
+
i = l === "exists" ? i.not(h, "is", null) : i.is(h, null);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
const d = a ? `${a}.${o}` : `${t}.${o}`;
|
|
187
|
+
i = B(i, d, l, p);
|
|
188
|
+
}
|
|
189
|
+
return i;
|
|
190
|
+
}
|
|
191
|
+
function B(r, t, e, s) {
|
|
192
|
+
const n = C(s);
|
|
193
|
+
if (t.includes(".")) {
|
|
194
|
+
if (!r.url?.searchParams)
|
|
195
|
+
throw new Error("Cannot apply nested filter: query.url.searchParams unavailable");
|
|
196
|
+
if (e === "between") {
|
|
197
|
+
const [i, c] = n;
|
|
198
|
+
return r.url.searchParams.append(t, `gte.${i}`), r.url.searchParams.append(t, `lte.${c}`), r;
|
|
199
|
+
}
|
|
200
|
+
return r.url.searchParams.append(t, N(e, n)), r;
|
|
201
|
+
}
|
|
202
|
+
switch (e) {
|
|
203
|
+
case "=":
|
|
204
|
+
return n === null ? r.is(t, null) : r.eq(t, n);
|
|
205
|
+
case "!=":
|
|
206
|
+
return n === null ? r.not(t, "is", null) : r.neq(t, n);
|
|
207
|
+
case "<":
|
|
208
|
+
return r.lt(t, n);
|
|
209
|
+
case ">":
|
|
210
|
+
return r.gt(t, n);
|
|
211
|
+
case "<=":
|
|
212
|
+
return r.lte(t, n);
|
|
213
|
+
case ">=":
|
|
214
|
+
return r.gte(t, n);
|
|
215
|
+
case "in":
|
|
216
|
+
return r.in(t, n);
|
|
217
|
+
case "notIn":
|
|
218
|
+
return r.not(t, "in", `(${n.join(",")})`);
|
|
219
|
+
case "contains":
|
|
220
|
+
case "includes":
|
|
221
|
+
return r.ilike(t, `%${n}%`);
|
|
222
|
+
case "notContains":
|
|
223
|
+
return r.not(t, "ilike", `%${n}%`);
|
|
224
|
+
case "startsWith":
|
|
225
|
+
return r.ilike(t, `${n}%`);
|
|
226
|
+
case "notStartsWith":
|
|
227
|
+
return r.not(t, "ilike", `${n}%`);
|
|
228
|
+
case "endsWith":
|
|
229
|
+
return r.ilike(t, `%${n}`);
|
|
230
|
+
case "notEndsWith":
|
|
231
|
+
return r.not(t, "ilike", `%${n}`);
|
|
232
|
+
case "between": {
|
|
233
|
+
const [i, c] = n;
|
|
234
|
+
return r.gte(t, i).lte(t, c);
|
|
235
|
+
}
|
|
236
|
+
case "notBetween": {
|
|
237
|
+
const [i, c] = n;
|
|
238
|
+
return r.or(`${t}.lt.${i},${t}.gt.${c}`);
|
|
239
|
+
}
|
|
240
|
+
case "isNull":
|
|
241
|
+
return r.is(t, null);
|
|
242
|
+
case "isNotNull":
|
|
243
|
+
return r.not(t, "is", null);
|
|
244
|
+
default:
|
|
245
|
+
throw new Error(`Unsupported operator: ${e}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function P(r, t) {
|
|
249
|
+
if (r == null) return r;
|
|
250
|
+
switch (t.type) {
|
|
251
|
+
case E.date:
|
|
252
|
+
return r instanceof Date ? r : new Date(r);
|
|
253
|
+
case E.keyValue:
|
|
254
|
+
if (typeof r == "object" && t.properties) {
|
|
255
|
+
const e = {};
|
|
256
|
+
for (const s of t.properties)
|
|
257
|
+
r[s.name] !== void 0 && (e[s.name] = P(r[s.name], s));
|
|
258
|
+
return e;
|
|
259
|
+
}
|
|
260
|
+
return r;
|
|
261
|
+
case E.boolean:
|
|
262
|
+
return !!r;
|
|
263
|
+
case E.json:
|
|
264
|
+
case E.stringArray:
|
|
265
|
+
case E.numberArray:
|
|
266
|
+
default:
|
|
267
|
+
return r;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function X(r, t, e) {
|
|
271
|
+
const s = new r();
|
|
272
|
+
for (const n of Object.keys(e)) {
|
|
273
|
+
const a = t.propertyMap.get(n);
|
|
274
|
+
s[n] = a ? P(e[n], a) : e[n];
|
|
275
|
+
}
|
|
276
|
+
return s;
|
|
277
|
+
}
|
|
278
|
+
class F extends W {
|
|
279
|
+
constructor(t, e) {
|
|
280
|
+
super(t.rxdb, e), this.adapter = t, this.metadata = b(e);
|
|
281
|
+
}
|
|
282
|
+
metadata;
|
|
283
|
+
/**
|
|
284
|
+
* 查询多个实体
|
|
285
|
+
*/
|
|
286
|
+
async find(t) {
|
|
287
|
+
const e = this.extract_relation_fields(t.where);
|
|
288
|
+
let s = "*";
|
|
289
|
+
if (e.size > 0) {
|
|
290
|
+
const c = Array.from(e);
|
|
291
|
+
s = `*, ${c.filter(
|
|
292
|
+
(l) => !c.some((p) => p !== l && p.startsWith(l + "."))
|
|
293
|
+
).map((l) => this.build_relation_select(l)).join(", ")}`;
|
|
294
|
+
}
|
|
295
|
+
let n = this.get_client().select(s);
|
|
296
|
+
if (n = A(n, t.where, this.metadata, this.adapter.rxdb.schemaManager), t.orderBy?.length)
|
|
297
|
+
for (const c of t.orderBy)
|
|
298
|
+
n = n.order(c.field, { ascending: c.sort === "asc" });
|
|
299
|
+
if (t.offset !== void 0) {
|
|
300
|
+
const c = t.offset, o = t.limit !== void 0 ? c + t.limit - 1 : Number.MAX_SAFE_INTEGER;
|
|
301
|
+
n = n.range(c, o);
|
|
302
|
+
} else t.limit !== void 0 && (n = n.limit(t.limit));
|
|
303
|
+
const { data: a, error: i } = await n;
|
|
304
|
+
if (i) throw new g(`Failed to find entities: ${i.message}`);
|
|
305
|
+
return (a || []).map((c) => X(this.EntityType, this.metadata, c));
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* 查询实体数量
|
|
309
|
+
*/
|
|
310
|
+
async count(t) {
|
|
311
|
+
if (t.groupBy) throw new Error("groupBy not supported yet");
|
|
312
|
+
const e = this.extract_relation_fields(t.where);
|
|
313
|
+
let s = "*";
|
|
314
|
+
e.size > 0 && (s = `*, ${Array.from(e).map((c) => this.build_relation_select(c)).join(", ")}`);
|
|
315
|
+
let n = this.get_client().select(s, { count: "exact", head: !0 });
|
|
316
|
+
n = A(n, t.where, this.metadata, this.adapter.rxdb.schemaManager);
|
|
317
|
+
const { count: a, error: i } = await n;
|
|
318
|
+
if (i) {
|
|
319
|
+
if (!i.message)
|
|
320
|
+
return console.warn("Supabase count returned empty error, returning 0. Options:", JSON.stringify(t)), 0;
|
|
321
|
+
throw new g(`Failed to count entities: ${i.message}`);
|
|
322
|
+
}
|
|
323
|
+
return a ?? 0;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* 创建实体
|
|
327
|
+
*/
|
|
328
|
+
async create(t) {
|
|
329
|
+
const e = { ...t }, s = this.rxdb.context.userId;
|
|
330
|
+
s && (e.createdBy = s);
|
|
331
|
+
const { data: n, error: a } = await this.get_client().insert(e).select().single();
|
|
332
|
+
if (a) throw new g(`Failed to create entity: ${a.message}`);
|
|
333
|
+
return n;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* 更新实体
|
|
337
|
+
*/
|
|
338
|
+
async update(t, e) {
|
|
339
|
+
const { data: s, error: n } = await this.get_client().update(e).eq("id", t.id).select().single();
|
|
340
|
+
if (n) throw new g(`Failed to update entity: ${n.message}`);
|
|
341
|
+
return s;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* 删除实体
|
|
345
|
+
* @param entity
|
|
346
|
+
* @returns
|
|
347
|
+
*/
|
|
348
|
+
async remove(t) {
|
|
349
|
+
const { error: e } = await this.get_client().delete().eq("id", t.id);
|
|
350
|
+
if (e) throw new g(`Failed to remove entity: ${e.message}`);
|
|
351
|
+
return t;
|
|
352
|
+
}
|
|
353
|
+
// ============================================
|
|
354
|
+
// 私有方法
|
|
355
|
+
// ============================================
|
|
356
|
+
/** 提取查询中的关系字段路径(用于 EXISTS 查询的 INNER JOIN) */
|
|
357
|
+
extract_relation_fields(t) {
|
|
358
|
+
const e = /* @__PURE__ */ new Set(), s = (n, a = "") => {
|
|
359
|
+
if (n?.rules) {
|
|
360
|
+
for (const i of n.rules)
|
|
361
|
+
if (i.rules)
|
|
362
|
+
s(i, a);
|
|
363
|
+
else if (typeof i.field == "string" && i.field.includes(".")) {
|
|
364
|
+
const c = i.field.split(".");
|
|
365
|
+
for (let o = 1; o < c.length; o++) {
|
|
366
|
+
const l = c.slice(0, o).join(".");
|
|
367
|
+
e.add(a ? `${a}.${l}` : l);
|
|
368
|
+
}
|
|
369
|
+
} else if (i.operator === "exists" || i.operator === "notExists") {
|
|
370
|
+
const c = String(i.field), o = a ? `${a}.${c}` : c;
|
|
371
|
+
this.metadata.relationMap?.has(c) && e.add(o), i.where && s(i.where, o);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
return s(t), e;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* 构建关系字段的 SELECT 语法
|
|
379
|
+
* 支持嵌套路径:'orders.items' → Order!inner(*, OrderItem!inner(*))
|
|
380
|
+
*/
|
|
381
|
+
build_relation_select(t) {
|
|
382
|
+
const e = t.split(".");
|
|
383
|
+
if (e.length === 1) return this.build_single_relation_select(e[0]);
|
|
384
|
+
const s = [];
|
|
385
|
+
let n = this.metadata;
|
|
386
|
+
for (const i of e) {
|
|
387
|
+
const c = n.relationMap?.get(i);
|
|
388
|
+
if (!c) return `${i}(id)`;
|
|
389
|
+
s.push({ tableName: c.mappedEntity, kind: c.kind, sourceEntity: n.name });
|
|
390
|
+
const o = this.adapter.rxdb.schemaManager.getEntityMetadata(c.mappedEntity, c.mappedNamespace ?? "");
|
|
391
|
+
o && (n = o);
|
|
392
|
+
}
|
|
393
|
+
let a = this.build_relation_segment(s[s.length - 1], !0);
|
|
394
|
+
for (let i = s.length - 2; i >= 0; i--)
|
|
395
|
+
a = this.build_relation_segment(s[i], !0).replace("(*)", `(*, ${a})`);
|
|
396
|
+
return a;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* 构建单层关系 SELECT
|
|
400
|
+
* 根据关系类型生成正确的消歧语法
|
|
401
|
+
*/
|
|
402
|
+
build_single_relation_select(t) {
|
|
403
|
+
const e = this.metadata.relationMap?.get(t);
|
|
404
|
+
if (!e) return `${t}(id)`;
|
|
405
|
+
const s = e.mappedEntity, n = this.metadata.name;
|
|
406
|
+
if (e.kind === "m:1" || e.kind === "1:1") {
|
|
407
|
+
const a = `${n}_${t}Id_fkey`;
|
|
408
|
+
return `${s}!${a}(*)`;
|
|
409
|
+
}
|
|
410
|
+
if (e.kind === "m:n") {
|
|
411
|
+
const a = this.get_join_table_name(n, s);
|
|
412
|
+
return `${s}!${a}(*)`;
|
|
413
|
+
}
|
|
414
|
+
return `${s}(*)`;
|
|
415
|
+
}
|
|
416
|
+
/** 构建关系 SELECT 片段 */
|
|
417
|
+
build_relation_segment(t, e) {
|
|
418
|
+
const s = e ? "!inner" : "";
|
|
419
|
+
if (t.kind === "m:n") {
|
|
420
|
+
const n = this.get_join_table_name(t.sourceEntity, t.tableName);
|
|
421
|
+
return `${t.tableName}!${n}${s}(*)`;
|
|
422
|
+
}
|
|
423
|
+
return `${t.tableName}${s}(*)`;
|
|
424
|
+
}
|
|
425
|
+
/** 获取 m:n 中间表名(按字母顺序) */
|
|
426
|
+
get_join_table_name(t, e) {
|
|
427
|
+
return [t, e].sort().join("_");
|
|
428
|
+
}
|
|
429
|
+
/** 获取带 schema 的 client */
|
|
430
|
+
get_client() {
|
|
431
|
+
return this.adapter.client.schema(this.metadata.namespace).from(this.metadata.name);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
class H extends F {
|
|
435
|
+
constructor(t, e) {
|
|
436
|
+
super(t, e);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* 查询子孙节点
|
|
440
|
+
*
|
|
441
|
+
* @remarks
|
|
442
|
+
* - 指定 entityId 时:包含当前节点 + 子孙节点
|
|
443
|
+
* - 不指定 entityId 时:返回所有根节点及其子孙
|
|
444
|
+
*/
|
|
445
|
+
async findDescendants(t) {
|
|
446
|
+
const { entityId: e, level: s = 100 } = t, { data: n, error: a } = await this.adapter.client.rpc(
|
|
447
|
+
e ? "get_descendants" : "get_root_descendants",
|
|
448
|
+
e ? { root_id: e, max_level: s } : { max_level: s }
|
|
449
|
+
);
|
|
450
|
+
if (a) {
|
|
451
|
+
if (a.message.includes("function") || a.message.includes("Could not find"))
|
|
452
|
+
return this.findDescendantsFallback(t);
|
|
453
|
+
throw new g(`Failed to find descendants: ${a.message}`);
|
|
454
|
+
}
|
|
455
|
+
return (n || []).map((i) => this.transformRowToEntity(i));
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* 查询子孙节点数量
|
|
459
|
+
*
|
|
460
|
+
* @remarks
|
|
461
|
+
* - 指定 entityId 时:**不包含当前节点**,只统计后代数量
|
|
462
|
+
* - 不指定 entityId 时:统计所有根节点及其后代的总数
|
|
463
|
+
*/
|
|
464
|
+
async countDescendants(t) {
|
|
465
|
+
const { entityId: e } = t, s = await this.findDescendants(t);
|
|
466
|
+
return e ? s.length - 1 : s.length;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* 查询祖先节点
|
|
470
|
+
*
|
|
471
|
+
* @remarks
|
|
472
|
+
* 指定 entityId 时:包含当前节点 + 祖先节点
|
|
473
|
+
*/
|
|
474
|
+
async findAncestors(t) {
|
|
475
|
+
const { entityId: e, level: s = 100 } = t;
|
|
476
|
+
if (!e)
|
|
477
|
+
return [];
|
|
478
|
+
const { data: n, error: a } = await this.adapter.client.rpc("get_ancestors", {
|
|
479
|
+
node_id: e,
|
|
480
|
+
max_level: s
|
|
481
|
+
});
|
|
482
|
+
if (a) {
|
|
483
|
+
if (a.message.includes("function") || a.message.includes("Could not find"))
|
|
484
|
+
return this.findAncestorsFallback(t);
|
|
485
|
+
throw new g(`Failed to find ancestors: ${a.message}`);
|
|
486
|
+
}
|
|
487
|
+
return (n || []).map((i) => this.transformRowToEntity(i));
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* 查询祖先节点数量
|
|
491
|
+
*
|
|
492
|
+
* @remarks
|
|
493
|
+
* 指定 entityId 时:**不包含当前节点**,只统计祖先数量
|
|
494
|
+
*/
|
|
495
|
+
async countAncestors(t) {
|
|
496
|
+
const e = await this.findAncestors(t);
|
|
497
|
+
return Math.max(0, e.length - 1);
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* 备用的子孙节点查询(不使用存储函数)
|
|
501
|
+
* 仅支持简单的层级查询
|
|
502
|
+
*
|
|
503
|
+
* TODO: 当前实现存在 N+1 查询问题,对于深或宽的树性能较差。
|
|
504
|
+
* 优化方案:一次查询获取所有节点,在内存中构建树结构。
|
|
505
|
+
*/
|
|
506
|
+
async findDescendantsFallback(t) {
|
|
507
|
+
const { entityId: e, level: s = 100 } = t, n = this.metadata.name, a = this.metadata.features?.tree?.hasChildren, i = [], c = /* @__PURE__ */ new Set();
|
|
508
|
+
let o = this.adapter.client.schema("public").from(n).select("*");
|
|
509
|
+
e ? o = o.eq("id", e) : o = o.is("parentId", null);
|
|
510
|
+
const { data: l, error: p } = await o;
|
|
511
|
+
if (p)
|
|
512
|
+
throw new g(`Failed to find start nodes: ${p.message}`);
|
|
513
|
+
const d = async (f, h) => {
|
|
514
|
+
for (const u of f) {
|
|
515
|
+
if (c.has(u.id) || h > s) continue;
|
|
516
|
+
c.add(u.id);
|
|
517
|
+
const w = this.transformRowToEntity(u);
|
|
518
|
+
if (a) {
|
|
519
|
+
const { count: m } = await this.adapter.client.schema("public").from(n).select("*", { count: "exact", head: !0 }).eq("parentId", u.id);
|
|
520
|
+
w.hasChildren = (m || 0) > 0;
|
|
521
|
+
}
|
|
522
|
+
if (i.push(w), h < s) {
|
|
523
|
+
const { data: m } = await this.adapter.client.schema("public").from(n).select("*").eq("parentId", u.id);
|
|
524
|
+
m && m.length > 0 && await d(m, h + 1);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
return await d(l || [], 0), i;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* 备用的祖先节点查询(不使用存储函数)
|
|
532
|
+
*
|
|
533
|
+
* TODO: 当前实现存在 N+1 查询问题,每个祖先都需要一次查询。
|
|
534
|
+
* 优化方案:一次查询获取所有节点,在内存中向上遍历。
|
|
535
|
+
*/
|
|
536
|
+
async findAncestorsFallback(t) {
|
|
537
|
+
const { entityId: e, level: s = 100 } = t;
|
|
538
|
+
if (!e)
|
|
539
|
+
return [];
|
|
540
|
+
const n = this.metadata.name, a = this.metadata.features?.tree?.hasChildren, i = [];
|
|
541
|
+
let c = e, o = 0;
|
|
542
|
+
for (; c && o <= s; ) {
|
|
543
|
+
const { data: l, error: p } = await this.adapter.client.schema("public").from(n).select("*").eq("id", c);
|
|
544
|
+
if (p || !l || l.length === 0)
|
|
545
|
+
break;
|
|
546
|
+
const d = l[0], f = this.transformRowToEntity(d);
|
|
547
|
+
if (a) {
|
|
548
|
+
const { count: h } = await this.adapter.client.schema("public").from(n).select("*", { count: "exact", head: !0 }).eq("parentId", d.id);
|
|
549
|
+
f.hasChildren = (h || 0) > 0;
|
|
550
|
+
}
|
|
551
|
+
i.push(f), c = d.parentId, o++;
|
|
552
|
+
}
|
|
553
|
+
return i;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* 将数据库行转换为实体
|
|
557
|
+
*/
|
|
558
|
+
transformRowToEntity(t) {
|
|
559
|
+
const e = new this.EntityType();
|
|
560
|
+
return Object.keys(t).forEach((s) => {
|
|
561
|
+
s !== "level" && (e[s] = t[s]);
|
|
562
|
+
}), e;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
const Y = "supabase";
|
|
566
|
+
class et extends U {
|
|
567
|
+
constructor(t, e) {
|
|
568
|
+
super(t), this.options = e, this.#t = e.client ?? K(e.supabaseUrl, e.supabaseKey);
|
|
569
|
+
}
|
|
570
|
+
#t;
|
|
571
|
+
#e = null;
|
|
572
|
+
name = Y;
|
|
573
|
+
get client() {
|
|
574
|
+
return this.#t;
|
|
575
|
+
}
|
|
576
|
+
// ============================================
|
|
577
|
+
// 连接管理
|
|
578
|
+
// ============================================
|
|
579
|
+
async connect() {
|
|
580
|
+
return this.#e || (this.#e = this.#t.channel("rxdb-changes").on(
|
|
581
|
+
"postgres_changes",
|
|
582
|
+
{ event: "INSERT", schema: "public", table: "RxDBChange" },
|
|
583
|
+
(t) => L(this, t)
|
|
584
|
+
).subscribe((t, e) => {
|
|
585
|
+
e && console.error("Supabase Realtime subscription failed:", e);
|
|
586
|
+
})), this;
|
|
587
|
+
}
|
|
588
|
+
async disconnect() {
|
|
589
|
+
this.#e && (await this.#t.removeChannel(this.#e), this.#e = null);
|
|
590
|
+
}
|
|
591
|
+
async version() {
|
|
592
|
+
return "2.86.0";
|
|
593
|
+
}
|
|
594
|
+
// ============================================
|
|
595
|
+
// 批量操作
|
|
596
|
+
// ============================================
|
|
597
|
+
/**
|
|
598
|
+
* 批量保存实体(upsert 语义,非事务)
|
|
599
|
+
*/
|
|
600
|
+
async saveMany(t) {
|
|
601
|
+
return t.length === 0 ? [] : this.executeUpsert(D(t));
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* 批量删除实体(非事务)
|
|
605
|
+
*/
|
|
606
|
+
async removeMany(t) {
|
|
607
|
+
return t.length === 0 ? [] : this.executeDelete(D(t));
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* 批量修改实体(事务)
|
|
611
|
+
*
|
|
612
|
+
* 通过 PostgreSQL RPC 调用 `rxdb_mutations` 存储过程,
|
|
613
|
+
* 在单个数据库事务中执行所有操作,确保原子性。
|
|
614
|
+
*/
|
|
615
|
+
async mutations(t) {
|
|
616
|
+
const e = this.rxdb.context.userId, s = [...k(t.create, e), ...k(t.update, e)], n = Q(t.remove), { data: a, error: i } = await this.#t.rpc("rxdb_mutations", {
|
|
617
|
+
p_upserts: s,
|
|
618
|
+
p_deletes: n
|
|
619
|
+
});
|
|
620
|
+
if (i)
|
|
621
|
+
throw new g(`Transaction failed: ${i.message}`);
|
|
622
|
+
const c = a?.upserted ?? [];
|
|
623
|
+
for (const [, o] of t.remove)
|
|
624
|
+
c.push(...o);
|
|
625
|
+
return c;
|
|
626
|
+
}
|
|
627
|
+
// ============================================
|
|
628
|
+
// Repository
|
|
629
|
+
// ============================================
|
|
630
|
+
getRepository(t) {
|
|
631
|
+
if (this.repository_cache.has(t))
|
|
632
|
+
return this.repository_cache.get(t);
|
|
633
|
+
const s = b(t).features?.tree ? new H(this, t) : new F(this, t);
|
|
634
|
+
return this.repository_cache.set(t, s), s;
|
|
635
|
+
}
|
|
636
|
+
// ============================================
|
|
637
|
+
// 工具方法
|
|
638
|
+
// ============================================
|
|
639
|
+
async isTableExisted(t) {
|
|
640
|
+
const e = b(t), n = await this.getSchemaClient(e.namespace).from(e.name).select("*", { count: "exact", head: !0 });
|
|
641
|
+
if (n.status === 200) return !0;
|
|
642
|
+
if (n.status === 204) return !1;
|
|
643
|
+
throw new g(
|
|
644
|
+
`Failed to check table existence: ${n.error?.message || `status ${n.status}`}`
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
// ============================================
|
|
648
|
+
// Pull/Push 同步方法
|
|
649
|
+
// ============================================
|
|
650
|
+
/**
|
|
651
|
+
* 从远程拉取变更记录
|
|
652
|
+
*
|
|
653
|
+
* @param sinceId - 拉取此 ID 之后的变更(不包含该 ID)
|
|
654
|
+
* @param limit - 最大拉取数量
|
|
655
|
+
* @param repositoryFilter - 可选的实体过滤列表(用于 repository-level sync)
|
|
656
|
+
* @returns RxDBChange 记录数组,按 id ASC 排序
|
|
657
|
+
*
|
|
658
|
+
* @remarks
|
|
659
|
+
* 使用 id 而非 createdAt 作为游标,避免同毫秒内多条记录导致的重复问题
|
|
660
|
+
*/
|
|
661
|
+
async pullChanges(t, e = 1e3, s) {
|
|
662
|
+
const n = [];
|
|
663
|
+
let a = this.#t.from("RxDBChange").select("*").gt("id", t).order("id", { ascending: !0 }).limit(e);
|
|
664
|
+
s && s.length > 0 && (a = a.in("entity", s));
|
|
665
|
+
const { data: i, error: c } = await a;
|
|
666
|
+
if (c)
|
|
667
|
+
throw new g(`Failed to pull changes: ${c.message}`);
|
|
668
|
+
const o = (i ?? []).map((l) => ({
|
|
669
|
+
...l,
|
|
670
|
+
createdAt: new Date(l.createdAt),
|
|
671
|
+
updatedAt: l.updatedAt ? new Date(l.updatedAt) : null
|
|
672
|
+
}));
|
|
673
|
+
return n.push(...o), n;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* 获取远程变更数量(轻量级,不下载数据)(T042, US2)
|
|
677
|
+
*
|
|
678
|
+
* 此方法只查询远程有多少新变更,不返回实际数据。
|
|
679
|
+
* 用于实现 checkRepositoryUpdates() 功能,节省带宽。
|
|
680
|
+
*
|
|
681
|
+
* @param sinceId - 起始 changeId(不包含该 ID)
|
|
682
|
+
* @param repositoryFilter - 可选的实体过滤列表
|
|
683
|
+
* @returns 变更数量和最新 changeId
|
|
684
|
+
*
|
|
685
|
+
* @example
|
|
686
|
+
* ```typescript
|
|
687
|
+
* // 查询 Todo 实体的新变更数量
|
|
688
|
+
* const { count, latestChangeId } = await adapter.getChangeCount(100, ['Todo']);
|
|
689
|
+
* console.log(`有 ${count} 条新变更,最新 ID: ${latestChangeId}`);
|
|
690
|
+
* ```
|
|
691
|
+
*/
|
|
692
|
+
async getChangeCount(t, e) {
|
|
693
|
+
let s = this.#t.from("RxDBChange").select("*", { count: "exact", head: !0 }).gt("id", t);
|
|
694
|
+
e && e.length > 0 && (s = s.in("entity", e));
|
|
695
|
+
const { count: n, error: a } = await s;
|
|
696
|
+
if (a)
|
|
697
|
+
throw new g(`Failed to get change count: ${a.message}`);
|
|
698
|
+
let i = t;
|
|
699
|
+
if (n && n > 0) {
|
|
700
|
+
let c = this.#t.from("RxDBChange").select("id").gt("id", t).order("id", { ascending: !1 }).limit(1);
|
|
701
|
+
e && e.length > 0 && (c = c.in("entity", e));
|
|
702
|
+
const { data: o, error: l } = await c;
|
|
703
|
+
if (l)
|
|
704
|
+
throw new g(`Failed to get latest changeId: ${l.message}`);
|
|
705
|
+
o && o.length > 0 && (i = o[0].id);
|
|
706
|
+
}
|
|
707
|
+
return {
|
|
708
|
+
count: n ?? 0,
|
|
709
|
+
latestChangeId: i
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* 推送变更记录到远程(双写:RxDBChange 表 + 实体表)
|
|
714
|
+
*
|
|
715
|
+
* @deprecated 请使用 mergeChanges 代替,该方法不支持事务且效率较低
|
|
716
|
+
* @param changes - 待推送的变更(已压缩)
|
|
717
|
+
* @throws 当任何变更推送失败时抛出错误
|
|
718
|
+
*/
|
|
719
|
+
async pushChanges(t) {
|
|
720
|
+
if (t.length === 0) return;
|
|
721
|
+
const e = {
|
|
722
|
+
inserts: /* @__PURE__ */ new Map(),
|
|
723
|
+
updates: /* @__PURE__ */ new Map(),
|
|
724
|
+
deletes: /* @__PURE__ */ new Map()
|
|
725
|
+
};
|
|
726
|
+
for (const s of t) {
|
|
727
|
+
const { entityKey: n, finalType: a, finalPatch: i, inversePatch: c } = s;
|
|
728
|
+
if (a)
|
|
729
|
+
switch (a) {
|
|
730
|
+
case "INSERT":
|
|
731
|
+
e.inserts.set(n, { patch: i, inversePatch: c });
|
|
732
|
+
break;
|
|
733
|
+
case "UPDATE":
|
|
734
|
+
e.updates.set(n, { patch: i, inversePatch: c });
|
|
735
|
+
break;
|
|
736
|
+
case "DELETE":
|
|
737
|
+
e.deletes.set(n, { patch: null, inversePatch: c });
|
|
738
|
+
break;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
await this.mergeChanges(e);
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* 应用压缩后的变更到远程(事务)
|
|
745
|
+
*
|
|
746
|
+
* 通过 rxdb_mutations RPC 在单个事务中:
|
|
747
|
+
* 1. 写入 RxDBChange 表(用于其他客户端 pull)
|
|
748
|
+
* 2. 应用 actions 到实体表(INSERT/UPDATE/DELETE)
|
|
749
|
+
* 3. 自动跳过同步触发器(p_skip_sync=true)
|
|
750
|
+
*
|
|
751
|
+
* @param actions - 压缩后的变更操作集合
|
|
752
|
+
*/
|
|
753
|
+
async mergeChanges(t) {
|
|
754
|
+
const e = (/* @__PURE__ */ new Date()).toISOString(), s = this.rxdb.context.userId, n = [], a = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map();
|
|
755
|
+
for (const [d, { inversePatch: f }] of t.deletes) {
|
|
756
|
+
const [h, u, w] = d.split(":"), m = h ? `${h}.${u}` : u;
|
|
757
|
+
n.push({
|
|
758
|
+
namespace: h || "public",
|
|
759
|
+
entity: u,
|
|
760
|
+
entityId: w,
|
|
761
|
+
type: "DELETE",
|
|
762
|
+
patch: null,
|
|
763
|
+
inversePatch: f,
|
|
764
|
+
clientId: this.rxdb.context.clientId,
|
|
765
|
+
createdAt: e,
|
|
766
|
+
updatedAt: e
|
|
767
|
+
});
|
|
768
|
+
const y = i.get(m) ?? [];
|
|
769
|
+
y.push(w), i.set(m, y);
|
|
770
|
+
}
|
|
771
|
+
for (const [d, { patch: f, inversePatch: h }] of t.updates) {
|
|
772
|
+
const [u, w, m] = d.split(":"), y = u ? `${u}.${w}` : w;
|
|
773
|
+
n.push({
|
|
774
|
+
namespace: u || "public",
|
|
775
|
+
entity: w,
|
|
776
|
+
entityId: m,
|
|
777
|
+
type: "UPDATE",
|
|
778
|
+
patch: f,
|
|
779
|
+
inversePatch: h,
|
|
780
|
+
clientId: this.rxdb.context.clientId,
|
|
781
|
+
createdAt: e,
|
|
782
|
+
updatedAt: e
|
|
783
|
+
});
|
|
784
|
+
const $ = a.get(y) ?? [], _ = { id: m, ...f };
|
|
785
|
+
s && (_.updatedBy = s), $.push(_), a.set(y, $);
|
|
786
|
+
}
|
|
787
|
+
for (const [d, { patch: f, inversePatch: h }] of t.inserts) {
|
|
788
|
+
const [u, w, m] = d.split(":"), y = u ? `${u}.${w}` : w;
|
|
789
|
+
n.push({
|
|
790
|
+
namespace: u || "public",
|
|
791
|
+
entity: w,
|
|
792
|
+
entityId: m,
|
|
793
|
+
type: "INSERT",
|
|
794
|
+
patch: f,
|
|
795
|
+
inversePatch: h,
|
|
796
|
+
clientId: this.rxdb.context.clientId,
|
|
797
|
+
createdAt: e,
|
|
798
|
+
updatedAt: e
|
|
799
|
+
});
|
|
800
|
+
const $ = a.get(y) ?? [], _ = { id: m, ...f };
|
|
801
|
+
s && (_.createdBy = s, _.updatedBy = s), $.push(_), a.set(y, $);
|
|
802
|
+
}
|
|
803
|
+
const c = Array.from(a.entries()).map(([d, f]) => {
|
|
804
|
+
const [h, u] = d.includes(".") ? d.split(".") : ["public", d];
|
|
805
|
+
return { table: u, schema: h, data: f };
|
|
806
|
+
}), o = Array.from(i.entries()).map(([d, f]) => {
|
|
807
|
+
const [h, u] = d.includes(".") ? d.split(".") : ["public", d];
|
|
808
|
+
return { table: u, schema: h, ids: f };
|
|
809
|
+
}), { data: l, error: p } = await this.#t.rpc("rxdb_mutations", {
|
|
810
|
+
p_upserts: c,
|
|
811
|
+
p_deletes: o,
|
|
812
|
+
p_changes: n,
|
|
813
|
+
p_skip_sync: !0
|
|
814
|
+
});
|
|
815
|
+
if (p)
|
|
816
|
+
throw new g(`Failed to merge changes: ${p.message}`);
|
|
817
|
+
return l?.max_change_id ?? void 0;
|
|
818
|
+
}
|
|
819
|
+
// ============================================
|
|
820
|
+
// 私有方法
|
|
821
|
+
// ============================================
|
|
822
|
+
/** 获取带 schema 的客户端 */
|
|
823
|
+
getSchemaClient(t) {
|
|
824
|
+
return t ? this.#t.schema(t) : this.#t;
|
|
825
|
+
}
|
|
826
|
+
/** 执行 upsert(非事务) */
|
|
827
|
+
async executeUpsert(t) {
|
|
828
|
+
const e = [], s = this.rxdb.context.userId;
|
|
829
|
+
for (const [n, a] of t) {
|
|
830
|
+
const i = b(n), c = this.getSchemaClient(i.namespace), o = Array.from(a), l = s ? o.map((f) => ({ ...f, createdBy: s, updatedBy: s })) : o, { data: p, error: d } = await c.from(i.name).upsert(l).select();
|
|
831
|
+
if (d)
|
|
832
|
+
throw new g(`Failed to upsert: ${d.message}`);
|
|
833
|
+
e.push(...p);
|
|
834
|
+
}
|
|
835
|
+
return e;
|
|
836
|
+
}
|
|
837
|
+
/** 执行 delete(非事务) */
|
|
838
|
+
async executeDelete(t) {
|
|
839
|
+
const e = [];
|
|
840
|
+
for (const [s, n] of t) {
|
|
841
|
+
const a = b(s), i = this.getSchemaClient(a.namespace), c = Array.from(n), o = c.map((p) => p.id), { error: l } = await i.from(a.name).delete().in("id", o);
|
|
842
|
+
if (l)
|
|
843
|
+
throw new g(`Failed to delete: ${l.message}`);
|
|
844
|
+
e.push(...c);
|
|
845
|
+
}
|
|
846
|
+
return e;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
export {
|
|
850
|
+
Y as ADAPTER_NAME,
|
|
851
|
+
et as RxDBAdapterSupabase,
|
|
852
|
+
q as SupabaseConfigError,
|
|
853
|
+
g as SupabaseDataError,
|
|
854
|
+
tt as SupabaseNetworkError,
|
|
855
|
+
F as SupabaseRepository,
|
|
856
|
+
S as SupabaseSyncError,
|
|
857
|
+
H as SupabaseTreeRepository
|
|
858
|
+
};
|