allez-orm 1.0.12 → 1.0.13

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tools/allez-orm.mjs +54 -25
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "allez-orm",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "AllezORM: lightweight browser SQLite ORM (sql.js) + schema generator CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,9 +15,9 @@
15
15
  * - --print-json-schema: output the JSON Schema used for validation
16
16
  *
17
17
  * Usage:
18
- * node tools/allez-orm.mjs create table <name> [fields...] [--dir=schemas_cli] [--stamps] [-f|--force] [--onDelete=cascade|restrict|setnull|noaction]
19
- * node tools/allez-orm.mjs from-json <config.json> [--dir=schemas_cli] [-f|--force]
20
- * node tools/allez-orm.mjs --print-json-schema
18
+ * allez-orm create table <name> [fields...] [--dir=schemas_cli] [--stamps] [-f|--force] [--onDelete=cascade|restrict|setnull|noaction]
19
+ * allez-orm from-json <config.json> [--dir=schemas_cli] [-f|--force]
20
+ * allez-orm --print-json-schema
21
21
  */
22
22
 
23
23
  import fs from "node:fs";
@@ -130,7 +130,7 @@ const CONFIG_JSON_SCHEMA = JSON.stringify({
130
130
  required: ["name"],
131
131
  properties: {
132
132
  name: { type: "string" },
133
- type: { type: "string" }, // TEXT (default), INTEGER, etc
133
+ type: { type: "string" },
134
134
  unique: { type: "boolean" },
135
135
  notnull: { type: "boolean" },
136
136
  fk: {
@@ -351,7 +351,12 @@ function parseFieldToken(tok) {
351
351
 
352
352
  function camel(s){return s.replace(/[-_](.)/g,(_,c)=>c.toUpperCase());}
353
353
 
354
- // ---------------- from-json implementation ----------------
354
+ // ---------------- from-json implementation (resilient) ----------------
355
+
356
+ function pick(obj, ...keys) {
357
+ for (const k of keys) { if (obj && obj[k] !== undefined) return obj[k]; }
358
+ return undefined;
359
+ }
355
360
 
356
361
  async function runFromJson(cliOpts) {
357
362
  const file = path.resolve(cliOpts.jsonFile);
@@ -361,38 +366,62 @@ async function runFromJson(cliOpts) {
361
366
  let cfg;
362
367
  try { cfg = JSON.parse(raw); } catch (e) { die(`Invalid JSON: ${e.message}`); }
363
368
 
364
- // light validation against our schema
365
- // (kept minimal to avoid bundling a validator)
366
- if (!cfg || !Array.isArray(cfg.tables)) die(`Config must have a "tables" array.`);
369
+ // allow OutDir/DefaultOnDelete/Tables
370
+ const outDir = cliOpts.dir || pick(cfg, "outDir", "OutDir") || "schemas_cli";
371
+ const defaultOnDelete = pick(cfg, "defaultOnDelete", "DefaultOnDelete") ?? null;
367
372
 
368
- const outDir = cliOpts.dir || cfg.outDir || "schemas_cli";
369
- const defaultOnDelete = cfg.defaultOnDelete ?? null;
373
+ const tables = pick(cfg, "tables", "Tables");
374
+ if (!Array.isArray(tables)) {
375
+ die(`Config must have an array at "tables" (or "Tables").`);
376
+ }
370
377
 
371
378
  fs.mkdirSync(outDir, { recursive: true });
372
379
 
373
- for (const t of cfg.tables) {
374
- if (!t || !t.name || !Array.isArray(t.fields)) {
375
- die(`Each table requires { name, fields[] }`);
380
+ for (let ti = 0; ti < tables.length; ti++) {
381
+ const tRaw = tables[ti] || {};
382
+ const tName = pick(tRaw, "name", "Name");
383
+ if (!tName || typeof tName !== "string") {
384
+ die(`Table at index ${ti} is missing "name".`);
385
+ }
386
+ const tStamps = !!pick(tRaw, "stamps", "Stamps");
387
+
388
+ // accept fields/Fields OR columns/Columns
389
+ let fieldsList = pick(tRaw, "fields", "Fields", "columns", "Columns");
390
+ if (!Array.isArray(fieldsList)) {
391
+ die(`Table "${tName}" must have "fields" (or "Fields"/"columns"/"Columns") array.`);
376
392
  }
377
- // convert config fields -> tokens for existing generator
393
+
378
394
  const tokens = [];
379
- for (const f of t.fields) {
380
- let token = f.name;
381
- const type = (f.type || "TEXT").toLowerCase();
382
-
383
- token += `:${type}`;
384
- if (f.notnull) token += `!`;
385
- if (f.unique) token += `+`;
386
- if (f.fk && f.fk.table) {
387
- token += `->${f.fk.table}`;
395
+ for (let fi = 0; fi < fieldsList.length; fi++) {
396
+ const f = fieldsList[fi] || {};
397
+ const name = pick(f, "name", "Name");
398
+ if (!name || typeof name !== "string") {
399
+ die(`Table "${tName}" field #${fi} is missing "name".`);
388
400
  }
401
+ const typeRaw = pick(f, "type", "Type");
402
+ const type = (typeRaw ? String(typeRaw) : "TEXT").toLowerCase();
403
+
404
+ const unique = !!pick(f, "unique", "Unique");
405
+ // support notnull, notNull, NotNull
406
+ const notnull = !!pick(f, "notnull", "notNull", "NotNull");
407
+
408
+ // FK variations: fk/FK with table/Table, column/Column
409
+ const fkRaw = pick(f, "fk", "FK");
410
+ const fkTable = fkRaw ? pick(fkRaw, "table", "Table") : undefined;
411
+ const fkCol = fkRaw ? (pick(fkRaw, "column", "Column") || "id") : undefined;
412
+
413
+ let token = name + `:${type}`;
414
+ if (notnull) token += `!`;
415
+ if (unique) token += `+`;
416
+ if (fkTable) token += `->` + fkTable;
417
+
389
418
  tokens.push(token);
390
419
  }
391
420
 
392
421
  await generateOne({
393
422
  outDir,
394
- name: t.name,
395
- stamps: !!t.stamps,
423
+ name: tName,
424
+ stamps: tStamps,
396
425
  onDelete: defaultOnDelete || null,
397
426
  force: cliOpts.force,
398
427
  fieldTokens: tokens