@aiao/rxdb-adapter-supabase 0.0.8 → 0.0.10
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.
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { EntityType, IRepository, IRxDBAdapter, RemoteChange, RxDB, RxDBMutationsMap, SwitchVersionActions, RxDBAdapterRemoteBase } from '../packages/rxdb/src/index.ts';
|
|
1
|
+
import { EntityType, IRepository, IRxDBAdapter, QueryCacheEntityMetadata, RemoteChange, RuleGroup, RxDB, RxDBMutationsMap, SwitchVersionActions, RxDBAdapterRemoteBase } from '../packages/rxdb/src/index.ts';
|
|
2
2
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
3
|
+
import { Observable } from 'rxjs';
|
|
3
4
|
import { SupabaseAdapterOptions } from './supabase.interface.js';
|
|
4
5
|
export declare const ADAPTER_NAME = "supabase";
|
|
5
6
|
/**
|
|
@@ -49,12 +50,16 @@ export declare class RxDBAdapterSupabase extends RxDBAdapterRemoteBase implement
|
|
|
49
50
|
* @param sinceId - 拉取此 ID 之后的变更(不包含该 ID)
|
|
50
51
|
* @param limit - 最大拉取数量
|
|
51
52
|
* @param repositoryFilter - 可选的实体过滤列表(用于 repository-level sync)
|
|
53
|
+
* @param filter - 可选的行级过滤条件(用于 SyncType.Filter)
|
|
52
54
|
* @returns RxDBChange 记录数组,按 id ASC 排序
|
|
53
55
|
*
|
|
54
56
|
* @remarks
|
|
55
57
|
* 使用 id 而非 createdAt 作为游标,避免同毫秒内多条记录导致的重复问题
|
|
58
|
+
*
|
|
59
|
+
* 当提供 filter 参数时,会通过 JOIN 实体表并应用过滤条件,
|
|
60
|
+
* 只返回满足条件的实体对应的变更记录。
|
|
56
61
|
*/
|
|
57
|
-
pullChanges(sinceId: number, limit?: number, repositoryFilter?: string[]): Promise<RemoteChange[]>;
|
|
62
|
+
pullChanges(sinceId: number, limit?: number, repositoryFilter?: string[], filter?: RuleGroup<any>): Promise<RemoteChange[]>;
|
|
58
63
|
/**
|
|
59
64
|
* 获取远程变更数量(轻量级,不下载数据)(T042, US2)
|
|
60
65
|
*
|
|
@@ -95,6 +100,30 @@ export declare class RxDBAdapterSupabase extends RxDBAdapterRemoteBase implement
|
|
|
95
100
|
* @param actions - 压缩后的变更操作集合
|
|
96
101
|
*/
|
|
97
102
|
mergeChanges(actions: SwitchVersionActions): Promise<any>;
|
|
103
|
+
/**
|
|
104
|
+
* 获取实体元数据,用于新鲜度比较(QueryCache 专用)
|
|
105
|
+
*
|
|
106
|
+
* 只返回 `{ id, updatedAt }` 元数据,网络传输量比完整数据减少 90%+。
|
|
107
|
+
*
|
|
108
|
+
* @param entityName - 实体名称
|
|
109
|
+
* @param query - 查询条件
|
|
110
|
+
* @returns Observable<QueryCacheEntityMetadata[]>
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* adapter.fetchMetadata('Product', { combinator: 'and', rules: [{ field: 'status', operator: 'eq', value: 'active' }] })
|
|
115
|
+
* .subscribe(metadata => console.log(metadata));
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
fetchMetadata(entityName: string, queryFilter: RuleGroup<unknown>): Observable<QueryCacheEntityMetadata[]>;
|
|
119
|
+
/**
|
|
120
|
+
* 按 ID 列表批量获取完整数据(QueryCache 专用)
|
|
121
|
+
*
|
|
122
|
+
* @param entityName - 实体名称
|
|
123
|
+
* @param ids - 需要获取的实体 ID 列表
|
|
124
|
+
* @returns Observable<T[]>
|
|
125
|
+
*/
|
|
126
|
+
findByIds<T>(entityName: string, ids: string[]): Observable<T[]>;
|
|
98
127
|
/** 获取带 schema 的客户端 */
|
|
99
128
|
private getSchemaClient;
|
|
100
129
|
/** 执行 upsert(非事务) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RxDBAdapterSupabase.d.ts","sourceRoot":"","sources":["../src/RxDBAdapterSupabase.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,IAAI,EACJ,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAqB,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAiC,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"RxDBAdapterSupabase.d.ts","sourceRoot":"","sources":["../src/RxDBAdapterSupabase.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SupabaseRepository.d.ts","sourceRoot":"","sources":["../src/SupabaseRepository.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAqB,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"SupabaseRepository.d.ts","sourceRoot":"","sources":["../src/SupabaseRepository.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAqB,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGpE;;;GAGG;AACH,qBAAa,kBAAkB,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAE,YAAW,WAAW,CAAC,CAAC,CAAC;IAIrG,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,mBAAmB;IAHjD,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;gBAGvB,OAAO,EAAE,mBAAmB,EAC/C,UAAU,EAAE,CAAC;IAMf;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,EAAE,aAAa,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAsCnF;;OAEG;IACG,KAAK,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IA2B1E;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAW/D;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAMhG;;;;OAIG;IACG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAU/D,6CAA6C;IAC7C,OAAO,CAAC,uBAAuB;IAgC/B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA2B7B;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAuBpC,qBAAqB;IACrB,OAAO,CAAC,sBAAsB;IAY9B,yBAAyB;IACzB,OAAO,CAAC,mBAAmB;IAI3B,0BAA0B;IAC1B,OAAO,CAAC,UAAU;CAGnB"}
|
package/dist/index.js
CHANGED
|
@@ -1,85 +1,54 @@
|
|
|
1
|
-
import { EntityRemoteRemovedEvent as
|
|
2
|
-
import { createClient as
|
|
1
|
+
import { EntityRemoteRemovedEvent as O, EntityRemoteUpdatedEvent as W, EntityRemoteCreatedEvent as U, isRuleGroup as A, getEntityMetadata as b, PropertyType as E, RepositoryBase as K, RxDBAdapterRemoteBase as z } from "@aiao/rxdb";
|
|
2
|
+
import { createClient as L } from "@supabase/supabase-js";
|
|
3
|
+
import { defer as D, from as k, map as N, of as Q } from "rxjs";
|
|
3
4
|
class S extends Error {
|
|
4
5
|
constructor(t, e) {
|
|
5
6
|
super(t), this.code = e, this.name = "SupabaseSyncError";
|
|
6
7
|
}
|
|
7
8
|
}
|
|
8
|
-
class
|
|
9
|
+
class at extends S {
|
|
9
10
|
constructor(t) {
|
|
10
11
|
super(t, "CONFIG_ERROR"), this.name = "SupabaseConfigError";
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
|
-
class
|
|
14
|
+
class rt extends S {
|
|
14
15
|
constructor(t) {
|
|
15
16
|
super(t, "NETWORK_ERROR"), this.name = "SupabaseNetworkError";
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
|
-
class
|
|
19
|
+
class m extends S {
|
|
19
20
|
constructor(t) {
|
|
20
21
|
super(t, "DATA_ERROR"), this.name = "SupabaseDataError";
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
|
-
const
|
|
24
|
-
INSERT:
|
|
25
|
-
UPDATE:
|
|
26
|
-
DELETE:
|
|
24
|
+
const V = {
|
|
25
|
+
INSERT: U,
|
|
26
|
+
UPDATE: W,
|
|
27
|
+
DELETE: O
|
|
27
28
|
};
|
|
28
|
-
function
|
|
29
|
+
function J(i, t) {
|
|
29
30
|
if (t.table !== "RxDBChange" || t.eventType !== "INSERT") return;
|
|
30
31
|
const e = t.new;
|
|
31
32
|
if (!e) return;
|
|
32
|
-
const { namespace: s, entity: n, entityId: a, type:
|
|
33
|
-
if (
|
|
34
|
-
const
|
|
35
|
-
if (!
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
new
|
|
33
|
+
const { namespace: s, entity: n, entityId: a, type: r, patch: o, clientId: c } = e, d = i.rxdb.context.clientId;
|
|
34
|
+
if (c && d && c === d || !a || !r) return;
|
|
35
|
+
const u = V[r];
|
|
36
|
+
if (!u) return;
|
|
37
|
+
const l = { id: a, ...o };
|
|
38
|
+
i.rxdb.dispatchEvent(
|
|
39
|
+
new u([
|
|
39
40
|
{
|
|
40
|
-
type:
|
|
41
|
+
type: r,
|
|
41
42
|
namespace: s || "public",
|
|
42
43
|
entity: n,
|
|
43
44
|
id: a,
|
|
44
|
-
data:
|
|
45
|
+
data: l,
|
|
45
46
|
recordAt: e.createdAt ? new Date(e.createdAt) : /* @__PURE__ */ new Date()
|
|
46
47
|
}
|
|
47
48
|
])
|
|
48
49
|
);
|
|
49
50
|
}
|
|
50
|
-
|
|
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 = {
|
|
51
|
+
const X = {
|
|
83
52
|
"=": "eq",
|
|
84
53
|
"!=": "neq",
|
|
85
54
|
"<": "lt",
|
|
@@ -92,22 +61,22 @@ const V = {
|
|
|
92
61
|
startsWith: "ilike",
|
|
93
62
|
endsWith: "ilike"
|
|
94
63
|
};
|
|
95
|
-
function C(
|
|
96
|
-
return
|
|
64
|
+
function C(i) {
|
|
65
|
+
return i instanceof Date ? i.toISOString() : Array.isArray(i) ? i.map(C) : i;
|
|
97
66
|
}
|
|
98
|
-
function
|
|
99
|
-
return !t || !
|
|
67
|
+
function B(i, t, e) {
|
|
68
|
+
return !t || !i.mappedEntity ? e : t.getEntityMetadata(i.mappedEntity, i.mappedNamespace ?? "") ?? e;
|
|
100
69
|
}
|
|
101
|
-
function
|
|
70
|
+
function H(i, t) {
|
|
102
71
|
const e = C(t);
|
|
103
|
-
switch (
|
|
72
|
+
switch (i) {
|
|
104
73
|
case "=":
|
|
105
74
|
case "!=":
|
|
106
75
|
case "<":
|
|
107
76
|
case "<=":
|
|
108
77
|
case ">":
|
|
109
78
|
case ">=":
|
|
110
|
-
return `${
|
|
79
|
+
return `${X[i]}.${e}`;
|
|
111
80
|
case "in":
|
|
112
81
|
if (!Array.isArray(e)) throw new Error("IN operator requires array");
|
|
113
82
|
return `in.(${e.join(",")})`;
|
|
@@ -119,163 +88,192 @@ function N(r, t) {
|
|
|
119
88
|
case "endsWith":
|
|
120
89
|
return `ilike.*${e}`;
|
|
121
90
|
default:
|
|
122
|
-
throw new Error(`Unsupported operator: ${
|
|
91
|
+
throw new Error(`Unsupported operator: ${i}`);
|
|
123
92
|
}
|
|
124
93
|
}
|
|
125
|
-
function
|
|
126
|
-
const [s, ...n] =
|
|
127
|
-
return n.length === 0 ? { field:
|
|
94
|
+
function F(i, t, e) {
|
|
95
|
+
const [s, ...n] = i.split(".");
|
|
96
|
+
return n.length === 0 ? { field: i, operator: t, value: e } : {
|
|
128
97
|
field: s,
|
|
129
98
|
operator: "exists",
|
|
130
|
-
where: { combinator: "and", rules: [
|
|
99
|
+
where: { combinator: "and", rules: [F(n.join("."), t, e)] }
|
|
131
100
|
};
|
|
132
101
|
}
|
|
133
|
-
function
|
|
134
|
-
if (!t?.rules?.length) return
|
|
102
|
+
function $(i, t, e, s) {
|
|
103
|
+
if (!t?.rules?.length) return i;
|
|
135
104
|
if (t.rules.length === 1) {
|
|
136
105
|
const a = t.rules[0];
|
|
137
|
-
return
|
|
106
|
+
return A(a) ? $(i, a, e, s) : I(i, a, e, s);
|
|
138
107
|
}
|
|
139
108
|
if (t.combinator === "and")
|
|
140
109
|
return t.rules.reduce(
|
|
141
|
-
(a,
|
|
142
|
-
|
|
110
|
+
(a, r) => A(r) ? $(a, r, e, s) : I(a, r, e, s),
|
|
111
|
+
i
|
|
143
112
|
);
|
|
144
113
|
const n = t.rules.map((a) => {
|
|
145
|
-
if (
|
|
146
|
-
const { field:
|
|
147
|
-
return `${
|
|
114
|
+
if (A(a)) throw new Error("Nested OR conditions not supported");
|
|
115
|
+
const { field: r, operator: o, value: c } = a;
|
|
116
|
+
return `${r}.${H(o, c)}`;
|
|
148
117
|
});
|
|
149
|
-
return
|
|
118
|
+
return i.or(n.join(","));
|
|
150
119
|
}
|
|
151
|
-
function
|
|
152
|
-
const { field: n, operator: a, value:
|
|
153
|
-
return typeof n == "string" && n.includes(".") ?
|
|
120
|
+
function I(i, t, e, s) {
|
|
121
|
+
const { field: n, operator: a, value: r } = t;
|
|
122
|
+
return typeof n == "string" && n.includes(".") ? I(i, F(n, a, r), e, s) : a === "exists" || a === "notExists" ? Y(i, t, e, s) : M(i, n, a, r);
|
|
154
123
|
}
|
|
155
|
-
function
|
|
156
|
-
const { field: n, operator: a } = t,
|
|
157
|
-
if (!
|
|
158
|
-
throw new Error(`Relation '${
|
|
159
|
-
const
|
|
160
|
-
if (!
|
|
161
|
-
return a === "exists" ?
|
|
162
|
-
const
|
|
163
|
-
if (!
|
|
164
|
-
return
|
|
124
|
+
function Y(i, t, e, s) {
|
|
125
|
+
const { field: n, operator: a } = t, r = t.where, o = String(n), c = e?.relationMap?.get(o);
|
|
126
|
+
if (!c)
|
|
127
|
+
throw new Error(`Relation '${o}' not found in '${e?.name || "unknown"}'`);
|
|
128
|
+
const d = c.mappedEntity;
|
|
129
|
+
if (!r?.rules?.length)
|
|
130
|
+
return a === "exists" ? i.not(d, "is", null) : i.is(d, null);
|
|
131
|
+
const u = e ? B(c, s, e) : void 0;
|
|
132
|
+
if (!u) throw new Error(`Cannot resolve metadata for '${o}'`);
|
|
133
|
+
return R(i, d, r, u, s, d);
|
|
165
134
|
}
|
|
166
|
-
function
|
|
167
|
-
if (!e?.rules?.length) return
|
|
168
|
-
let
|
|
169
|
-
for (const
|
|
170
|
-
if (
|
|
171
|
-
|
|
135
|
+
function R(i, t, e, s, n, a = "") {
|
|
136
|
+
if (!e?.rules?.length) return i;
|
|
137
|
+
let r = i;
|
|
138
|
+
for (const o of e.rules) {
|
|
139
|
+
if (A(o)) {
|
|
140
|
+
r = R(r, t, o, s, n, a);
|
|
172
141
|
continue;
|
|
173
142
|
}
|
|
174
|
-
const { field:
|
|
175
|
-
if (
|
|
176
|
-
const
|
|
177
|
-
if (!
|
|
178
|
-
const
|
|
179
|
-
if (
|
|
180
|
-
const
|
|
181
|
-
|
|
143
|
+
const { field: c, operator: d, value: u } = o;
|
|
144
|
+
if (d === "exists" || d === "notExists") {
|
|
145
|
+
const p = s?.relationMap?.get(String(c));
|
|
146
|
+
if (!p) throw new Error(`Relation '${c}' not found in ${t}`);
|
|
147
|
+
const f = p.mappedEntity, h = o.where, y = B(p, n, s);
|
|
148
|
+
if (h?.rules?.length) {
|
|
149
|
+
const g = a ? `${a}.${f}` : f;
|
|
150
|
+
r = R(r, f, h, y, n, g);
|
|
182
151
|
} else
|
|
183
|
-
|
|
152
|
+
r = d === "exists" ? r.not(f, "is", null) : r.is(f, null);
|
|
184
153
|
continue;
|
|
185
154
|
}
|
|
186
|
-
const
|
|
187
|
-
|
|
155
|
+
const l = a ? `${a}.${c}` : `${t}.${c}`;
|
|
156
|
+
r = M(r, l, d, u);
|
|
188
157
|
}
|
|
189
|
-
return
|
|
158
|
+
return r;
|
|
190
159
|
}
|
|
191
|
-
function
|
|
160
|
+
function M(i, t, e, s) {
|
|
192
161
|
const n = C(s);
|
|
193
|
-
if (t.includes(".")) {
|
|
194
|
-
|
|
195
|
-
|
|
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;
|
|
162
|
+
if (t.includes(".") && e === "between") {
|
|
163
|
+
const [r, o] = n;
|
|
164
|
+
return i.gte(t, r).lte(t, o);
|
|
201
165
|
}
|
|
202
166
|
switch (e) {
|
|
203
167
|
case "=":
|
|
204
|
-
return n === null ?
|
|
168
|
+
return n === null ? i.is(t, null) : i.eq(t, n);
|
|
205
169
|
case "!=":
|
|
206
|
-
return n === null ?
|
|
170
|
+
return n === null ? i.not(t, "is", null) : i.neq(t, n);
|
|
207
171
|
case "<":
|
|
208
|
-
return
|
|
172
|
+
return i.lt(t, n);
|
|
209
173
|
case ">":
|
|
210
|
-
return
|
|
174
|
+
return i.gt(t, n);
|
|
211
175
|
case "<=":
|
|
212
|
-
return
|
|
176
|
+
return i.lte(t, n);
|
|
213
177
|
case ">=":
|
|
214
|
-
return
|
|
178
|
+
return i.gte(t, n);
|
|
215
179
|
case "in":
|
|
216
|
-
return
|
|
180
|
+
return i.in(t, n);
|
|
217
181
|
case "notIn":
|
|
218
|
-
return
|
|
182
|
+
return i.not(t, "in", `(${n.join(",")})`);
|
|
219
183
|
case "contains":
|
|
220
184
|
case "includes":
|
|
221
|
-
return
|
|
185
|
+
return i.ilike(t, `%${n}%`);
|
|
222
186
|
case "notContains":
|
|
223
|
-
return
|
|
187
|
+
return i.not(t, "ilike", `%${n}%`);
|
|
224
188
|
case "startsWith":
|
|
225
|
-
return
|
|
189
|
+
return i.ilike(t, `${n}%`);
|
|
226
190
|
case "notStartsWith":
|
|
227
|
-
return
|
|
191
|
+
return i.not(t, "ilike", `${n}%`);
|
|
228
192
|
case "endsWith":
|
|
229
|
-
return
|
|
193
|
+
return i.ilike(t, `%${n}`);
|
|
230
194
|
case "notEndsWith":
|
|
231
|
-
return
|
|
195
|
+
return i.not(t, "ilike", `%${n}`);
|
|
232
196
|
case "between": {
|
|
233
|
-
const [
|
|
234
|
-
return
|
|
197
|
+
const [r, o] = n;
|
|
198
|
+
return i.gte(t, r).lte(t, o);
|
|
235
199
|
}
|
|
236
200
|
case "notBetween": {
|
|
237
|
-
const [
|
|
238
|
-
return
|
|
201
|
+
const [r, o] = n;
|
|
202
|
+
return i.or(`${t}.lt.${r},${t}.gt.${o}`);
|
|
239
203
|
}
|
|
204
|
+
case "null":
|
|
240
205
|
case "isNull":
|
|
241
|
-
return
|
|
206
|
+
return i.is(t, null);
|
|
207
|
+
case "notNull":
|
|
242
208
|
case "isNotNull":
|
|
243
|
-
return
|
|
209
|
+
return i.not(t, "is", null);
|
|
244
210
|
default:
|
|
245
211
|
throw new Error(`Unsupported operator: ${e}`);
|
|
246
212
|
}
|
|
247
213
|
}
|
|
248
|
-
function
|
|
249
|
-
|
|
214
|
+
function T(i) {
|
|
215
|
+
const t = /* @__PURE__ */ new Map();
|
|
216
|
+
for (const e of i) {
|
|
217
|
+
const s = e.constructor;
|
|
218
|
+
t.has(s) || t.set(s, /* @__PURE__ */ new Set()), t.get(s).add(e);
|
|
219
|
+
}
|
|
220
|
+
return t;
|
|
221
|
+
}
|
|
222
|
+
function v(i, t) {
|
|
223
|
+
const e = [];
|
|
224
|
+
for (const [s, n] of i) {
|
|
225
|
+
const a = b(s), r = Array.from(n);
|
|
226
|
+
e.push({
|
|
227
|
+
table: a.name,
|
|
228
|
+
schema: a.namespace,
|
|
229
|
+
data: t ? r.map((o) => ({ ...o, createdBy: t, updatedBy: t })) : r
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
return e;
|
|
233
|
+
}
|
|
234
|
+
function Z(i) {
|
|
235
|
+
const t = [];
|
|
236
|
+
for (const [e, s] of i) {
|
|
237
|
+
const n = b(e);
|
|
238
|
+
t.push({
|
|
239
|
+
table: n.name,
|
|
240
|
+
schema: n.namespace,
|
|
241
|
+
ids: Array.from(s).map((a) => a.id)
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return t;
|
|
245
|
+
}
|
|
246
|
+
function j(i, t) {
|
|
247
|
+
if (i == null) return i;
|
|
250
248
|
switch (t.type) {
|
|
251
249
|
case E.date:
|
|
252
|
-
return
|
|
250
|
+
return i instanceof Date ? i : new Date(i);
|
|
253
251
|
case E.keyValue:
|
|
254
|
-
if (typeof
|
|
252
|
+
if (typeof i == "object" && t.properties) {
|
|
255
253
|
const e = {};
|
|
256
254
|
for (const s of t.properties)
|
|
257
|
-
|
|
255
|
+
i[s.name] !== void 0 && (e[s.name] = j(i[s.name], s));
|
|
258
256
|
return e;
|
|
259
257
|
}
|
|
260
|
-
return
|
|
258
|
+
return i;
|
|
261
259
|
case E.boolean:
|
|
262
|
-
return !!
|
|
260
|
+
return !!i;
|
|
263
261
|
case E.json:
|
|
264
262
|
case E.stringArray:
|
|
265
263
|
case E.numberArray:
|
|
266
264
|
default:
|
|
267
|
-
return
|
|
265
|
+
return i;
|
|
268
266
|
}
|
|
269
267
|
}
|
|
270
|
-
function
|
|
271
|
-
const s = new
|
|
268
|
+
function G(i, t, e) {
|
|
269
|
+
const s = new i();
|
|
272
270
|
for (const n of Object.keys(e)) {
|
|
273
271
|
const a = t.propertyMap.get(n);
|
|
274
|
-
s[n] = a ?
|
|
272
|
+
s[n] = a ? j(e[n], a) : e[n];
|
|
275
273
|
}
|
|
276
274
|
return s;
|
|
277
275
|
}
|
|
278
|
-
class
|
|
276
|
+
class P extends K {
|
|
279
277
|
constructor(t, e) {
|
|
280
278
|
super(t.rxdb, e), this.adapter = t, this.metadata = b(e);
|
|
281
279
|
}
|
|
@@ -287,22 +285,22 @@ class F extends W {
|
|
|
287
285
|
const e = this.extract_relation_fields(t.where);
|
|
288
286
|
let s = "*";
|
|
289
287
|
if (e.size > 0) {
|
|
290
|
-
const
|
|
291
|
-
s = `*, ${
|
|
292
|
-
(
|
|
293
|
-
).map((
|
|
288
|
+
const o = Array.from(e);
|
|
289
|
+
s = `*, ${o.filter(
|
|
290
|
+
(d) => !o.some((u) => u !== d && u.startsWith(d + "."))
|
|
291
|
+
).map((d) => this.build_relation_select(d)).join(", ")}`;
|
|
294
292
|
}
|
|
295
293
|
let n = this.get_client().select(s);
|
|
296
|
-
if (n =
|
|
297
|
-
for (const
|
|
298
|
-
n = n.order(
|
|
294
|
+
if (n = $(n, t.where, this.metadata, this.adapter.rxdb.schemaManager), t.orderBy?.length)
|
|
295
|
+
for (const o of t.orderBy)
|
|
296
|
+
n = n.order(o.field, { ascending: o.sort === "asc" });
|
|
299
297
|
if (t.offset !== void 0) {
|
|
300
|
-
const
|
|
301
|
-
n = n.range(
|
|
298
|
+
const o = t.offset, c = t.limit !== void 0 ? o + t.limit - 1 : Number.MAX_SAFE_INTEGER;
|
|
299
|
+
n = n.range(o, c);
|
|
302
300
|
} else t.limit !== void 0 && (n = n.limit(t.limit));
|
|
303
|
-
const { data: a, error:
|
|
304
|
-
if (
|
|
305
|
-
return (a || []).map((
|
|
301
|
+
const { data: a, error: r } = await n;
|
|
302
|
+
if (r) throw new m(`Failed to find entities: ${r.message}`);
|
|
303
|
+
return (a || []).map((o) => G(this.EntityType, this.metadata, o));
|
|
306
304
|
}
|
|
307
305
|
/**
|
|
308
306
|
* 查询实体数量
|
|
@@ -311,14 +309,14 @@ class F extends W {
|
|
|
311
309
|
if (t.groupBy) throw new Error("groupBy not supported yet");
|
|
312
310
|
const e = this.extract_relation_fields(t.where);
|
|
313
311
|
let s = "*";
|
|
314
|
-
e.size > 0 && (s = `*, ${Array.from(e).map((
|
|
312
|
+
e.size > 0 && (s = `*, ${Array.from(e).map((o) => this.build_relation_select(o)).join(", ")}`);
|
|
315
313
|
let n = this.get_client().select(s, { count: "exact", head: !0 });
|
|
316
|
-
n =
|
|
317
|
-
const { count: a, error:
|
|
318
|
-
if (
|
|
319
|
-
if (!
|
|
314
|
+
n = $(n, t.where, this.metadata, this.adapter.rxdb.schemaManager);
|
|
315
|
+
const { count: a, error: r } = await n;
|
|
316
|
+
if (r) {
|
|
317
|
+
if (!r.message)
|
|
320
318
|
return console.warn("Supabase count returned empty error, returning 0. Options:", JSON.stringify(t)), 0;
|
|
321
|
-
throw new
|
|
319
|
+
throw new m(`Failed to count entities: ${r.message}`);
|
|
322
320
|
}
|
|
323
321
|
return a ?? 0;
|
|
324
322
|
}
|
|
@@ -329,7 +327,7 @@ class F extends W {
|
|
|
329
327
|
const e = { ...t }, s = this.rxdb.context.userId;
|
|
330
328
|
s && (e.createdBy = s);
|
|
331
329
|
const { data: n, error: a } = await this.get_client().insert(e).select().single();
|
|
332
|
-
if (a) throw new
|
|
330
|
+
if (a) throw new m(`Failed to create entity: ${a.message}`);
|
|
333
331
|
return n;
|
|
334
332
|
}
|
|
335
333
|
/**
|
|
@@ -337,7 +335,7 @@ class F extends W {
|
|
|
337
335
|
*/
|
|
338
336
|
async update(t, e) {
|
|
339
337
|
const { data: s, error: n } = await this.get_client().update(e).eq("id", t.id).select().single();
|
|
340
|
-
if (n) throw new
|
|
338
|
+
if (n) throw new m(`Failed to update entity: ${n.message}`);
|
|
341
339
|
return s;
|
|
342
340
|
}
|
|
343
341
|
/**
|
|
@@ -347,7 +345,7 @@ class F extends W {
|
|
|
347
345
|
*/
|
|
348
346
|
async remove(t) {
|
|
349
347
|
const { error: e } = await this.get_client().delete().eq("id", t.id);
|
|
350
|
-
if (e) throw new
|
|
348
|
+
if (e) throw new m(`Failed to remove entity: ${e.message}`);
|
|
351
349
|
return t;
|
|
352
350
|
}
|
|
353
351
|
// ============================================
|
|
@@ -357,18 +355,18 @@ class F extends W {
|
|
|
357
355
|
extract_relation_fields(t) {
|
|
358
356
|
const e = /* @__PURE__ */ new Set(), s = (n, a = "") => {
|
|
359
357
|
if (n?.rules) {
|
|
360
|
-
for (const
|
|
361
|
-
if (
|
|
362
|
-
s(
|
|
363
|
-
else if (typeof
|
|
364
|
-
const
|
|
365
|
-
for (let
|
|
366
|
-
const
|
|
367
|
-
e.add(a ? `${a}.${
|
|
358
|
+
for (const r of n.rules)
|
|
359
|
+
if (r.rules)
|
|
360
|
+
s(r, a);
|
|
361
|
+
else if (typeof r.field == "string" && r.field.includes(".")) {
|
|
362
|
+
const o = r.field.split(".");
|
|
363
|
+
for (let c = 1; c < o.length; c++) {
|
|
364
|
+
const d = o.slice(0, c).join(".");
|
|
365
|
+
e.add(a ? `${a}.${d}` : d);
|
|
368
366
|
}
|
|
369
|
-
} else if (
|
|
370
|
-
const
|
|
371
|
-
this.metadata.relationMap?.has(
|
|
367
|
+
} else if (r.operator === "exists" || r.operator === "notExists") {
|
|
368
|
+
const o = String(r.field), c = a ? `${a}.${o}` : o;
|
|
369
|
+
this.metadata.relationMap?.has(o) && e.add(c), r.where && s(r.where, c);
|
|
372
370
|
}
|
|
373
371
|
}
|
|
374
372
|
};
|
|
@@ -383,16 +381,16 @@ class F extends W {
|
|
|
383
381
|
if (e.length === 1) return this.build_single_relation_select(e[0]);
|
|
384
382
|
const s = [];
|
|
385
383
|
let n = this.metadata;
|
|
386
|
-
for (const
|
|
387
|
-
const
|
|
388
|
-
if (!
|
|
389
|
-
s.push({ tableName:
|
|
390
|
-
const
|
|
391
|
-
|
|
384
|
+
for (const r of e) {
|
|
385
|
+
const o = n.relationMap?.get(r);
|
|
386
|
+
if (!o) return `${r}(id)`;
|
|
387
|
+
s.push({ tableName: o.mappedEntity, kind: o.kind, sourceEntity: n.name });
|
|
388
|
+
const c = this.adapter.rxdb.schemaManager.getEntityMetadata(o.mappedEntity, o.mappedNamespace ?? "");
|
|
389
|
+
c && (n = c);
|
|
392
390
|
}
|
|
393
391
|
let a = this.build_relation_segment(s[s.length - 1], !0);
|
|
394
|
-
for (let
|
|
395
|
-
a = this.build_relation_segment(s[
|
|
392
|
+
for (let r = s.length - 2; r >= 0; r--)
|
|
393
|
+
a = this.build_relation_segment(s[r], !0).replace("(*)", `(*, ${a})`);
|
|
396
394
|
return a;
|
|
397
395
|
}
|
|
398
396
|
/**
|
|
@@ -431,7 +429,7 @@ class F extends W {
|
|
|
431
429
|
return this.adapter.client.schema(this.metadata.namespace).from(this.metadata.name);
|
|
432
430
|
}
|
|
433
431
|
}
|
|
434
|
-
class
|
|
432
|
+
class q extends P {
|
|
435
433
|
constructor(t, e) {
|
|
436
434
|
super(t, e);
|
|
437
435
|
}
|
|
@@ -450,9 +448,9 @@ class H extends F {
|
|
|
450
448
|
if (a) {
|
|
451
449
|
if (a.message.includes("function") || a.message.includes("Could not find"))
|
|
452
450
|
return this.findDescendantsFallback(t);
|
|
453
|
-
throw new
|
|
451
|
+
throw new m(`Failed to find descendants: ${a.message}`);
|
|
454
452
|
}
|
|
455
|
-
return (n || []).map((
|
|
453
|
+
return (n || []).map((r) => this.transformRowToEntity(r));
|
|
456
454
|
}
|
|
457
455
|
/**
|
|
458
456
|
* 查询子孙节点数量
|
|
@@ -482,9 +480,9 @@ class H extends F {
|
|
|
482
480
|
if (a) {
|
|
483
481
|
if (a.message.includes("function") || a.message.includes("Could not find"))
|
|
484
482
|
return this.findAncestorsFallback(t);
|
|
485
|
-
throw new
|
|
483
|
+
throw new m(`Failed to find ancestors: ${a.message}`);
|
|
486
484
|
}
|
|
487
|
-
return (n || []).map((
|
|
485
|
+
return (n || []).map((r) => this.transformRowToEntity(r));
|
|
488
486
|
}
|
|
489
487
|
/**
|
|
490
488
|
* 查询祖先节点数量
|
|
@@ -504,28 +502,28 @@ class H extends F {
|
|
|
504
502
|
* 优化方案:一次查询获取所有节点,在内存中构建树结构。
|
|
505
503
|
*/
|
|
506
504
|
async findDescendantsFallback(t) {
|
|
507
|
-
const { entityId: e, level: s = 100 } = t, n = this.metadata.name, a = this.metadata.features?.tree?.hasChildren,
|
|
508
|
-
let
|
|
509
|
-
e ?
|
|
510
|
-
const { data:
|
|
511
|
-
if (
|
|
512
|
-
throw new
|
|
513
|
-
const
|
|
514
|
-
for (const
|
|
515
|
-
if (
|
|
516
|
-
|
|
517
|
-
const
|
|
505
|
+
const { entityId: e, level: s = 100 } = t, n = this.metadata.name, a = this.metadata.features?.tree?.hasChildren, r = [], o = /* @__PURE__ */ new Set();
|
|
506
|
+
let c = this.adapter.client.schema("public").from(n).select("*");
|
|
507
|
+
e ? c = c.eq("id", e) : c = c.is("parentId", null);
|
|
508
|
+
const { data: d, error: u } = await c;
|
|
509
|
+
if (u)
|
|
510
|
+
throw new m(`Failed to find start nodes: ${u.message}`);
|
|
511
|
+
const l = async (p, f) => {
|
|
512
|
+
for (const h of p) {
|
|
513
|
+
if (o.has(h.id) || f > s) continue;
|
|
514
|
+
o.add(h.id);
|
|
515
|
+
const y = this.transformRowToEntity(h);
|
|
518
516
|
if (a) {
|
|
519
|
-
const { count:
|
|
520
|
-
|
|
517
|
+
const { count: g } = await this.adapter.client.schema("public").from(n).select("*", { count: "exact", head: !0 }).eq("parentId", h.id);
|
|
518
|
+
y.hasChildren = (g || 0) > 0;
|
|
521
519
|
}
|
|
522
|
-
if (
|
|
523
|
-
const { data:
|
|
524
|
-
|
|
520
|
+
if (r.push(y), f < s) {
|
|
521
|
+
const { data: g } = await this.adapter.client.schema("public").from(n).select("*").eq("parentId", h.id);
|
|
522
|
+
g && g.length > 0 && await l(g, f + 1);
|
|
525
523
|
}
|
|
526
524
|
}
|
|
527
525
|
};
|
|
528
|
-
return await d
|
|
526
|
+
return await l(d || [], 0), r;
|
|
529
527
|
}
|
|
530
528
|
/**
|
|
531
529
|
* 备用的祖先节点查询(不使用存储函数)
|
|
@@ -537,20 +535,20 @@ class H extends F {
|
|
|
537
535
|
const { entityId: e, level: s = 100 } = t;
|
|
538
536
|
if (!e)
|
|
539
537
|
return [];
|
|
540
|
-
const n = this.metadata.name, a = this.metadata.features?.tree?.hasChildren,
|
|
541
|
-
let
|
|
542
|
-
for (;
|
|
543
|
-
const { data:
|
|
544
|
-
if (
|
|
538
|
+
const n = this.metadata.name, a = this.metadata.features?.tree?.hasChildren, r = [];
|
|
539
|
+
let o = e, c = 0;
|
|
540
|
+
for (; o && c <= s; ) {
|
|
541
|
+
const { data: d, error: u } = await this.adapter.client.schema("public").from(n).select("*").eq("id", o);
|
|
542
|
+
if (u || !d || d.length === 0)
|
|
545
543
|
break;
|
|
546
|
-
const
|
|
544
|
+
const l = d[0], p = this.transformRowToEntity(l);
|
|
547
545
|
if (a) {
|
|
548
|
-
const { count:
|
|
549
|
-
|
|
546
|
+
const { count: f } = await this.adapter.client.schema("public").from(n).select("*", { count: "exact", head: !0 }).eq("parentId", l.id);
|
|
547
|
+
p.hasChildren = (f || 0) > 0;
|
|
550
548
|
}
|
|
551
|
-
|
|
549
|
+
r.push(p), o = l.parentId, c++;
|
|
552
550
|
}
|
|
553
|
-
return
|
|
551
|
+
return r;
|
|
554
552
|
}
|
|
555
553
|
/**
|
|
556
554
|
* 将数据库行转换为实体
|
|
@@ -562,14 +560,14 @@ class H extends F {
|
|
|
562
560
|
}), e;
|
|
563
561
|
}
|
|
564
562
|
}
|
|
565
|
-
const
|
|
566
|
-
class
|
|
563
|
+
const tt = "supabase";
|
|
564
|
+
class it extends z {
|
|
567
565
|
constructor(t, e) {
|
|
568
|
-
super(t), this.options = e, this.#t = e.client ??
|
|
566
|
+
super(t), this.options = e, this.#t = e.client ?? L(e.supabaseUrl, e.supabaseKey);
|
|
569
567
|
}
|
|
570
568
|
#t;
|
|
571
569
|
#e = null;
|
|
572
|
-
name =
|
|
570
|
+
name = tt;
|
|
573
571
|
get client() {
|
|
574
572
|
return this.#t;
|
|
575
573
|
}
|
|
@@ -580,7 +578,7 @@ class et extends U {
|
|
|
580
578
|
return this.#e || (this.#e = this.#t.channel("rxdb-changes").on(
|
|
581
579
|
"postgres_changes",
|
|
582
580
|
{ event: "INSERT", schema: "public", table: "RxDBChange" },
|
|
583
|
-
(t) =>
|
|
581
|
+
(t) => J(this, t)
|
|
584
582
|
).subscribe((t, e) => {
|
|
585
583
|
e && console.error("Supabase Realtime subscription failed:", e);
|
|
586
584
|
})), this;
|
|
@@ -598,13 +596,13 @@ class et extends U {
|
|
|
598
596
|
* 批量保存实体(upsert 语义,非事务)
|
|
599
597
|
*/
|
|
600
598
|
async saveMany(t) {
|
|
601
|
-
return t.length === 0 ? [] : this.executeUpsert(
|
|
599
|
+
return t.length === 0 ? [] : this.executeUpsert(T(t));
|
|
602
600
|
}
|
|
603
601
|
/**
|
|
604
602
|
* 批量删除实体(非事务)
|
|
605
603
|
*/
|
|
606
604
|
async removeMany(t) {
|
|
607
|
-
return t.length === 0 ? [] : this.executeDelete(
|
|
605
|
+
return t.length === 0 ? [] : this.executeDelete(T(t));
|
|
608
606
|
}
|
|
609
607
|
/**
|
|
610
608
|
* 批量修改实体(事务)
|
|
@@ -613,16 +611,16 @@ class et extends U {
|
|
|
613
611
|
* 在单个数据库事务中执行所有操作,确保原子性。
|
|
614
612
|
*/
|
|
615
613
|
async mutations(t) {
|
|
616
|
-
const e = this.rxdb.context.userId, s = [...
|
|
614
|
+
const e = this.rxdb.context.userId, s = [...v(t.create, e), ...v(t.update, e)], n = Z(t.remove), { data: a, error: r } = await this.#t.rpc("rxdb_mutations", {
|
|
617
615
|
p_upserts: s,
|
|
618
616
|
p_deletes: n
|
|
619
617
|
});
|
|
620
|
-
if (
|
|
621
|
-
throw new
|
|
622
|
-
const
|
|
623
|
-
for (const [,
|
|
624
|
-
|
|
625
|
-
return
|
|
618
|
+
if (r)
|
|
619
|
+
throw new m(`Transaction failed: ${r.message}`);
|
|
620
|
+
const o = a?.upserted ?? [];
|
|
621
|
+
for (const [, c] of t.remove)
|
|
622
|
+
o.push(...c);
|
|
623
|
+
return o;
|
|
626
624
|
}
|
|
627
625
|
// ============================================
|
|
628
626
|
// Repository
|
|
@@ -630,7 +628,7 @@ class et extends U {
|
|
|
630
628
|
getRepository(t) {
|
|
631
629
|
if (this.repository_cache.has(t))
|
|
632
630
|
return this.repository_cache.get(t);
|
|
633
|
-
const s = b(t).features?.tree ? new
|
|
631
|
+
const s = b(t).features?.tree ? new q(this, t) : new P(this, t);
|
|
634
632
|
return this.repository_cache.set(t, s), s;
|
|
635
633
|
}
|
|
636
634
|
// ============================================
|
|
@@ -640,7 +638,7 @@ class et extends U {
|
|
|
640
638
|
const e = b(t), n = await this.getSchemaClient(e.namespace).from(e.name).select("*", { count: "exact", head: !0 });
|
|
641
639
|
if (n.status === 200) return !0;
|
|
642
640
|
if (n.status === 204) return !1;
|
|
643
|
-
throw new
|
|
641
|
+
throw new m(
|
|
644
642
|
`Failed to check table existence: ${n.error?.message || `status ${n.status}`}`
|
|
645
643
|
);
|
|
646
644
|
}
|
|
@@ -653,24 +651,34 @@ class et extends U {
|
|
|
653
651
|
* @param sinceId - 拉取此 ID 之后的变更(不包含该 ID)
|
|
654
652
|
* @param limit - 最大拉取数量
|
|
655
653
|
* @param repositoryFilter - 可选的实体过滤列表(用于 repository-level sync)
|
|
654
|
+
* @param filter - 可选的行级过滤条件(用于 SyncType.Filter)
|
|
656
655
|
* @returns RxDBChange 记录数组,按 id ASC 排序
|
|
657
656
|
*
|
|
658
657
|
* @remarks
|
|
659
658
|
* 使用 id 而非 createdAt 作为游标,避免同毫秒内多条记录导致的重复问题
|
|
659
|
+
*
|
|
660
|
+
* 当提供 filter 参数时,会通过 JOIN 实体表并应用过滤条件,
|
|
661
|
+
* 只返回满足条件的实体对应的变更记录。
|
|
660
662
|
*/
|
|
661
|
-
async pullChanges(t, e = 1e3, s) {
|
|
662
|
-
const
|
|
663
|
-
let
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
663
|
+
async pullChanges(t, e = 1e3, s, n) {
|
|
664
|
+
const a = [];
|
|
665
|
+
let r;
|
|
666
|
+
if (n && s?.length === 1) {
|
|
667
|
+
const l = s[0];
|
|
668
|
+
if (r = await this.#n(l, n), r.length === 0)
|
|
669
|
+
return [];
|
|
670
|
+
}
|
|
671
|
+
let o = this.#t.from("RxDBChange").select("*").gt("id", t).order("id", { ascending: !0 }).limit(e);
|
|
672
|
+
s && s.length > 0 && (o = o.in("entity", s)), r && (o = o.in("entityId", r));
|
|
673
|
+
const { data: c, error: d } = await o;
|
|
674
|
+
if (d)
|
|
675
|
+
throw new m(`Failed to pull changes: ${d.message}`);
|
|
676
|
+
const u = (c ?? []).map((l) => ({
|
|
669
677
|
...l,
|
|
670
678
|
createdAt: new Date(l.createdAt),
|
|
671
679
|
updatedAt: l.updatedAt ? new Date(l.updatedAt) : null
|
|
672
680
|
}));
|
|
673
|
-
return
|
|
681
|
+
return a.push(...u), a;
|
|
674
682
|
}
|
|
675
683
|
/**
|
|
676
684
|
* 获取远程变更数量(轻量级,不下载数据)(T042, US2)
|
|
@@ -694,19 +702,19 @@ class et extends U {
|
|
|
694
702
|
e && e.length > 0 && (s = s.in("entity", e));
|
|
695
703
|
const { count: n, error: a } = await s;
|
|
696
704
|
if (a)
|
|
697
|
-
throw new
|
|
698
|
-
let
|
|
705
|
+
throw new m(`Failed to get change count: ${a.message}`);
|
|
706
|
+
let r = t;
|
|
699
707
|
if (n && n > 0) {
|
|
700
|
-
let
|
|
701
|
-
e && e.length > 0 && (
|
|
702
|
-
const { data:
|
|
703
|
-
if (
|
|
704
|
-
throw new
|
|
705
|
-
|
|
708
|
+
let o = this.#t.from("RxDBChange").select("id").gt("id", t).order("id", { ascending: !1 }).limit(1);
|
|
709
|
+
e && e.length > 0 && (o = o.in("entity", e));
|
|
710
|
+
const { data: c, error: d } = await o;
|
|
711
|
+
if (d)
|
|
712
|
+
throw new m(`Failed to get latest changeId: ${d.message}`);
|
|
713
|
+
c && c.length > 0 && (r = c[0].id);
|
|
706
714
|
}
|
|
707
715
|
return {
|
|
708
716
|
count: n ?? 0,
|
|
709
|
-
latestChangeId:
|
|
717
|
+
latestChangeId: r
|
|
710
718
|
};
|
|
711
719
|
}
|
|
712
720
|
/**
|
|
@@ -724,17 +732,17 @@ class et extends U {
|
|
|
724
732
|
deletes: /* @__PURE__ */ new Map()
|
|
725
733
|
};
|
|
726
734
|
for (const s of t) {
|
|
727
|
-
const { entityKey: n, finalType: a, finalPatch:
|
|
735
|
+
const { entityKey: n, finalType: a, finalPatch: r, inversePatch: o } = s;
|
|
728
736
|
if (a)
|
|
729
737
|
switch (a) {
|
|
730
738
|
case "INSERT":
|
|
731
|
-
e.inserts.set(n, { patch:
|
|
739
|
+
e.inserts.set(n, { patch: r, inversePatch: o });
|
|
732
740
|
break;
|
|
733
741
|
case "UPDATE":
|
|
734
|
-
e.updates.set(n, { patch:
|
|
742
|
+
e.updates.set(n, { patch: r, inversePatch: o });
|
|
735
743
|
break;
|
|
736
744
|
case "DELETE":
|
|
737
|
-
e.deletes.set(n, { patch: null, inversePatch:
|
|
745
|
+
e.deletes.set(n, { patch: null, inversePatch: o });
|
|
738
746
|
break;
|
|
739
747
|
}
|
|
740
748
|
}
|
|
@@ -751,70 +759,119 @@ class et extends U {
|
|
|
751
759
|
* @param actions - 压缩后的变更操作集合
|
|
752
760
|
*/
|
|
753
761
|
async mergeChanges(t) {
|
|
754
|
-
const e = (/* @__PURE__ */ new Date()).toISOString(), s = this.rxdb.context.userId, n = [], a = /* @__PURE__ */ new Map(),
|
|
755
|
-
for (const [
|
|
756
|
-
const [
|
|
762
|
+
const e = (/* @__PURE__ */ new Date()).toISOString(), s = this.rxdb.context.userId, n = [], a = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map();
|
|
763
|
+
for (const [l, { inversePatch: p }] of t.deletes) {
|
|
764
|
+
const [f, h, y] = l.split(":"), g = f ? `${f}.${h}` : h;
|
|
757
765
|
n.push({
|
|
758
|
-
namespace:
|
|
759
|
-
entity:
|
|
760
|
-
entityId:
|
|
766
|
+
namespace: f || "public",
|
|
767
|
+
entity: h,
|
|
768
|
+
entityId: y,
|
|
761
769
|
type: "DELETE",
|
|
762
770
|
patch: null,
|
|
763
|
-
inversePatch:
|
|
771
|
+
inversePatch: p,
|
|
764
772
|
clientId: this.rxdb.context.clientId,
|
|
765
773
|
createdAt: e,
|
|
766
774
|
updatedAt: e
|
|
767
775
|
});
|
|
768
|
-
const
|
|
769
|
-
|
|
776
|
+
const w = r.get(g) ?? [];
|
|
777
|
+
w.push(y), r.set(g, w);
|
|
770
778
|
}
|
|
771
|
-
for (const [
|
|
772
|
-
const [
|
|
779
|
+
for (const [l, { patch: p, inversePatch: f }] of t.updates) {
|
|
780
|
+
const [h, y, g] = l.split(":"), w = h ? `${h}.${y}` : y;
|
|
773
781
|
n.push({
|
|
774
|
-
namespace:
|
|
775
|
-
entity:
|
|
776
|
-
entityId:
|
|
782
|
+
namespace: h || "public",
|
|
783
|
+
entity: y,
|
|
784
|
+
entityId: g,
|
|
777
785
|
type: "UPDATE",
|
|
778
|
-
patch:
|
|
779
|
-
inversePatch:
|
|
786
|
+
patch: p,
|
|
787
|
+
inversePatch: f,
|
|
780
788
|
clientId: this.rxdb.context.clientId,
|
|
781
789
|
createdAt: e,
|
|
782
790
|
updatedAt: e
|
|
783
791
|
});
|
|
784
|
-
const
|
|
785
|
-
s && (_.updatedBy = s),
|
|
792
|
+
const x = a.get(w) ?? [], _ = { id: g, ...p };
|
|
793
|
+
s && (_.updatedBy = s), x.push(_), a.set(w, x);
|
|
786
794
|
}
|
|
787
|
-
for (const [
|
|
788
|
-
const [
|
|
795
|
+
for (const [l, { patch: p, inversePatch: f }] of t.inserts) {
|
|
796
|
+
const [h, y, g] = l.split(":"), w = h ? `${h}.${y}` : y;
|
|
789
797
|
n.push({
|
|
790
|
-
namespace:
|
|
791
|
-
entity:
|
|
792
|
-
entityId:
|
|
798
|
+
namespace: h || "public",
|
|
799
|
+
entity: y,
|
|
800
|
+
entityId: g,
|
|
793
801
|
type: "INSERT",
|
|
794
|
-
patch:
|
|
795
|
-
inversePatch:
|
|
802
|
+
patch: p,
|
|
803
|
+
inversePatch: f,
|
|
796
804
|
clientId: this.rxdb.context.clientId,
|
|
797
805
|
createdAt: e,
|
|
798
806
|
updatedAt: e
|
|
799
807
|
});
|
|
800
|
-
const
|
|
801
|
-
s && (_.createdBy = s, _.updatedBy = s),
|
|
808
|
+
const x = a.get(w) ?? [], _ = { id: g, ...p };
|
|
809
|
+
s && (_.createdBy = s, _.updatedBy = s), x.push(_), a.set(w, x);
|
|
802
810
|
}
|
|
803
|
-
const
|
|
804
|
-
const [
|
|
805
|
-
return { table:
|
|
806
|
-
}),
|
|
807
|
-
const [
|
|
808
|
-
return { table:
|
|
809
|
-
}), { data:
|
|
810
|
-
p_upserts:
|
|
811
|
-
p_deletes:
|
|
811
|
+
const o = Array.from(a.entries()).map(([l, p]) => {
|
|
812
|
+
const [f, h] = l.includes(".") ? l.split(".") : ["public", l];
|
|
813
|
+
return { table: h, schema: f, data: p };
|
|
814
|
+
}), c = Array.from(r.entries()).map(([l, p]) => {
|
|
815
|
+
const [f, h] = l.includes(".") ? l.split(".") : ["public", l];
|
|
816
|
+
return { table: h, schema: f, ids: p };
|
|
817
|
+
}), { data: d, error: u } = await this.#t.rpc("rxdb_mutations", {
|
|
818
|
+
p_upserts: o,
|
|
819
|
+
p_deletes: c,
|
|
812
820
|
p_changes: n,
|
|
813
821
|
p_skip_sync: !0
|
|
814
822
|
});
|
|
815
|
-
if (
|
|
816
|
-
throw new
|
|
817
|
-
return
|
|
823
|
+
if (u)
|
|
824
|
+
throw new m(`Failed to merge changes: ${u.message}`);
|
|
825
|
+
return d?.max_change_id ?? void 0;
|
|
826
|
+
}
|
|
827
|
+
// ============================================
|
|
828
|
+
// QueryCache 方法
|
|
829
|
+
// ============================================
|
|
830
|
+
/**
|
|
831
|
+
* 获取实体元数据,用于新鲜度比较(QueryCache 专用)
|
|
832
|
+
*
|
|
833
|
+
* 只返回 `{ id, updatedAt }` 元数据,网络传输量比完整数据减少 90%+。
|
|
834
|
+
*
|
|
835
|
+
* @param entityName - 实体名称
|
|
836
|
+
* @param query - 查询条件
|
|
837
|
+
* @returns Observable<QueryCacheEntityMetadata[]>
|
|
838
|
+
*
|
|
839
|
+
* @example
|
|
840
|
+
* ```typescript
|
|
841
|
+
* adapter.fetchMetadata('Product', { combinator: 'and', rules: [{ field: 'status', operator: 'eq', value: 'active' }] })
|
|
842
|
+
* .subscribe(metadata => console.log(metadata));
|
|
843
|
+
* ```
|
|
844
|
+
*/
|
|
845
|
+
fetchMetadata(t, e) {
|
|
846
|
+
return D(() => {
|
|
847
|
+
let s = this.#t.from(t).select("id, updatedAt");
|
|
848
|
+
return s = $(s, e), k(s).pipe(
|
|
849
|
+
N(({ data: n, error: a }) => {
|
|
850
|
+
if (a)
|
|
851
|
+
throw new m(`Failed to fetch metadata: ${a.message}`);
|
|
852
|
+
return (n ?? []).map((r) => ({
|
|
853
|
+
id: r.id,
|
|
854
|
+
updatedAt: r.updatedAt
|
|
855
|
+
}));
|
|
856
|
+
})
|
|
857
|
+
);
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* 按 ID 列表批量获取完整数据(QueryCache 专用)
|
|
862
|
+
*
|
|
863
|
+
* @param entityName - 实体名称
|
|
864
|
+
* @param ids - 需要获取的实体 ID 列表
|
|
865
|
+
* @returns Observable<T[]>
|
|
866
|
+
*/
|
|
867
|
+
findByIds(t, e) {
|
|
868
|
+
return D(() => e.length === 0 ? Q([]) : k(this.#t.from(t).select("*").in("id", e)).pipe(
|
|
869
|
+
N(({ data: s, error: n }) => {
|
|
870
|
+
if (n)
|
|
871
|
+
throw new m(`Failed to find by ids: ${n.message}`);
|
|
872
|
+
return s ?? [];
|
|
873
|
+
})
|
|
874
|
+
));
|
|
818
875
|
}
|
|
819
876
|
// ============================================
|
|
820
877
|
// 私有方法
|
|
@@ -827,10 +884,10 @@ class et extends U {
|
|
|
827
884
|
async executeUpsert(t) {
|
|
828
885
|
const e = [], s = this.rxdb.context.userId;
|
|
829
886
|
for (const [n, a] of t) {
|
|
830
|
-
const
|
|
831
|
-
if (
|
|
832
|
-
throw new
|
|
833
|
-
e.push(...
|
|
887
|
+
const r = b(n), o = this.getSchemaClient(r.namespace), c = Array.from(a), d = s ? c.map((p) => ({ ...p, createdBy: s, updatedBy: s })) : c, { data: u, error: l } = await o.from(r.name).upsert(d).select();
|
|
888
|
+
if (l)
|
|
889
|
+
throw new m(`Failed to upsert: ${l.message}`);
|
|
890
|
+
e.push(...u);
|
|
834
891
|
}
|
|
835
892
|
return e;
|
|
836
893
|
}
|
|
@@ -838,21 +895,36 @@ class et extends U {
|
|
|
838
895
|
async executeDelete(t) {
|
|
839
896
|
const e = [];
|
|
840
897
|
for (const [s, n] of t) {
|
|
841
|
-
const a = b(s),
|
|
842
|
-
if (
|
|
843
|
-
throw new
|
|
844
|
-
e.push(...
|
|
898
|
+
const a = b(s), r = this.getSchemaClient(a.namespace), o = Array.from(n), c = o.map((u) => u.id), { error: d } = await r.from(a.name).delete().in("id", c);
|
|
899
|
+
if (d)
|
|
900
|
+
throw new m(`Failed to delete: ${d.message}`);
|
|
901
|
+
e.push(...o);
|
|
845
902
|
}
|
|
846
903
|
return e;
|
|
847
904
|
}
|
|
905
|
+
/**
|
|
906
|
+
* 获取满足 filter 条件的实体 ID 列表
|
|
907
|
+
*
|
|
908
|
+
* @param entityName - 实体表名
|
|
909
|
+
* @param filter - 过滤条件
|
|
910
|
+
* @returns 满足条件的 entityId 列表
|
|
911
|
+
*/
|
|
912
|
+
async #n(t, e) {
|
|
913
|
+
let s = this.#t.from(t).select("id");
|
|
914
|
+
s = $(s, e);
|
|
915
|
+
const { data: n, error: a } = await s;
|
|
916
|
+
if (a)
|
|
917
|
+
throw new m(`Failed to query filtered entities: ${a.message}`);
|
|
918
|
+
return (n ?? []).map((r) => r.id);
|
|
919
|
+
}
|
|
848
920
|
}
|
|
849
921
|
export {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
922
|
+
tt as ADAPTER_NAME,
|
|
923
|
+
it as RxDBAdapterSupabase,
|
|
924
|
+
at as SupabaseConfigError,
|
|
925
|
+
m as SupabaseDataError,
|
|
926
|
+
rt as SupabaseNetworkError,
|
|
927
|
+
P as SupabaseRepository,
|
|
856
928
|
S as SupabaseSyncError,
|
|
857
|
-
|
|
929
|
+
q as SupabaseTreeRepository
|
|
858
930
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { SchemaManager, EntityMetadata, RuleGroup } from '../packages/rxdb/src/index.ts';
|
|
2
|
+
import { PostgrestFilterBuilder } from '@supabase/postgrest-js';
|
|
2
3
|
/**
|
|
3
|
-
* Supabase Query Builder
|
|
4
|
+
* Supabase Query Builder
|
|
4
5
|
*/
|
|
5
|
-
type SupabaseQueryBuilder = any
|
|
6
|
+
type SupabaseQueryBuilder = PostgrestFilterBuilder<any, any, any, any, any, any, any>;
|
|
6
7
|
/**
|
|
7
8
|
* 应用 RuleGroup 到 Supabase Query Builder
|
|
8
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule_group_builder.d.ts","sourceRoot":"","sources":["../src/rule_group_builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAEL,aAAa,EACb,KAAK,cAAc,EAGnB,KAAK,SAAS,EACf,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"rule_group_builder.d.ts","sourceRoot":"","sources":["../src/rule_group_builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAEL,aAAa,EACb,KAAK,cAAc,EAGnB,KAAK,SAAS,EACf,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAMrE;;GAEG;AACH,KAAK,oBAAoB,GAAG,sBAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AA4FtF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,KAAK,EAAE,oBAAoB,EAC3B,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,QAAQ,CAAC,EAAE,cAAc,EACzB,aAAa,CAAC,EAAE,aAAa,GAC5B,oBAAoB,CA6BtB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiao/rxdb-adapter-supabase",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
"dist",
|
|
19
19
|
"!**/*.tsbuildinfo"
|
|
20
20
|
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
21
24
|
"nx": {
|
|
22
25
|
"name": "rxdb-adapter-supabase",
|
|
23
26
|
"tags": [
|
|
@@ -25,12 +28,14 @@
|
|
|
25
28
|
]
|
|
26
29
|
},
|
|
27
30
|
"peerDependencies": {
|
|
28
|
-
"@supabase/supabase-js": "^2.
|
|
29
|
-
"@
|
|
31
|
+
"@supabase/supabase-js": "^2.88.0",
|
|
32
|
+
"@supabase/postgrest-js": "^2.89.0",
|
|
33
|
+
"rxjs": "^7.8.2",
|
|
34
|
+
"@aiao/rxdb": "0.0.10"
|
|
30
35
|
},
|
|
31
36
|
"devDependencies": {
|
|
32
37
|
"dotenv": "^17.2.3",
|
|
33
|
-
"@aiao/rxdb-
|
|
34
|
-
"@aiao/rxdb-
|
|
38
|
+
"@aiao/rxdb-adapter-sqlite": "0.0.10",
|
|
39
|
+
"@aiao/rxdb-test": "0.0.10"
|
|
35
40
|
}
|
|
36
41
|
}
|