js-bao 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.cjs +367 -1
- package/dist/browser.d.cts +126 -1
- package/dist/browser.d.ts +126 -1
- package/dist/browser.js +367 -1
- package/dist/client.cjs +16 -11
- package/dist/client.d.cts +3 -1
- package/dist/client.d.ts +3 -1
- package/dist/client.js +16 -11
- package/dist/cloudflare-do.cjs +937 -286
- package/dist/cloudflare-do.d.cts +517 -15
- package/dist/cloudflare-do.d.ts +517 -15
- package/dist/cloudflare-do.js +928 -286
- package/dist/cloudflare.cjs +573 -18
- package/dist/cloudflare.d.cts +147 -2
- package/dist/cloudflare.d.ts +147 -2
- package/dist/cloudflare.js +573 -18
- package/dist/codegen.cjs +6 -6
- package/dist/index.cjs +19 -10
- package/dist/index.js +19 -10
- package/dist/node.cjs +388 -6
- package/dist/node.d.cts +131 -1
- package/dist/node.d.ts +131 -1
- package/dist/node.js +377 -5
- package/package.json +6 -6
package/dist/cloudflare.js
CHANGED
|
@@ -59,14 +59,138 @@ var init_DocumentQueryTranslator = __esm({
|
|
|
59
59
|
|
|
60
60
|
// src/models/metaSync.ts
|
|
61
61
|
import * as Y from "yjs";
|
|
62
|
+
function inferFieldType(value) {
|
|
63
|
+
if (value instanceof Y.Map) return "stringset";
|
|
64
|
+
switch (typeof value) {
|
|
65
|
+
case "string":
|
|
66
|
+
return "string";
|
|
67
|
+
case "number":
|
|
68
|
+
return "number";
|
|
69
|
+
case "boolean":
|
|
70
|
+
return "boolean";
|
|
71
|
+
default:
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
62
75
|
function registerFunctionDefault(fn, name) {
|
|
63
76
|
KNOWN_FUNCTION_DEFAULTS.set(fn, name);
|
|
64
77
|
}
|
|
65
|
-
|
|
78
|
+
function encodeDefault(value) {
|
|
79
|
+
if (value === void 0 || value === null) return void 0;
|
|
80
|
+
if (typeof value === "function") {
|
|
81
|
+
const name = KNOWN_FUNCTION_DEFAULTS.get(value);
|
|
82
|
+
return name ? `$${name}` : "$unknown_function";
|
|
83
|
+
}
|
|
84
|
+
return value;
|
|
85
|
+
}
|
|
86
|
+
function clearMetaSyncCache(yDoc) {
|
|
87
|
+
if (yDoc) {
|
|
88
|
+
_syncedCache.delete(yDoc);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function syncModelMeta(yDoc, modelName, schema) {
|
|
92
|
+
let synced = _syncedCache.get(yDoc);
|
|
93
|
+
if (synced?.has(modelName)) return;
|
|
94
|
+
if (!synced) {
|
|
95
|
+
synced = /* @__PURE__ */ new Set();
|
|
96
|
+
_syncedCache.set(yDoc, synced);
|
|
97
|
+
}
|
|
98
|
+
const meta = yDoc.getMap(`_meta_${modelName}`);
|
|
99
|
+
for (const [fieldName, fieldOpts] of schema.fields.entries()) {
|
|
100
|
+
syncFieldMeta(meta, fieldName, fieldOpts);
|
|
101
|
+
}
|
|
102
|
+
const compoundConstraints = schema.resolvedUniqueConstraints.filter(
|
|
103
|
+
(c) => c.fields.length > 1
|
|
104
|
+
);
|
|
105
|
+
if (compoundConstraints.length > 0) {
|
|
106
|
+
let constraints = meta.get("_constraints");
|
|
107
|
+
if (!constraints) {
|
|
108
|
+
constraints = new Y.Map();
|
|
109
|
+
meta.set("_constraints", constraints);
|
|
110
|
+
}
|
|
111
|
+
for (const constraint of compoundConstraints) {
|
|
112
|
+
syncConstraintMeta(constraints, constraint);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const relationships = schema.options.relationships;
|
|
116
|
+
if (relationships && Object.keys(relationships).length > 0) {
|
|
117
|
+
let rels = meta.get("_relationships");
|
|
118
|
+
if (!rels) {
|
|
119
|
+
rels = new Y.Map();
|
|
120
|
+
meta.set("_relationships", rels);
|
|
121
|
+
}
|
|
122
|
+
for (const [relName, relConfig] of Object.entries(relationships)) {
|
|
123
|
+
syncRelationshipMeta(rels, relName, relConfig);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
synced.add(modelName);
|
|
127
|
+
}
|
|
128
|
+
function syncFieldMeta(metaMap, fieldName, fieldOpts) {
|
|
129
|
+
let fieldMeta = metaMap.get(fieldName);
|
|
130
|
+
if (!fieldMeta) {
|
|
131
|
+
fieldMeta = new Y.Map();
|
|
132
|
+
metaMap.set(fieldName, fieldMeta);
|
|
133
|
+
}
|
|
134
|
+
setIfChanged(fieldMeta, "type", fieldOpts.type);
|
|
135
|
+
if (fieldOpts.indexed) setIfChanged(fieldMeta, "indexed", true);
|
|
136
|
+
if (fieldOpts.unique) setIfChanged(fieldMeta, "unique", true);
|
|
137
|
+
if (fieldOpts.required) setIfChanged(fieldMeta, "required", true);
|
|
138
|
+
if (fieldOpts.autoAssign) setIfChanged(fieldMeta, "autoAssign", true);
|
|
139
|
+
if (fieldOpts.maxLength !== void 0) setIfChanged(fieldMeta, "maxLength", fieldOpts.maxLength);
|
|
140
|
+
if (fieldOpts.maxCount !== void 0) setIfChanged(fieldMeta, "maxCount", fieldOpts.maxCount);
|
|
141
|
+
const encoded = encodeDefault(fieldOpts.default);
|
|
142
|
+
if (encoded !== void 0) setIfChanged(fieldMeta, "default", encoded);
|
|
143
|
+
}
|
|
144
|
+
function syncConstraintMeta(constraintsMap, constraint) {
|
|
145
|
+
let cMeta = constraintsMap.get(constraint.name);
|
|
146
|
+
if (!cMeta) {
|
|
147
|
+
cMeta = new Y.Map();
|
|
148
|
+
constraintsMap.set(constraint.name, cMeta);
|
|
149
|
+
}
|
|
150
|
+
setIfChanged(cMeta, "type", "unique");
|
|
151
|
+
const fieldsJson = JSON.stringify(constraint.fields);
|
|
152
|
+
setIfChanged(cMeta, "fields", fieldsJson);
|
|
153
|
+
}
|
|
154
|
+
function syncRelationshipMeta(relsMap, relName, relConfig) {
|
|
155
|
+
let relMeta = relsMap.get(relName);
|
|
156
|
+
if (!relMeta) {
|
|
157
|
+
relMeta = new Y.Map();
|
|
158
|
+
relsMap.set(relName, relMeta);
|
|
159
|
+
}
|
|
160
|
+
for (const [key, value] of Object.entries(relConfig)) {
|
|
161
|
+
if (value !== void 0) {
|
|
162
|
+
setIfChanged(relMeta, key, value);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function syncInferredMeta(yDoc, modelName, recordData) {
|
|
167
|
+
const meta = yDoc.getMap(`_meta_${modelName}`);
|
|
168
|
+
for (const [fieldName, value] of Object.entries(recordData)) {
|
|
169
|
+
if (fieldName.startsWith("_")) continue;
|
|
170
|
+
let fieldMeta = meta.get(fieldName);
|
|
171
|
+
if (!fieldMeta) {
|
|
172
|
+
fieldMeta = new Y.Map();
|
|
173
|
+
meta.set(fieldName, fieldMeta);
|
|
174
|
+
}
|
|
175
|
+
if (!fieldMeta.has("type")) {
|
|
176
|
+
const inferredType = inferFieldType(value);
|
|
177
|
+
if (inferredType) {
|
|
178
|
+
fieldMeta.set("type", inferredType);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function setIfChanged(map, key, value) {
|
|
184
|
+
if (map.get(key) !== value) {
|
|
185
|
+
map.set(key, value);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
var KNOWN_FUNCTION_DEFAULTS, _syncedCache;
|
|
66
189
|
var init_metaSync = __esm({
|
|
67
190
|
"src/models/metaSync.ts"() {
|
|
68
191
|
"use strict";
|
|
69
192
|
KNOWN_FUNCTION_DEFAULTS = /* @__PURE__ */ new WeakMap();
|
|
193
|
+
_syncedCache = /* @__PURE__ */ new WeakMap();
|
|
70
194
|
}
|
|
71
195
|
});
|
|
72
196
|
|
|
@@ -158,6 +282,23 @@ var init_BaseModel = __esm({
|
|
|
158
282
|
}
|
|
159
283
|
});
|
|
160
284
|
|
|
285
|
+
// src/models/relationshipManager.ts
|
|
286
|
+
var init_relationshipManager = __esm({
|
|
287
|
+
"src/models/relationshipManager.ts"() {
|
|
288
|
+
"use strict";
|
|
289
|
+
init_BaseModel();
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// src/models/ModelRegistry.ts
|
|
294
|
+
var init_ModelRegistry = __esm({
|
|
295
|
+
"src/models/ModelRegistry.ts"() {
|
|
296
|
+
"use strict";
|
|
297
|
+
init_BaseModel();
|
|
298
|
+
init_relationshipManager();
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
161
302
|
// src/initialize-do.ts
|
|
162
303
|
init_BaseModel();
|
|
163
304
|
|
|
@@ -302,7 +443,8 @@ var DOClientEngine = class extends DatabaseEngine {
|
|
|
302
443
|
data,
|
|
303
444
|
stringSets,
|
|
304
445
|
ifNotExists: options?.ifNotExists,
|
|
305
|
-
condition: options?.condition
|
|
446
|
+
condition: options?.condition,
|
|
447
|
+
upsertOn: options?.upsertOn
|
|
306
448
|
};
|
|
307
449
|
const response = await this.doFetch("/save", request);
|
|
308
450
|
return response.id;
|
|
@@ -669,22 +811,24 @@ async function initJsBaoDO(options) {
|
|
|
669
811
|
if (!docId) {
|
|
670
812
|
throw new Error("Not connected to a document. Call connectDocument() first.");
|
|
671
813
|
}
|
|
672
|
-
if (!data.id) {
|
|
673
|
-
throw new Error("Record must have an 'id' field");
|
|
674
|
-
}
|
|
675
814
|
let stringSets;
|
|
676
815
|
let ifNotExists;
|
|
677
816
|
let condition;
|
|
817
|
+
let upsertOn;
|
|
678
818
|
if (options2 && typeof options2 === "object") {
|
|
679
|
-
if (options2.ifNotExists !== void 0 || options2.stringSets !== void 0 || options2.condition !== void 0) {
|
|
819
|
+
if (options2.ifNotExists !== void 0 || options2.stringSets !== void 0 || options2.condition !== void 0 || options2.upsertOn !== void 0) {
|
|
680
820
|
stringSets = options2.stringSets;
|
|
681
821
|
ifNotExists = options2.ifNotExists;
|
|
682
822
|
condition = options2.condition;
|
|
823
|
+
upsertOn = options2.upsertOn;
|
|
683
824
|
} else {
|
|
684
825
|
stringSets = options2;
|
|
685
826
|
}
|
|
686
827
|
}
|
|
687
|
-
|
|
828
|
+
if (!data.id && !upsertOn) {
|
|
829
|
+
throw new Error("Record must have an 'id' field (or use upsertOn)");
|
|
830
|
+
}
|
|
831
|
+
return engine.saveModel(resolveModelName(model), data.id, data, stringSets, { ifNotExists, condition, upsertOn });
|
|
688
832
|
},
|
|
689
833
|
patch: async (model, id, data, options2) => {
|
|
690
834
|
const docId = engine.getCurrentDocument();
|
|
@@ -843,22 +987,24 @@ function createModelAccessor(engine, modelName) {
|
|
|
843
987
|
return result.data.length > 0 ? result.data[0] : null;
|
|
844
988
|
},
|
|
845
989
|
save: (data, options) => {
|
|
846
|
-
if (!data.id) {
|
|
847
|
-
throw new Error("Record must have an 'id' field");
|
|
848
|
-
}
|
|
849
990
|
let stringSets;
|
|
850
991
|
let ifNotExists;
|
|
851
992
|
let condition;
|
|
993
|
+
let upsertOn;
|
|
852
994
|
if (options && typeof options === "object") {
|
|
853
|
-
if (options.ifNotExists !== void 0 || options.stringSets !== void 0 || options.condition !== void 0) {
|
|
995
|
+
if (options.ifNotExists !== void 0 || options.stringSets !== void 0 || options.condition !== void 0 || options.upsertOn !== void 0) {
|
|
854
996
|
stringSets = options.stringSets;
|
|
855
997
|
ifNotExists = options.ifNotExists;
|
|
856
998
|
condition = options.condition;
|
|
999
|
+
upsertOn = options.upsertOn;
|
|
857
1000
|
} else {
|
|
858
1001
|
stringSets = options;
|
|
859
1002
|
}
|
|
860
1003
|
}
|
|
861
|
-
|
|
1004
|
+
if (!data.id && !upsertOn) {
|
|
1005
|
+
throw new Error("Record must have an 'id' field (or use upsertOn)");
|
|
1006
|
+
}
|
|
1007
|
+
return engine.saveModel(modelName, data.id, data, stringSets, { ifNotExists, condition, upsertOn });
|
|
862
1008
|
},
|
|
863
1009
|
patch: (id, data, options) => {
|
|
864
1010
|
let stringSets;
|
|
@@ -945,22 +1091,24 @@ function connectDoDb(options) {
|
|
|
945
1091
|
return result.data.length > 0 ? result.data[0] : null;
|
|
946
1092
|
},
|
|
947
1093
|
save: (model, data, options2) => {
|
|
948
|
-
if (!data.id) {
|
|
949
|
-
throw new Error("Record must have an 'id' field");
|
|
950
|
-
}
|
|
951
1094
|
let stringSets;
|
|
952
1095
|
let ifNotExists;
|
|
953
1096
|
let condition;
|
|
1097
|
+
let upsertOn;
|
|
954
1098
|
if (options2 && typeof options2 === "object") {
|
|
955
|
-
if (options2.ifNotExists !== void 0 || options2.stringSets !== void 0 || options2.condition !== void 0) {
|
|
1099
|
+
if (options2.ifNotExists !== void 0 || options2.stringSets !== void 0 || options2.condition !== void 0 || options2.upsertOn !== void 0) {
|
|
956
1100
|
stringSets = options2.stringSets;
|
|
957
1101
|
ifNotExists = options2.ifNotExists;
|
|
958
1102
|
condition = options2.condition;
|
|
1103
|
+
upsertOn = options2.upsertOn;
|
|
959
1104
|
} else {
|
|
960
1105
|
stringSets = options2;
|
|
961
1106
|
}
|
|
962
1107
|
}
|
|
963
|
-
|
|
1108
|
+
if (!data.id && !upsertOn) {
|
|
1109
|
+
throw new Error("Record must have an 'id' field (or use upsertOn)");
|
|
1110
|
+
}
|
|
1111
|
+
return engine.saveModel(resolveModelName(model), data.id, data, stringSets, { ifNotExists, condition, upsertOn });
|
|
964
1112
|
},
|
|
965
1113
|
patch: (model, id2, data, options2) => {
|
|
966
1114
|
let stringSets;
|
|
@@ -1026,10 +1174,417 @@ function connectDoDb(options) {
|
|
|
1026
1174
|
Logger.info(`[connectDoDb] Connected to document: ${id} at ${endpoint}`);
|
|
1027
1175
|
return db;
|
|
1028
1176
|
}
|
|
1177
|
+
|
|
1178
|
+
// src/utils/yDocSchema.ts
|
|
1179
|
+
import * as Y3 from "yjs";
|
|
1180
|
+
function discoverSchema(yDoc) {
|
|
1181
|
+
const models = {};
|
|
1182
|
+
const metaNames = /* @__PURE__ */ new Set();
|
|
1183
|
+
for (const key of yDoc.share.keys()) {
|
|
1184
|
+
if (!key.startsWith("_meta_")) continue;
|
|
1185
|
+
const map = materializeMap(yDoc, key);
|
|
1186
|
+
if (!map) continue;
|
|
1187
|
+
const modelName = key.slice("_meta_".length);
|
|
1188
|
+
metaNames.add(modelName);
|
|
1189
|
+
models[modelName] = readModelMeta(map);
|
|
1190
|
+
}
|
|
1191
|
+
for (const key of yDoc.share.keys()) {
|
|
1192
|
+
if (key.startsWith("_")) continue;
|
|
1193
|
+
if (metaNames.has(key)) continue;
|
|
1194
|
+
const map = materializeMap(yDoc, key);
|
|
1195
|
+
if (!map || map.size === 0) continue;
|
|
1196
|
+
const inferred = inferModelFromData(map);
|
|
1197
|
+
if (inferred) models[key] = inferred;
|
|
1198
|
+
}
|
|
1199
|
+
return { models };
|
|
1200
|
+
}
|
|
1201
|
+
function discoverModelNames(yDoc) {
|
|
1202
|
+
const names = [];
|
|
1203
|
+
for (const key of yDoc.share.keys()) {
|
|
1204
|
+
if (key.startsWith("_")) continue;
|
|
1205
|
+
const map = materializeMap(yDoc, key);
|
|
1206
|
+
if (map) names.push(key);
|
|
1207
|
+
}
|
|
1208
|
+
return names.sort();
|
|
1209
|
+
}
|
|
1210
|
+
function materializeMap(yDoc, key) {
|
|
1211
|
+
try {
|
|
1212
|
+
const map = yDoc.getMap(key);
|
|
1213
|
+
return map instanceof Y3.Map ? map : null;
|
|
1214
|
+
} catch {
|
|
1215
|
+
return null;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
function readModelMeta(metaMap) {
|
|
1219
|
+
const fields = {};
|
|
1220
|
+
let constraints;
|
|
1221
|
+
let relationships;
|
|
1222
|
+
for (const [key, value] of metaMap.entries()) {
|
|
1223
|
+
if (key === "_constraints" && value instanceof Y3.Map) {
|
|
1224
|
+
constraints = readConstraints(value);
|
|
1225
|
+
} else if (key === "_relationships" && value instanceof Y3.Map) {
|
|
1226
|
+
relationships = readRelationships(value);
|
|
1227
|
+
} else if (value instanceof Y3.Map) {
|
|
1228
|
+
fields[key] = readFieldMeta(value);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
const model = { fields };
|
|
1232
|
+
if (constraints && Object.keys(constraints).length > 0) {
|
|
1233
|
+
model.constraints = constraints;
|
|
1234
|
+
}
|
|
1235
|
+
if (relationships && Object.keys(relationships).length > 0) {
|
|
1236
|
+
model.relationships = relationships;
|
|
1237
|
+
}
|
|
1238
|
+
return model;
|
|
1239
|
+
}
|
|
1240
|
+
function readFieldMeta(fieldMap) {
|
|
1241
|
+
const field = { type: fieldMap.get("type") ?? "unknown" };
|
|
1242
|
+
if (fieldMap.get("indexed") === true) field.indexed = true;
|
|
1243
|
+
if (fieldMap.get("unique") === true) field.unique = true;
|
|
1244
|
+
if (fieldMap.get("required") === true) field.required = true;
|
|
1245
|
+
if (fieldMap.get("autoAssign") === true) field.autoAssign = true;
|
|
1246
|
+
const def = fieldMap.get("default");
|
|
1247
|
+
if (def !== void 0) field.default = def;
|
|
1248
|
+
const maxLength = fieldMap.get("maxLength");
|
|
1249
|
+
if (maxLength !== void 0) field.maxLength = maxLength;
|
|
1250
|
+
const maxCount = fieldMap.get("maxCount");
|
|
1251
|
+
if (maxCount !== void 0) field.maxCount = maxCount;
|
|
1252
|
+
return field;
|
|
1253
|
+
}
|
|
1254
|
+
function inferModelFromData(dataMap) {
|
|
1255
|
+
const fields = {};
|
|
1256
|
+
let sampled = 0;
|
|
1257
|
+
for (const [_recordId, recordValue] of dataMap.entries()) {
|
|
1258
|
+
if (!(recordValue instanceof Y3.Map)) continue;
|
|
1259
|
+
if (++sampled > 5) break;
|
|
1260
|
+
for (const [fieldName, value] of recordValue.entries()) {
|
|
1261
|
+
if (fieldName.startsWith("_")) continue;
|
|
1262
|
+
if (fields[fieldName]) continue;
|
|
1263
|
+
const type = inferTypeFromValue(value);
|
|
1264
|
+
if (type) fields[fieldName] = { type };
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
if (Object.keys(fields).length === 0) return null;
|
|
1268
|
+
return { fields };
|
|
1269
|
+
}
|
|
1270
|
+
function inferTypeFromValue(value) {
|
|
1271
|
+
if (value instanceof Y3.Map) return "stringset";
|
|
1272
|
+
switch (typeof value) {
|
|
1273
|
+
case "string":
|
|
1274
|
+
return "string";
|
|
1275
|
+
case "number":
|
|
1276
|
+
return "number";
|
|
1277
|
+
case "boolean":
|
|
1278
|
+
return "boolean";
|
|
1279
|
+
default:
|
|
1280
|
+
return null;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
function readConstraints(constraintsMap) {
|
|
1284
|
+
const out = {};
|
|
1285
|
+
for (const [name, value] of constraintsMap.entries()) {
|
|
1286
|
+
if (!(value instanceof Y3.Map)) continue;
|
|
1287
|
+
let fields = [];
|
|
1288
|
+
const rawFields = value.get("fields");
|
|
1289
|
+
if (typeof rawFields === "string") {
|
|
1290
|
+
try {
|
|
1291
|
+
fields = JSON.parse(rawFields);
|
|
1292
|
+
} catch {
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
out[name] = {
|
|
1296
|
+
type: value.get("type") ?? "unknown",
|
|
1297
|
+
fields
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
return out;
|
|
1301
|
+
}
|
|
1302
|
+
function readRelationships(relsMap) {
|
|
1303
|
+
const out = {};
|
|
1304
|
+
for (const [name, value] of relsMap.entries()) {
|
|
1305
|
+
if (!(value instanceof Y3.Map)) continue;
|
|
1306
|
+
const rel = {};
|
|
1307
|
+
for (const [k, v] of value.entries()) {
|
|
1308
|
+
rel[k] = v;
|
|
1309
|
+
}
|
|
1310
|
+
out[name] = rel;
|
|
1311
|
+
}
|
|
1312
|
+
return out;
|
|
1313
|
+
}
|
|
1314
|
+
var CAMEL_TO_SNAKE = {
|
|
1315
|
+
autoAssign: "auto_assign",
|
|
1316
|
+
maxLength: "max_length",
|
|
1317
|
+
maxCount: "max_count",
|
|
1318
|
+
relatedIdField: "related_id_field",
|
|
1319
|
+
joinModel: "join_model",
|
|
1320
|
+
joinModelLocalField: "join_model_local_field",
|
|
1321
|
+
joinModelRelatedField: "join_model_related_field",
|
|
1322
|
+
joinModelOrderByField: "join_model_order_by_field",
|
|
1323
|
+
joinModelOrderDirection: "join_model_order_direction",
|
|
1324
|
+
orderByField: "order_by_field",
|
|
1325
|
+
orderDirection: "order_direction"
|
|
1326
|
+
};
|
|
1327
|
+
function toSnake(key) {
|
|
1328
|
+
return CAMEL_TO_SNAKE[key] ?? key;
|
|
1329
|
+
}
|
|
1330
|
+
function tomlValue(v) {
|
|
1331
|
+
if (typeof v === "string") {
|
|
1332
|
+
return `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")}"`;
|
|
1333
|
+
}
|
|
1334
|
+
return String(v);
|
|
1335
|
+
}
|
|
1336
|
+
function schemaToToml(schema) {
|
|
1337
|
+
const lines = [];
|
|
1338
|
+
for (const [modelName, model] of Object.entries(schema.models)) {
|
|
1339
|
+
if (lines.length > 0) lines.push("", "");
|
|
1340
|
+
lines.push(`[models.${modelName}]`);
|
|
1341
|
+
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
1342
|
+
lines.push("");
|
|
1343
|
+
lines.push(`[models.${modelName}.fields.${fieldName}]`);
|
|
1344
|
+
lines.push(`type = ${tomlValue(field.type)}`);
|
|
1345
|
+
if (field.autoAssign) lines.push("auto_assign = true");
|
|
1346
|
+
if (field.indexed) lines.push("indexed = true");
|
|
1347
|
+
if (field.unique) lines.push("unique = true");
|
|
1348
|
+
if (field.required) lines.push("required = true");
|
|
1349
|
+
if (field.maxLength !== void 0) lines.push(`max_length = ${field.maxLength}`);
|
|
1350
|
+
if (field.maxCount !== void 0) lines.push(`max_count = ${field.maxCount}`);
|
|
1351
|
+
if (field.default !== void 0) lines.push(`default = ${tomlValue(field.default)}`);
|
|
1352
|
+
}
|
|
1353
|
+
if (model.relationships) {
|
|
1354
|
+
for (const [relName, rel] of Object.entries(model.relationships)) {
|
|
1355
|
+
lines.push("");
|
|
1356
|
+
lines.push(`[models.${modelName}.relationships.${relName}]`);
|
|
1357
|
+
for (const [k, v] of Object.entries(rel)) {
|
|
1358
|
+
if (v === void 0) continue;
|
|
1359
|
+
lines.push(`${toSnake(k)} = ${tomlValue(v)}`);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
if (model.constraints) {
|
|
1364
|
+
for (const [cName, c] of Object.entries(model.constraints)) {
|
|
1365
|
+
lines.push("");
|
|
1366
|
+
lines.push(`[[models.${modelName}.unique_constraints]]`);
|
|
1367
|
+
lines.push(`name = ${tomlValue(cName)}`);
|
|
1368
|
+
lines.push(`fields = [${c.fields.map((f) => tomlValue(f)).join(", ")}]`);
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
lines.push("");
|
|
1373
|
+
return lines.join("\n");
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
// src/models/tomlLoader.ts
|
|
1377
|
+
import { parse as parseToml } from "smol-toml";
|
|
1378
|
+
|
|
1379
|
+
// src/models/schema.ts
|
|
1380
|
+
init_BaseModel();
|
|
1381
|
+
init_ModelRegistry();
|
|
1382
|
+
function defineModelSchema(input) {
|
|
1383
|
+
const { name, fields } = input;
|
|
1384
|
+
const options = {
|
|
1385
|
+
name,
|
|
1386
|
+
uniqueConstraints: input.options?.uniqueConstraints ? [...input.options.uniqueConstraints] : void 0,
|
|
1387
|
+
relationships: input.options?.relationships
|
|
1388
|
+
};
|
|
1389
|
+
const schema = {
|
|
1390
|
+
name,
|
|
1391
|
+
fields,
|
|
1392
|
+
options,
|
|
1393
|
+
runtimeShape: void 0,
|
|
1394
|
+
buildRuntimeShape(modelClass) {
|
|
1395
|
+
if (schema.runtimeShape && schema.runtimeShape.class === modelClass) {
|
|
1396
|
+
return schema.runtimeShape;
|
|
1397
|
+
}
|
|
1398
|
+
const fieldsMap = /* @__PURE__ */ new Map();
|
|
1399
|
+
for (const [fieldName, fieldOptions] of Object.entries(fields)) {
|
|
1400
|
+
fieldsMap.set(fieldName, { ...fieldOptions });
|
|
1401
|
+
}
|
|
1402
|
+
const resolvedUniqueConstraints = resolveUniqueConstraints(
|
|
1403
|
+
name,
|
|
1404
|
+
fieldsMap,
|
|
1405
|
+
options.uniqueConstraints
|
|
1406
|
+
);
|
|
1407
|
+
schema.runtimeShape = {
|
|
1408
|
+
class: modelClass,
|
|
1409
|
+
options,
|
|
1410
|
+
fields: fieldsMap,
|
|
1411
|
+
resolvedUniqueConstraints
|
|
1412
|
+
};
|
|
1413
|
+
return schema.runtimeShape;
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
return schema;
|
|
1417
|
+
}
|
|
1418
|
+
function resolveUniqueConstraints(modelName, fields, customConstraints) {
|
|
1419
|
+
const resolved = [];
|
|
1420
|
+
for (const [fieldName, options] of fields.entries()) {
|
|
1421
|
+
if (options.unique) {
|
|
1422
|
+
resolved.push({
|
|
1423
|
+
name: `${modelName}_${fieldName}_unique`,
|
|
1424
|
+
fields: [fieldName]
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
if (customConstraints) {
|
|
1429
|
+
for (const constraint of customConstraints) {
|
|
1430
|
+
const missingField = constraint.fields.find(
|
|
1431
|
+
(field) => !fields.has(field)
|
|
1432
|
+
);
|
|
1433
|
+
if (missingField) {
|
|
1434
|
+
console.warn(
|
|
1435
|
+
`[defineModelSchema] Unique constraint "${constraint.name}" for model "${modelName}" references unknown field "${missingField}". Skipping.`
|
|
1436
|
+
);
|
|
1437
|
+
continue;
|
|
1438
|
+
}
|
|
1439
|
+
if (resolved.some((item) => item.name === constraint.name)) {
|
|
1440
|
+
console.warn(
|
|
1441
|
+
`[defineModelSchema] Duplicate unique constraint name "${constraint.name}" in model "${modelName}".`
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
resolved.push({
|
|
1445
|
+
name: constraint.name,
|
|
1446
|
+
fields: [...constraint.fields]
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
return resolved;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
// src/models/tomlLoader.ts
|
|
1454
|
+
var VALID_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
1455
|
+
"string",
|
|
1456
|
+
"number",
|
|
1457
|
+
"boolean",
|
|
1458
|
+
"date",
|
|
1459
|
+
"id",
|
|
1460
|
+
"stringset"
|
|
1461
|
+
]);
|
|
1462
|
+
function parseFieldOptions(raw) {
|
|
1463
|
+
if (!raw.type || !VALID_FIELD_TYPES.has(raw.type)) {
|
|
1464
|
+
throw new Error(
|
|
1465
|
+
`Invalid field type "${raw.type}". Must be one of: ${[...VALID_FIELD_TYPES].join(", ")}`
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1468
|
+
const opts = { type: raw.type };
|
|
1469
|
+
if (raw.indexed === true) opts.indexed = true;
|
|
1470
|
+
if (raw.unique === true) opts.unique = true;
|
|
1471
|
+
if (raw.required === true) opts.required = true;
|
|
1472
|
+
if (raw.auto_assign === true) opts.autoAssign = true;
|
|
1473
|
+
if (raw.max_length !== void 0) opts.maxLength = raw.max_length;
|
|
1474
|
+
if (raw.max_count !== void 0) opts.maxCount = raw.max_count;
|
|
1475
|
+
if (raw.default !== void 0) opts.default = raw.default;
|
|
1476
|
+
return opts;
|
|
1477
|
+
}
|
|
1478
|
+
function requireField(raw, field, context) {
|
|
1479
|
+
if (!raw[field]) {
|
|
1480
|
+
throw new Error(`Relationship ${context}: missing required field "${field}"`);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
function parseRelationship(raw) {
|
|
1484
|
+
const type = raw.type;
|
|
1485
|
+
if (type === "refersTo") {
|
|
1486
|
+
requireField(raw, "model", "refersTo");
|
|
1487
|
+
requireField(raw, "related_id_field", "refersTo");
|
|
1488
|
+
return {
|
|
1489
|
+
type: "refersTo",
|
|
1490
|
+
model: raw.model,
|
|
1491
|
+
relatedIdField: raw.related_id_field
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
if (type === "hasMany") {
|
|
1495
|
+
requireField(raw, "model", "hasMany");
|
|
1496
|
+
requireField(raw, "related_id_field", "hasMany");
|
|
1497
|
+
const rel = {
|
|
1498
|
+
type: "hasMany",
|
|
1499
|
+
model: raw.model,
|
|
1500
|
+
relatedIdField: raw.related_id_field
|
|
1501
|
+
};
|
|
1502
|
+
if (raw.order_by_field) rel.orderByField = raw.order_by_field;
|
|
1503
|
+
if (raw.order_direction) rel.orderDirection = raw.order_direction;
|
|
1504
|
+
return rel;
|
|
1505
|
+
}
|
|
1506
|
+
if (type === "hasManyThrough") {
|
|
1507
|
+
requireField(raw, "model", "hasManyThrough");
|
|
1508
|
+
requireField(raw, "join_model", "hasManyThrough");
|
|
1509
|
+
requireField(raw, "join_model_local_field", "hasManyThrough");
|
|
1510
|
+
requireField(raw, "join_model_related_field", "hasManyThrough");
|
|
1511
|
+
const rel = {
|
|
1512
|
+
type: "hasManyThrough",
|
|
1513
|
+
model: raw.model,
|
|
1514
|
+
joinModel: raw.join_model,
|
|
1515
|
+
joinModelLocalField: raw.join_model_local_field,
|
|
1516
|
+
joinModelRelatedField: raw.join_model_related_field
|
|
1517
|
+
};
|
|
1518
|
+
if (raw.join_model_order_by_field)
|
|
1519
|
+
rel.joinModelOrderByField = raw.join_model_order_by_field;
|
|
1520
|
+
if (raw.join_model_order_direction)
|
|
1521
|
+
rel.joinModelOrderDirection = raw.join_model_order_direction;
|
|
1522
|
+
return rel;
|
|
1523
|
+
}
|
|
1524
|
+
throw new Error(`Unknown relationship type: ${type}`);
|
|
1525
|
+
}
|
|
1526
|
+
function loadSchemaFromTomlString(tomlString) {
|
|
1527
|
+
const parsed = parseToml(tomlString);
|
|
1528
|
+
const models = parsed.models;
|
|
1529
|
+
if (!models || typeof models !== "object") {
|
|
1530
|
+
throw new Error("TOML schema must have a [models] section");
|
|
1531
|
+
}
|
|
1532
|
+
const schemas = [];
|
|
1533
|
+
for (const [modelName, modelDef] of Object.entries(models)) {
|
|
1534
|
+
const fields = {};
|
|
1535
|
+
if (modelDef.fields) {
|
|
1536
|
+
for (const [fieldName, fieldDef] of Object.entries(modelDef.fields)) {
|
|
1537
|
+
fields[fieldName] = parseFieldOptions(fieldDef);
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
let relationships;
|
|
1541
|
+
if (modelDef.relationships) {
|
|
1542
|
+
relationships = {};
|
|
1543
|
+
for (const [relName, relDef] of Object.entries(
|
|
1544
|
+
modelDef.relationships
|
|
1545
|
+
)) {
|
|
1546
|
+
relationships[relName] = parseRelationship(relDef);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
let uniqueConstraints;
|
|
1550
|
+
if (modelDef.unique_constraints) {
|
|
1551
|
+
uniqueConstraints = [];
|
|
1552
|
+
for (const raw of modelDef.unique_constraints) {
|
|
1553
|
+
uniqueConstraints.push({
|
|
1554
|
+
name: raw.name,
|
|
1555
|
+
fields: [...raw.fields]
|
|
1556
|
+
});
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
schemas.push(
|
|
1560
|
+
defineModelSchema({
|
|
1561
|
+
name: modelName,
|
|
1562
|
+
fields,
|
|
1563
|
+
options: {
|
|
1564
|
+
uniqueConstraints,
|
|
1565
|
+
relationships
|
|
1566
|
+
}
|
|
1567
|
+
})
|
|
1568
|
+
);
|
|
1569
|
+
}
|
|
1570
|
+
return schemas;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
// src/cloudflare.ts
|
|
1574
|
+
init_metaSync();
|
|
1029
1575
|
export {
|
|
1030
1576
|
DOClientEngine,
|
|
1577
|
+
clearMetaSyncCache,
|
|
1031
1578
|
connectDoDb,
|
|
1579
|
+
discoverModelNames,
|
|
1580
|
+
discoverSchema,
|
|
1032
1581
|
getActiveDOEngine,
|
|
1582
|
+
inferFieldType,
|
|
1033
1583
|
initJsBaoDO,
|
|
1034
|
-
|
|
1584
|
+
loadSchemaFromTomlString,
|
|
1585
|
+
registerFunctionDefault,
|
|
1586
|
+
resetJsBaoDO,
|
|
1587
|
+
schemaToToml,
|
|
1588
|
+
syncInferredMeta,
|
|
1589
|
+
syncModelMeta
|
|
1035
1590
|
};
|