@syncular/core 0.1.3 → 0.2.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/README.md +5 -19
- package/dist/blob-ref.d.ts +21 -0
- package/dist/blob-ref.js +97 -0
- package/dist/bytes.d.ts +45 -0
- package/dist/bytes.js +242 -0
- package/dist/canonical-json.d.ts +10 -0
- package/dist/canonical-json.js +18 -0
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +5 -0
- package/dist/crypto.d.ts +60 -0
- package/dist/crypto.js +251 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.js +17 -0
- package/dist/frames.d.ts +24 -0
- package/dist/frames.js +42 -0
- package/dist/index.d.ts +18 -26
- package/dist/index.js +18 -43
- package/dist/message.d.ts +157 -0
- package/dist/message.js +786 -0
- package/dist/realtime.d.ts +92 -0
- package/dist/realtime.js +222 -0
- package/dist/render.d.ts +22 -0
- package/dist/render.js +273 -0
- package/dist/row-codec.d.ts +39 -0
- package/dist/row-codec.js +176 -0
- package/dist/segment.d.ts +18 -0
- package/dist/segment.js +105 -0
- package/dist/stream.d.ts +20 -0
- package/dist/stream.js +102 -0
- package/package.json +7 -59
- package/src/blob-ref.ts +135 -0
- package/src/bytes.ts +301 -0
- package/src/canonical-json.ts +20 -0
- package/src/constants.ts +7 -0
- package/src/crypto.ts +335 -0
- package/src/errors.ts +18 -0
- package/src/frames.ts +47 -0
- package/src/index.ts +18 -43
- package/src/message.ts +1024 -0
- package/src/realtime.ts +340 -0
- package/src/render.ts +325 -0
- package/src/row-codec.ts +265 -0
- package/src/segment.ts +150 -0
- package/src/stream.ts +128 -0
- package/dist/blobs.d.ts +0 -153
- package/dist/blobs.d.ts.map +0 -1
- package/dist/blobs.js +0 -47
- package/dist/blobs.js.map +0 -1
- package/dist/column-codecs.d.ts +0 -59
- package/dist/column-codecs.d.ts.map +0 -1
- package/dist/column-codecs.js +0 -159
- package/dist/column-codecs.js.map +0 -1
- package/dist/conflict.d.ts +0 -22
- package/dist/conflict.d.ts.map +0 -1
- package/dist/conflict.js +0 -81
- package/dist/conflict.js.map +0 -1
- package/dist/database.d.ts +0 -7
- package/dist/database.d.ts.map +0 -1
- package/dist/database.js +0 -14
- package/dist/database.js.map +0 -1
- package/dist/dialect.d.ts +0 -7
- package/dist/dialect.d.ts.map +0 -1
- package/dist/dialect.js +0 -2
- package/dist/dialect.js.map +0 -1
- package/dist/error-responses.d.ts +0 -393
- package/dist/error-responses.d.ts.map +0 -1
- package/dist/error-responses.js +0 -393
- package/dist/error-responses.js.map +0 -1
- package/dist/http/api-client.d.ts +0 -11
- package/dist/http/api-client.d.ts.map +0 -1
- package/dist/http/api-client.js +0 -30
- package/dist/http/api-client.js.map +0 -1
- package/dist/http/blob.d.ts +0 -6
- package/dist/http/blob.d.ts.map +0 -1
- package/dist/http/blob.js +0 -46
- package/dist/http/blob.js.map +0 -1
- package/dist/http/generated/api.d.ts +0 -5241
- package/dist/http/generated/api.d.ts.map +0 -1
- package/dist/http/generated/api.js +0 -6
- package/dist/http/generated/api.js.map +0 -1
- package/dist/http/index.d.ts +0 -18
- package/dist/http/index.d.ts.map +0 -1
- package/dist/http/index.js +0 -212
- package/dist/http/index.js.map +0 -1
- package/dist/http/shared.d.ts +0 -45
- package/dist/http/shared.d.ts.map +0 -1
- package/dist/http/shared.js +0 -122
- package/dist/http/shared.js.map +0 -1
- package/dist/http/transport-client.d.ts +0 -31
- package/dist/http/transport-client.d.ts.map +0 -1
- package/dist/http/transport-client.js +0 -193
- package/dist/http/transport-client.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/kysely-column-codecs.d.ts +0 -31
- package/dist/kysely-column-codecs.d.ts.map +0 -1
- package/dist/kysely-column-codecs.js +0 -452
- package/dist/kysely-column-codecs.js.map +0 -1
- package/dist/logger.d.ts +0 -29
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -26
- package/dist/logger.js.map +0 -1
- package/dist/proxy/index.d.ts +0 -54
- package/dist/proxy/index.d.ts.map +0 -1
- package/dist/proxy/index.js +0 -7
- package/dist/proxy/index.js.map +0 -1
- package/dist/schemas/blobs.d.ts +0 -82
- package/dist/schemas/blobs.d.ts.map +0 -1
- package/dist/schemas/blobs.js +0 -64
- package/dist/schemas/blobs.js.map +0 -1
- package/dist/schemas/common.d.ts +0 -100
- package/dist/schemas/common.d.ts.map +0 -1
- package/dist/schemas/common.js +0 -64
- package/dist/schemas/common.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -7
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -7
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/sync.d.ts +0 -1065
- package/dist/schemas/sync.d.ts.map +0 -1
- package/dist/schemas/sync.js +0 -361
- package/dist/schemas/sync.js.map +0 -1
- package/dist/scopes/index.d.ts +0 -113
- package/dist/scopes/index.d.ts.map +0 -1
- package/dist/scopes/index.js +0 -103
- package/dist/scopes/index.js.map +0 -1
- package/dist/sentry.d.ts +0 -31
- package/dist/sentry.d.ts.map +0 -1
- package/dist/sentry.js +0 -147
- package/dist/sentry.js.map +0 -1
- package/dist/snapshot-chunks.d.ts +0 -110
- package/dist/snapshot-chunks.d.ts.map +0 -1
- package/dist/snapshot-chunks.js +0 -682
- package/dist/snapshot-chunks.js.map +0 -1
- package/dist/sync-packs.d.ts +0 -33
- package/dist/sync-packs.d.ts.map +0 -1
- package/dist/sync-packs.js +0 -821
- package/dist/sync-packs.js.map +0 -1
- package/dist/telemetry.d.ts +0 -114
- package/dist/telemetry.d.ts.map +0 -1
- package/dist/telemetry.js +0 -114
- package/dist/telemetry.js.map +0 -1
- package/dist/transforms.d.ts +0 -146
- package/dist/transforms.d.ts.map +0 -1
- package/dist/transforms.js +0 -155
- package/dist/transforms.js.map +0 -1
- package/dist/types.d.ts +0 -210
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -20
- package/dist/types.js.map +0 -1
- package/dist/utils/bytes.d.ts +0 -4
- package/dist/utils/bytes.d.ts.map +0 -1
- package/dist/utils/bytes.js +0 -66
- package/dist/utils/bytes.js.map +0 -1
- package/dist/utils/compression.d.ts +0 -22
- package/dist/utils/compression.d.ts.map +0 -1
- package/dist/utils/compression.js +0 -129
- package/dist/utils/compression.js.map +0 -1
- package/dist/utils/crypto.d.ts +0 -13
- package/dist/utils/crypto.d.ts.map +0 -1
- package/dist/utils/crypto.js +0 -107
- package/dist/utils/crypto.js.map +0 -1
- package/dist/utils/id.d.ts +0 -3
- package/dist/utils/id.d.ts.map +0 -1
- package/dist/utils/id.js +0 -25
- package/dist/utils/id.js.map +0 -1
- package/dist/utils/index.d.ts +0 -10
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -10
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/internal-runtime.d.ts +0 -16
- package/dist/utils/internal-runtime.d.ts.map +0 -1
- package/dist/utils/internal-runtime.js +0 -14
- package/dist/utils/internal-runtime.js.map +0 -1
- package/dist/utils/object.d.ts +0 -2
- package/dist/utils/object.d.ts.map +0 -1
- package/dist/utils/object.js +0 -4
- package/dist/utils/object.js.map +0 -1
- package/dist/utils/realtime-change-index.d.ts +0 -9
- package/dist/utils/realtime-change-index.d.ts.map +0 -1
- package/dist/utils/realtime-change-index.js +0 -36
- package/dist/utils/realtime-change-index.js.map +0 -1
- package/dist/utils/realtime-connection-registry.d.ts +0 -40
- package/dist/utils/realtime-connection-registry.d.ts.map +0 -1
- package/dist/utils/realtime-connection-registry.js +0 -237
- package/dist/utils/realtime-connection-registry.js.map +0 -1
- package/dist/utils/table-registry.d.ts +0 -10
- package/dist/utils/table-registry.d.ts.map +0 -1
- package/dist/utils/table-registry.js +0 -54
- package/dist/utils/table-registry.js.map +0 -1
- package/dist/utils/url.d.ts +0 -3
- package/dist/utils/url.d.ts.map +0 -1
- package/dist/utils/url.js +0 -20
- package/dist/utils/url.js.map +0 -1
- package/src/blobs.ts +0 -219
- package/src/column-codecs.ts +0 -262
- package/src/conflict.ts +0 -92
- package/src/database.ts +0 -21
- package/src/dialect.ts +0 -8
- package/src/error-responses.ts +0 -423
- package/src/http/api-client.ts +0 -39
- package/src/http/blob.ts +0 -95
- package/src/http/generated/api.ts +0 -5241
- package/src/http/index.ts +0 -365
- package/src/http/shared.ts +0 -220
- package/src/http/transport-client.ts +0 -314
- package/src/kysely-column-codecs.ts +0 -585
- package/src/logger.ts +0 -38
- package/src/proxy/index.ts +0 -57
- package/src/schemas/blobs.ts +0 -110
- package/src/schemas/common.ts +0 -89
- package/src/schemas/index.ts +0 -7
- package/src/schemas/sync.ts +0 -517
- package/src/scopes/index.ts +0 -237
- package/src/sentry.ts +0 -200
- package/src/snapshot-chunks.ts +0 -964
- package/src/sync-packs.ts +0 -1096
- package/src/telemetry.ts +0 -243
- package/src/transforms.ts +0 -256
- package/src/types.ts +0 -267
- package/src/utils/bytes.ts +0 -75
- package/src/utils/compression.ts +0 -187
- package/src/utils/crypto.ts +0 -146
- package/src/utils/id.ts +0 -34
- package/src/utils/index.ts +0 -9
- package/src/utils/internal-runtime.ts +0 -39
- package/src/utils/object.ts +0 -3
- package/src/utils/realtime-change-index.ts +0 -44
- package/src/utils/realtime-connection-registry.ts +0 -286
- package/src/utils/table-registry.ts +0 -67
- package/src/utils/url.ts +0 -29
|
@@ -1,585 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type AliasNode,
|
|
3
|
-
type ColumnNode,
|
|
4
|
-
type ColumnUpdateNode,
|
|
5
|
-
type DeleteQueryNode,
|
|
6
|
-
type IdentifierNode,
|
|
7
|
-
type InsertQueryNode,
|
|
8
|
-
type KyselyPlugin,
|
|
9
|
-
type OperationNode,
|
|
10
|
-
OperationNodeTransformer,
|
|
11
|
-
type PluginTransformQueryArgs,
|
|
12
|
-
type PluginTransformResultArgs,
|
|
13
|
-
type PrimitiveValueListNode,
|
|
14
|
-
type QueryResult,
|
|
15
|
-
type ReferenceNode,
|
|
16
|
-
type RootOperationNode,
|
|
17
|
-
type SelectionNode,
|
|
18
|
-
type SelectQueryNode,
|
|
19
|
-
type TableNode,
|
|
20
|
-
type UnknownRow,
|
|
21
|
-
type UpdateQueryNode,
|
|
22
|
-
type ValueNode,
|
|
23
|
-
type ValuesNode,
|
|
24
|
-
} from 'kysely';
|
|
25
|
-
import {
|
|
26
|
-
type AnyColumnCodec,
|
|
27
|
-
applyCodecFromDbValue,
|
|
28
|
-
applyCodecToDbValue,
|
|
29
|
-
type ColumnCodecDialect,
|
|
30
|
-
type ColumnCodecSource,
|
|
31
|
-
createTableColumnCodecsResolver,
|
|
32
|
-
type TableColumnCodecs,
|
|
33
|
-
} from './column-codecs';
|
|
34
|
-
|
|
35
|
-
interface ColumnCodecPluginOptions {
|
|
36
|
-
codecs: ColumnCodecSource;
|
|
37
|
-
dialect?: ColumnCodecDialect;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface ColumnReference {
|
|
41
|
-
outputKey: string;
|
|
42
|
-
table: string;
|
|
43
|
-
column: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface QueryResultPlan {
|
|
47
|
-
explicit: ColumnReference[];
|
|
48
|
-
selectAllTables: string[];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function isIdentifierNode(
|
|
52
|
-
node: OperationNode | undefined
|
|
53
|
-
): node is IdentifierNode {
|
|
54
|
-
return node?.kind === 'IdentifierNode';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function isTableNode(node: OperationNode | undefined): node is TableNode {
|
|
58
|
-
return node?.kind === 'TableNode';
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function isAliasNode(node: OperationNode | undefined): node is AliasNode {
|
|
62
|
-
return node?.kind === 'AliasNode';
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function isColumnNode(node: OperationNode | undefined): node is ColumnNode {
|
|
66
|
-
return node?.kind === 'ColumnNode';
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function isReferenceNode(
|
|
70
|
-
node: OperationNode | undefined
|
|
71
|
-
): node is ReferenceNode {
|
|
72
|
-
return node?.kind === 'ReferenceNode';
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function isSelectionNode(
|
|
76
|
-
node: OperationNode | undefined
|
|
77
|
-
): node is SelectionNode {
|
|
78
|
-
return node?.kind === 'SelectionNode';
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function isPrimitiveValueListNode(
|
|
82
|
-
node: OperationNode | undefined
|
|
83
|
-
): node is PrimitiveValueListNode {
|
|
84
|
-
return node?.kind === 'PrimitiveValueListNode';
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function isValuesNode(node: OperationNode | undefined): node is ValuesNode {
|
|
88
|
-
return node?.kind === 'ValuesNode';
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function isValueNode(node: OperationNode | undefined): node is ValueNode {
|
|
92
|
-
return node?.kind === 'ValueNode';
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function getIdentifierName(node?: OperationNode): string | undefined {
|
|
96
|
-
if (!isIdentifierNode(node)) return undefined;
|
|
97
|
-
return node?.name;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function getTableName(node?: OperationNode): string | undefined {
|
|
101
|
-
if (!isTableNode(node)) return undefined;
|
|
102
|
-
return getIdentifierName(node.table.identifier);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function getColumnName(node?: OperationNode): string | undefined {
|
|
106
|
-
if (!isColumnNode(node)) return undefined;
|
|
107
|
-
return getIdentifierName(node.column);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function getBaseTableFromAlias(node: AliasNode): string | undefined {
|
|
111
|
-
if (!isTableNode(node.node)) return undefined;
|
|
112
|
-
return getTableName(node.node);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function getAliasName(node: AliasNode): string | undefined {
|
|
116
|
-
return getIdentifierName(node.alias);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function tableAliasMapForSelect(node: SelectQueryNode): Map<string, string> {
|
|
120
|
-
const aliases = new Map<string, string>();
|
|
121
|
-
|
|
122
|
-
for (const fromItem of node.from?.froms ?? []) {
|
|
123
|
-
if (isTableNode(fromItem)) {
|
|
124
|
-
const tableName = getTableName(fromItem);
|
|
125
|
-
if (tableName) aliases.set(tableName, tableName);
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
if (isAliasNode(fromItem)) {
|
|
129
|
-
const tableName = getBaseTableFromAlias(fromItem);
|
|
130
|
-
const aliasName = getAliasName(fromItem);
|
|
131
|
-
if (tableName && aliasName) aliases.set(aliasName, tableName);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
for (const join of node.joins ?? []) {
|
|
136
|
-
const joinItem = join.table;
|
|
137
|
-
if (isTableNode(joinItem)) {
|
|
138
|
-
const tableName = getTableName(joinItem);
|
|
139
|
-
if (tableName) aliases.set(tableName, tableName);
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
if (isAliasNode(joinItem)) {
|
|
143
|
-
const tableName = getBaseTableFromAlias(joinItem);
|
|
144
|
-
const aliasName = getAliasName(joinItem);
|
|
145
|
-
if (tableName && aliasName) aliases.set(aliasName, tableName);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return aliases;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function resolveTableName(args: {
|
|
153
|
-
refTable?: string;
|
|
154
|
-
aliases: Map<string, string>;
|
|
155
|
-
fallbackTable?: string;
|
|
156
|
-
}): string | undefined {
|
|
157
|
-
if (args.refTable) {
|
|
158
|
-
return args.aliases.get(args.refTable) ?? args.refTable;
|
|
159
|
-
}
|
|
160
|
-
if (args.fallbackTable) return args.fallbackTable;
|
|
161
|
-
if (args.aliases.size === 1) {
|
|
162
|
-
return args.aliases.values().next().value;
|
|
163
|
-
}
|
|
164
|
-
return undefined;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function collectSelectionReferences(args: {
|
|
168
|
-
selections: readonly OperationNode[];
|
|
169
|
-
aliases: Map<string, string>;
|
|
170
|
-
fallbackTable?: string;
|
|
171
|
-
}): { explicit: ColumnReference[]; selectAllTables: string[] } {
|
|
172
|
-
const explicit: ColumnReference[] = [];
|
|
173
|
-
const selectAllTables: string[] = [];
|
|
174
|
-
|
|
175
|
-
for (const selectionCandidate of args.selections) {
|
|
176
|
-
if (!isSelectionNode(selectionCandidate)) continue;
|
|
177
|
-
const selectionNode = selectionCandidate;
|
|
178
|
-
const selection = selectionNode.selection;
|
|
179
|
-
|
|
180
|
-
if (selection.kind === 'SelectAllNode') {
|
|
181
|
-
const tableName = resolveTableName({
|
|
182
|
-
aliases: args.aliases,
|
|
183
|
-
fallbackTable: args.fallbackTable,
|
|
184
|
-
});
|
|
185
|
-
if (tableName) selectAllTables.push(tableName);
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (selection.kind === 'ReferenceNode') {
|
|
190
|
-
if (selection.column.kind === 'SelectAllNode') {
|
|
191
|
-
const tableRef = getTableName(selection.table);
|
|
192
|
-
const tableName = resolveTableName({
|
|
193
|
-
refTable: tableRef,
|
|
194
|
-
aliases: args.aliases,
|
|
195
|
-
fallbackTable: args.fallbackTable,
|
|
196
|
-
});
|
|
197
|
-
if (tableName) selectAllTables.push(tableName);
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const columnName = getColumnName(selection.column);
|
|
202
|
-
const tableRef = getTableName(selection.table);
|
|
203
|
-
const tableName = resolveTableName({
|
|
204
|
-
refTable: tableRef,
|
|
205
|
-
aliases: args.aliases,
|
|
206
|
-
fallbackTable: args.fallbackTable,
|
|
207
|
-
});
|
|
208
|
-
if (!columnName || !tableName) continue;
|
|
209
|
-
|
|
210
|
-
explicit.push({
|
|
211
|
-
outputKey: columnName,
|
|
212
|
-
table: tableName,
|
|
213
|
-
column: columnName,
|
|
214
|
-
});
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (selection.kind === 'AliasNode' && isReferenceNode(selection.node)) {
|
|
219
|
-
const outputKey = getIdentifierName(selection.alias);
|
|
220
|
-
if (!outputKey) continue;
|
|
221
|
-
|
|
222
|
-
const reference = selection.node;
|
|
223
|
-
if (reference.column.kind === 'SelectAllNode') {
|
|
224
|
-
const tableRef = getTableName(reference.table);
|
|
225
|
-
const tableName = resolveTableName({
|
|
226
|
-
refTable: tableRef,
|
|
227
|
-
aliases: args.aliases,
|
|
228
|
-
fallbackTable: args.fallbackTable,
|
|
229
|
-
});
|
|
230
|
-
if (tableName) selectAllTables.push(tableName);
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const columnName = getColumnName(reference.column);
|
|
235
|
-
const tableRef = getTableName(reference.table);
|
|
236
|
-
const tableName = resolveTableName({
|
|
237
|
-
refTable: tableRef,
|
|
238
|
-
aliases: args.aliases,
|
|
239
|
-
fallbackTable: args.fallbackTable,
|
|
240
|
-
});
|
|
241
|
-
if (!columnName || !tableName) continue;
|
|
242
|
-
|
|
243
|
-
explicit.push({
|
|
244
|
-
outputKey,
|
|
245
|
-
table: tableName,
|
|
246
|
-
column: columnName,
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return { explicit, selectAllTables };
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function planForSelect(node: SelectQueryNode): QueryResultPlan | null {
|
|
255
|
-
if (!node.selections || node.selections.length === 0) return null;
|
|
256
|
-
const aliases = tableAliasMapForSelect(node);
|
|
257
|
-
const collected = collectSelectionReferences({
|
|
258
|
-
selections: node.selections,
|
|
259
|
-
aliases,
|
|
260
|
-
});
|
|
261
|
-
if (
|
|
262
|
-
collected.explicit.length === 0 &&
|
|
263
|
-
collected.selectAllTables.length === 0
|
|
264
|
-
) {
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
return collected;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function planForInsert(node: InsertQueryNode): QueryResultPlan | null {
|
|
271
|
-
if (!node.returning || node.returning.selections.length === 0) return null;
|
|
272
|
-
const tableName = getTableName(node.into);
|
|
273
|
-
if (!tableName) return null;
|
|
274
|
-
const aliases = new Map<string, string>([[tableName, tableName]]);
|
|
275
|
-
const collected = collectSelectionReferences({
|
|
276
|
-
selections: node.returning.selections,
|
|
277
|
-
aliases,
|
|
278
|
-
fallbackTable: tableName,
|
|
279
|
-
});
|
|
280
|
-
if (
|
|
281
|
-
collected.explicit.length === 0 &&
|
|
282
|
-
collected.selectAllTables.length === 0
|
|
283
|
-
) {
|
|
284
|
-
return null;
|
|
285
|
-
}
|
|
286
|
-
return collected;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
function planForUpdate(node: UpdateQueryNode): QueryResultPlan | null {
|
|
290
|
-
if (!node.returning || node.returning.selections.length === 0) return null;
|
|
291
|
-
const tableName = getTableName(node.table);
|
|
292
|
-
if (!tableName) return null;
|
|
293
|
-
const aliases = new Map<string, string>([[tableName, tableName]]);
|
|
294
|
-
const collected = collectSelectionReferences({
|
|
295
|
-
selections: node.returning.selections,
|
|
296
|
-
aliases,
|
|
297
|
-
fallbackTable: tableName,
|
|
298
|
-
});
|
|
299
|
-
if (
|
|
300
|
-
collected.explicit.length === 0 &&
|
|
301
|
-
collected.selectAllTables.length === 0
|
|
302
|
-
) {
|
|
303
|
-
return null;
|
|
304
|
-
}
|
|
305
|
-
return collected;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function planForDelete(node: DeleteQueryNode): QueryResultPlan | null {
|
|
309
|
-
if (!node.returning || node.returning.selections.length === 0) return null;
|
|
310
|
-
const fromTables = node.from?.froms ?? [];
|
|
311
|
-
if (fromTables.length !== 1) return null;
|
|
312
|
-
const fromItem = fromTables[0];
|
|
313
|
-
if (!fromItem) return null;
|
|
314
|
-
|
|
315
|
-
let tableName: string | undefined;
|
|
316
|
-
if (isTableNode(fromItem)) {
|
|
317
|
-
tableName = getTableName(fromItem);
|
|
318
|
-
} else if (isAliasNode(fromItem)) {
|
|
319
|
-
tableName = getBaseTableFromAlias(fromItem);
|
|
320
|
-
}
|
|
321
|
-
if (!tableName) return null;
|
|
322
|
-
|
|
323
|
-
const aliases = new Map<string, string>([[tableName, tableName]]);
|
|
324
|
-
const collected = collectSelectionReferences({
|
|
325
|
-
selections: node.returning.selections,
|
|
326
|
-
aliases,
|
|
327
|
-
fallbackTable: tableName,
|
|
328
|
-
});
|
|
329
|
-
if (
|
|
330
|
-
collected.explicit.length === 0 &&
|
|
331
|
-
collected.selectAllTables.length === 0
|
|
332
|
-
) {
|
|
333
|
-
return null;
|
|
334
|
-
}
|
|
335
|
-
return collected;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
export function buildQueryResultPlan(
|
|
339
|
-
node: RootOperationNode
|
|
340
|
-
): QueryResultPlan | null {
|
|
341
|
-
if (node.kind === 'SelectQueryNode') return planForSelect(node);
|
|
342
|
-
if (node.kind === 'InsertQueryNode') return planForInsert(node);
|
|
343
|
-
if (node.kind === 'UpdateQueryNode') return planForUpdate(node);
|
|
344
|
-
if (node.kind === 'DeleteQueryNode') return planForDelete(node);
|
|
345
|
-
return null;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
export function applyQueryResultPlan(args: {
|
|
349
|
-
row: UnknownRow;
|
|
350
|
-
plan: QueryResultPlan;
|
|
351
|
-
resolveTableCodecs: (
|
|
352
|
-
table: string,
|
|
353
|
-
row: Record<string, unknown>
|
|
354
|
-
) => TableColumnCodecs;
|
|
355
|
-
dialect: ColumnCodecDialect;
|
|
356
|
-
}): UnknownRow {
|
|
357
|
-
const { row, plan, resolveTableCodecs, dialect } = args;
|
|
358
|
-
const source = row as Record<string, unknown>;
|
|
359
|
-
const target: Record<string, unknown> = { ...source };
|
|
360
|
-
|
|
361
|
-
if (plan.selectAllTables.length > 0) {
|
|
362
|
-
const codecCandidates = new Map<string, AnyColumnCodec>();
|
|
363
|
-
const ambiguousColumns = new Set<string>();
|
|
364
|
-
|
|
365
|
-
for (const table of plan.selectAllTables) {
|
|
366
|
-
const tableCodecs = resolveTableCodecs(table, source);
|
|
367
|
-
for (const [column, codec] of Object.entries(tableCodecs)) {
|
|
368
|
-
if (!(column in source)) continue;
|
|
369
|
-
const existing = codecCandidates.get(column);
|
|
370
|
-
if (existing && existing !== codec) {
|
|
371
|
-
ambiguousColumns.add(column);
|
|
372
|
-
continue;
|
|
373
|
-
}
|
|
374
|
-
codecCandidates.set(column, codec);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
for (const [column, codec] of codecCandidates.entries()) {
|
|
379
|
-
if (ambiguousColumns.has(column)) continue;
|
|
380
|
-
target[column] = applyCodecFromDbValue(codec, target[column], dialect);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
for (const ref of plan.explicit) {
|
|
385
|
-
if (!(ref.outputKey in source)) continue;
|
|
386
|
-
const tableCodecs = resolveTableCodecs(ref.table, {
|
|
387
|
-
[ref.column]: source[ref.outputKey],
|
|
388
|
-
});
|
|
389
|
-
const codec = tableCodecs[ref.column];
|
|
390
|
-
if (!codec) continue;
|
|
391
|
-
target[ref.outputKey] = applyCodecFromDbValue(
|
|
392
|
-
codec,
|
|
393
|
-
target[ref.outputKey],
|
|
394
|
-
dialect
|
|
395
|
-
);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
return target;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
class ColumnCodecsTransformer extends OperationNodeTransformer {
|
|
402
|
-
readonly #dialect: ColumnCodecDialect;
|
|
403
|
-
readonly #resolveTableCodecs: (
|
|
404
|
-
table: string,
|
|
405
|
-
row: Record<string, unknown>
|
|
406
|
-
) => TableColumnCodecs;
|
|
407
|
-
#currentUpdateTable: string | null = null;
|
|
408
|
-
|
|
409
|
-
constructor(options: ColumnCodecPluginOptions) {
|
|
410
|
-
super();
|
|
411
|
-
this.#dialect = options.dialect ?? 'sqlite';
|
|
412
|
-
this.#resolveTableCodecs = createTableColumnCodecsResolver(options.codecs, {
|
|
413
|
-
dialect: this.#dialect,
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
protected override transformInsertQuery(
|
|
418
|
-
node: InsertQueryNode
|
|
419
|
-
): InsertQueryNode {
|
|
420
|
-
const transformed = super.transformInsertQuery(node);
|
|
421
|
-
if (!transformed.columns || transformed.columns.length === 0) {
|
|
422
|
-
return transformed;
|
|
423
|
-
}
|
|
424
|
-
if (!isValuesNode(transformed.values)) {
|
|
425
|
-
return transformed;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
const tableName = getTableName(transformed.into);
|
|
429
|
-
if (!tableName) return transformed;
|
|
430
|
-
|
|
431
|
-
const columns = transformed.columns
|
|
432
|
-
.map((columnNode) => getColumnName(columnNode))
|
|
433
|
-
.filter((columnName): columnName is string => Boolean(columnName));
|
|
434
|
-
if (columns.length === 0) return transformed;
|
|
435
|
-
|
|
436
|
-
const tableCodecs = this.#resolveTableCodecs(
|
|
437
|
-
tableName,
|
|
438
|
-
Object.fromEntries(columns.map((column) => [column, null]))
|
|
439
|
-
);
|
|
440
|
-
|
|
441
|
-
let didChange = false;
|
|
442
|
-
const nextValueRows = transformed.values.values.map((valueNode) => {
|
|
443
|
-
if (!isPrimitiveValueListNode(valueNode)) return valueNode;
|
|
444
|
-
|
|
445
|
-
const nextValues = valueNode.values.map(
|
|
446
|
-
(value: unknown, index: number) => {
|
|
447
|
-
const columnName = columns[index];
|
|
448
|
-
if (!columnName) return value;
|
|
449
|
-
const codec = tableCodecs[columnName];
|
|
450
|
-
if (!codec) return value;
|
|
451
|
-
const converted = applyCodecToDbValue(codec, value, this.#dialect);
|
|
452
|
-
if (converted !== value) {
|
|
453
|
-
didChange = true;
|
|
454
|
-
}
|
|
455
|
-
return converted;
|
|
456
|
-
}
|
|
457
|
-
);
|
|
458
|
-
|
|
459
|
-
if (!didChange) return valueNode;
|
|
460
|
-
return {
|
|
461
|
-
...valueNode,
|
|
462
|
-
values: nextValues,
|
|
463
|
-
};
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
if (!didChange) return transformed;
|
|
467
|
-
|
|
468
|
-
const nextValuesNode: ValuesNode = {
|
|
469
|
-
...transformed.values,
|
|
470
|
-
values: nextValueRows,
|
|
471
|
-
};
|
|
472
|
-
|
|
473
|
-
return {
|
|
474
|
-
...transformed,
|
|
475
|
-
values: nextValuesNode,
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
protected override transformUpdateQuery(
|
|
480
|
-
node: UpdateQueryNode
|
|
481
|
-
): UpdateQueryNode {
|
|
482
|
-
const previousTable = this.#currentUpdateTable;
|
|
483
|
-
this.#currentUpdateTable = getTableName(node.table) ?? null;
|
|
484
|
-
try {
|
|
485
|
-
return super.transformUpdateQuery(node);
|
|
486
|
-
} finally {
|
|
487
|
-
this.#currentUpdateTable = previousTable;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
protected override transformColumnUpdate(
|
|
492
|
-
node: ColumnUpdateNode,
|
|
493
|
-
queryId?: { readonly queryId: string }
|
|
494
|
-
): ColumnUpdateNode {
|
|
495
|
-
const transformed = super.transformColumnUpdate(node, queryId);
|
|
496
|
-
if (!this.#currentUpdateTable) return transformed;
|
|
497
|
-
if (!isValueNode(transformed.value)) return transformed;
|
|
498
|
-
|
|
499
|
-
const columnName = getColumnName(transformed.column);
|
|
500
|
-
if (!columnName) return transformed;
|
|
501
|
-
|
|
502
|
-
const tableCodecs = this.#resolveTableCodecs(this.#currentUpdateTable, {
|
|
503
|
-
[columnName]: null,
|
|
504
|
-
});
|
|
505
|
-
const codec = tableCodecs[columnName];
|
|
506
|
-
if (!codec) return transformed;
|
|
507
|
-
|
|
508
|
-
const valueNode = transformed.value;
|
|
509
|
-
const converted = applyCodecToDbValue(
|
|
510
|
-
codec,
|
|
511
|
-
valueNode.value,
|
|
512
|
-
this.#dialect
|
|
513
|
-
);
|
|
514
|
-
if (converted === valueNode.value) return transformed;
|
|
515
|
-
|
|
516
|
-
const nextValueNode: ValueNode = {
|
|
517
|
-
...valueNode,
|
|
518
|
-
value: converted,
|
|
519
|
-
};
|
|
520
|
-
return {
|
|
521
|
-
...transformed,
|
|
522
|
-
value: nextValueNode,
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
export class ColumnCodecsPlugin implements KyselyPlugin {
|
|
528
|
-
readonly #dialect: ColumnCodecDialect;
|
|
529
|
-
readonly #transformer: ColumnCodecsTransformer;
|
|
530
|
-
readonly #resultPlans = new WeakMap<object, QueryResultPlan>();
|
|
531
|
-
readonly #resolveTableCodecs: (
|
|
532
|
-
table: string,
|
|
533
|
-
row: Record<string, unknown>
|
|
534
|
-
) => TableColumnCodecs;
|
|
535
|
-
|
|
536
|
-
constructor(options: ColumnCodecPluginOptions) {
|
|
537
|
-
this.#dialect = options.dialect ?? 'sqlite';
|
|
538
|
-
this.#resolveTableCodecs = createTableColumnCodecsResolver(options.codecs, {
|
|
539
|
-
dialect: this.#dialect,
|
|
540
|
-
});
|
|
541
|
-
this.#transformer = new ColumnCodecsTransformer(options);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
transformQuery({
|
|
545
|
-
node,
|
|
546
|
-
queryId,
|
|
547
|
-
}: PluginTransformQueryArgs): RootOperationNode {
|
|
548
|
-
const transformed = this.#transformer.transformNode(node);
|
|
549
|
-
const plan = buildQueryResultPlan(transformed);
|
|
550
|
-
if (plan) {
|
|
551
|
-
this.#resultPlans.set(queryId, plan);
|
|
552
|
-
}
|
|
553
|
-
return transformed;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
async transformResult({
|
|
557
|
-
result,
|
|
558
|
-
queryId,
|
|
559
|
-
}: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>> {
|
|
560
|
-
const plan = this.#resultPlans.get(queryId);
|
|
561
|
-
if (!plan) return result;
|
|
562
|
-
if (!result.rows || result.rows.length === 0) return result;
|
|
563
|
-
|
|
564
|
-
const rows = result.rows.map((row) => this.#transformRow(row, plan));
|
|
565
|
-
return {
|
|
566
|
-
...result,
|
|
567
|
-
rows,
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
#transformRow(row: UnknownRow, plan: QueryResultPlan): UnknownRow {
|
|
572
|
-
return applyQueryResultPlan({
|
|
573
|
-
row,
|
|
574
|
-
plan,
|
|
575
|
-
resolveTableCodecs: this.#resolveTableCodecs,
|
|
576
|
-
dialect: this.#dialect,
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
export function createColumnCodecsPlugin(
|
|
582
|
-
options: ColumnCodecPluginOptions
|
|
583
|
-
): ColumnCodecsPlugin {
|
|
584
|
-
return new ColumnCodecsPlugin(options);
|
|
585
|
-
}
|
package/src/logger.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @syncular/core - Structured logging utilities for sync operations
|
|
3
|
-
*
|
|
4
|
-
* Uses the active telemetry backend configured via `configureSyncTelemetry()`.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { getSyncTelemetry, type SyncTelemetryEvent } from './telemetry';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Sync log event structure.
|
|
11
|
-
*/
|
|
12
|
-
export type SyncLogEvent = SyncTelemetryEvent;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Logger function type.
|
|
16
|
-
*/
|
|
17
|
-
export type SyncLogger = (event: SyncLogEvent) => void;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Log a sync event using the currently configured telemetry backend.
|
|
21
|
-
*/
|
|
22
|
-
export const logSyncEvent: SyncLogger = (event) => {
|
|
23
|
-
getSyncTelemetry().log(event);
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Create a timer for measuring operation duration.
|
|
28
|
-
* Returns the elapsed time in milliseconds when called.
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* const elapsed = createSyncTimer();
|
|
32
|
-
* await doSomeWork();
|
|
33
|
-
* logSyncEvent({ event: 'work_complete', durationMs: elapsed() });
|
|
34
|
-
*/
|
|
35
|
-
export function createSyncTimer(): () => number {
|
|
36
|
-
const start = performance.now();
|
|
37
|
-
return () => Math.round(performance.now() - start);
|
|
38
|
-
}
|
package/src/proxy/index.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @syncular/core - Proxy Protocol Types
|
|
3
|
-
*
|
|
4
|
-
* Shared protocol types between proxy client (Kysely dialect) and server (WebSocket handler).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Message sent from proxy client to server.
|
|
9
|
-
*/
|
|
10
|
-
export interface ProxyMessage {
|
|
11
|
-
/** Correlation ID for matching request/response */
|
|
12
|
-
id: string;
|
|
13
|
-
/** Message type */
|
|
14
|
-
type: 'query' | 'begin' | 'commit' | 'rollback';
|
|
15
|
-
/** SQL query (for 'query' type) */
|
|
16
|
-
sql?: string;
|
|
17
|
-
/** Query parameters (for 'query' type) */
|
|
18
|
-
parameters?: readonly unknown[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Response sent from server to proxy client.
|
|
23
|
-
*/
|
|
24
|
-
export interface ProxyResponse {
|
|
25
|
-
/** Correlation ID matching the request */
|
|
26
|
-
id: string;
|
|
27
|
-
/** Response type */
|
|
28
|
-
type: 'result' | 'error';
|
|
29
|
-
/** Query result rows (for SELECT queries) */
|
|
30
|
-
rows?: unknown[];
|
|
31
|
-
/** Number of affected rows (for mutations) */
|
|
32
|
-
rowCount?: number;
|
|
33
|
-
/** Error message (for 'error' type) */
|
|
34
|
-
error?: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Handshake message sent when connection is established.
|
|
39
|
-
*/
|
|
40
|
-
export interface ProxyHandshake {
|
|
41
|
-
type: 'handshake';
|
|
42
|
-
/** Actor ID for oplog tracking */
|
|
43
|
-
actorId: string;
|
|
44
|
-
/** Client ID for oplog tracking */
|
|
45
|
-
clientId: string;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Handshake acknowledgement from server.
|
|
50
|
-
*/
|
|
51
|
-
export interface ProxyHandshakeAck {
|
|
52
|
-
type: 'handshake_ack';
|
|
53
|
-
/** Whether handshake was successful */
|
|
54
|
-
ok: boolean;
|
|
55
|
-
/** Error message if handshake failed */
|
|
56
|
-
error?: string;
|
|
57
|
-
}
|