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.
@@ -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
- var KNOWN_FUNCTION_DEFAULTS;
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
- return engine.saveModel(resolveModelName(model), data.id, data, stringSets, { ifNotExists, condition });
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
- return engine.saveModel(modelName, data.id, data, stringSets, { ifNotExists, condition });
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
- return engine.saveModel(resolveModelName(model), data.id, data, stringSets, { ifNotExists, condition });
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
- resetJsBaoDO
1584
+ loadSchemaFromTomlString,
1585
+ registerFunctionDefault,
1586
+ resetJsBaoDO,
1587
+ schemaToToml,
1588
+ syncInferredMeta,
1589
+ syncModelMeta
1035
1590
  };