@stacksjs/database 0.75.369 → 0.75.371

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/erd.d.ts CHANGED
@@ -40,6 +40,8 @@ export declare function toDiagrammableModel(definition: {
40
40
  * because it reads as schema rather than as a typo.
41
41
  */
42
42
  export declare function relationEdges(models: DiagrammableModel[]): DiagramEdge[];
43
+ /** The level `options` asks for, with `columns: false` still meaning `none`. */
44
+ export declare function erdDetailFrom(options: RenderErdOptions): ErdDetail;
43
45
  /**
44
46
  * A Mermaid `erDiagram` for these models.
45
47
  *
@@ -48,6 +50,8 @@ export declare function relationEdges(models: DiagrammableModel[]): DiagramEdge[
48
50
  * the detail of each table.
49
51
  */
50
52
  export declare function renderErd(models: DiagrammableModel[], options?: RenderErdOptions): string;
53
+ /** Mermaid's own default `maxTextSize`, past which it draws an error box. */
54
+ export declare const MERMAID_MAX_TEXT_SIZE: unknown;
51
55
  /** One model, reduced to what a diagram needs. */
52
56
  export declare interface DiagrammableModel {
53
57
  name: string
@@ -72,5 +76,19 @@ export declare interface DiagramEdge {
72
76
  }
73
77
  export declare interface RenderErdOptions {
74
78
  columns?: boolean
79
+ detail?: ErdDetail
75
80
  only?: string[]
76
81
  }
82
+ /**
83
+ * How much of each table the diagram draws.
84
+ *
85
+ * Mermaid stops rendering a diagram whose source passes `maxTextSize`, which
86
+ * is 50,000 characters unless the page says otherwise, and replaces the whole
87
+ * thing with an error box. Columns are the bulk of an ER diagram's text - on a
88
+ * 155-table schema they were 76% of it - so the dial that keeps a diagram
89
+ * renderable is how many of them are drawn, not how many tables are.
90
+ *
91
+ * `keys` keeps the primary and foreign keys, which is what makes an ER diagram
92
+ * worth reading: it is the column a relationship is made of.
93
+ */
94
+ export type ErdDetail = 'full' | 'keys' | 'none';
package/dist/erd.js CHANGED
@@ -1,3 +1,3 @@
1
- import{foreignKeyForModel}from"./vschema";const SAFE_TYPE=/^[a-z][a-z0-9_]*$/;export function columnType(attribute){const rules=attribute?.validation?.rule?.rules,head=Array.isArray(rules)?rules[0]?.name:void 0;if(typeof head==="string"&&SAFE_TYPE.test(head))return head;const fallback=attribute?.default;if(typeof fallback==="boolean")return"boolean";if(typeof fallback==="number")return"number";if(typeof fallback==="string")return"string";return"unknown"}export function relatedModelNames(raw){if(typeof raw==="string")return[raw];if(Array.isArray(raw))return raw.map((entry)=>typeof entry==="string"?entry:entry?.model).filter((entry)=>Boolean(entry));if(raw&&typeof raw==="object")return Object.keys(raw);return[]}export function toDiagrammableModel(definition,table){const primaryKey=definition?.primaryKey||"id",traits=definition?.traits??{},columns=[{name:primaryKey,type:"number",key:"PK"}];if(traits.useUuid)columns.push({name:"uuid",type:"string",key:"UK"});for(const[name,attribute]of Object.entries(definition?.attributes??{})){const unique=Boolean(attribute?.unique);columns.push({name,type:columnType(attribute),...unique?{key:"UK"}:{}})}const belongsTo=relatedModelNames(definition?.belongsTo);for(const parent of belongsTo){const column=foreignKeyForModel(parent);if(!columns.some((existing)=>existing.name===column))columns.push({name:column,type:"number",key:"FK"})}if(traits.useTimestamps){columns.push({name:"created_at",type:"datetime"});columns.push({name:"updated_at",type:"datetime"})}if(traits.useSoftDeletes)columns.push({name:"deleted_at",type:"datetime"});return{name:definition?.name??table,table,primaryKey,columns,belongsTo,hasOne:relatedModelNames(definition?.hasOne),hasMany:relatedModelNames(definition?.hasMany)}}export function relationEdges(models){const tableByModel=new Map(models.map((model)=>[model.name,model.table])),seen=new Set,edges=[],add=(from,to,cardinality,label)=>{const key=[from,to].sort().join("\x00");if(seen.has(key))return;seen.add(key);edges.push({from,to,cardinality,label})},sorted=[...models].sort((a,b)=>a.table.localeCompare(b.table));for(const model of sorted){for(const child of[...model.hasMany].sort()){const table=tableByModel.get(child);if(table)add(model.table,table,"||--o{","has many")}for(const child of[...model.hasOne].sort()){const table=tableByModel.get(child);if(table)add(model.table,table,"||--o|","has one")}}for(const model of sorted)for(const parent of[...model.belongsTo].sort()){const table=tableByModel.get(parent);if(table)add(table,model.table,"||--o{","has many")}return edges}export function renderErd(models,options={}){const sorted=[...options.only&&options.only.length>0?models.filter((model)=>options.only.includes(model.table)||options.only.includes(model.name)):models].sort((a,b)=>a.table.localeCompare(b.table)),lines=["erDiagram"];for(const edge of relationEdges(sorted))lines.push(` ${edge.from} ${edge.cardinality} ${edge.to} : "${edge.label}"`);if(options.columns===!1)return lines.join(`
2
- `);for(const model of sorted){lines.push(` ${model.table} {`);for(const column of model.columns)lines.push(` ${column.type} ${column.name}${column.key?` ${column.key}`:""}`);lines.push(" }")}return lines.join(`
1
+ import{foreignKeyForModel}from"./vschema";const SAFE_TYPE=/^[a-z][a-z0-9_]*$/;export function columnType(attribute){const rules=attribute?.validation?.rule?.rules,head=Array.isArray(rules)?rules[0]?.name:void 0;if(typeof head==="string"&&SAFE_TYPE.test(head))return head;const fallback=attribute?.default;if(typeof fallback==="boolean")return"boolean";if(typeof fallback==="number")return"number";if(typeof fallback==="string")return"string";return"unknown"}export function relatedModelNames(raw){if(typeof raw==="string")return[raw];if(Array.isArray(raw))return raw.map((entry)=>typeof entry==="string"?entry:entry?.model).filter((entry)=>Boolean(entry));if(raw&&typeof raw==="object")return Object.keys(raw);return[]}export function toDiagrammableModel(definition,table){const primaryKey=definition?.primaryKey||"id",traits=definition?.traits??{},columns=[{name:primaryKey,type:"number",key:"PK"}];if(traits.useUuid)columns.push({name:"uuid",type:"string",key:"UK"});for(const[name,attribute]of Object.entries(definition?.attributes??{})){const unique=Boolean(attribute?.unique);columns.push({name,type:columnType(attribute),...unique?{key:"UK"}:{}})}const belongsTo=relatedModelNames(definition?.belongsTo);for(const parent of belongsTo){const column=foreignKeyForModel(parent);if(!columns.some((existing)=>existing.name===column))columns.push({name:column,type:"number",key:"FK"})}if(traits.useTimestamps){columns.push({name:"created_at",type:"datetime"});columns.push({name:"updated_at",type:"datetime"})}if(traits.useSoftDeletes)columns.push({name:"deleted_at",type:"datetime"});return{name:definition?.name??table,table,primaryKey,columns,belongsTo,hasOne:relatedModelNames(definition?.hasOne),hasMany:relatedModelNames(definition?.hasMany)}}export function relationEdges(models){const tableByModel=new Map(models.map((model)=>[model.name,model.table])),seen=new Set,edges=[],add=(from,to,cardinality,label)=>{const key=[from,to].sort().join("\x00");if(seen.has(key))return;seen.add(key);edges.push({from,to,cardinality,label})},sorted=[...models].sort((a,b)=>a.table.localeCompare(b.table));for(const model of sorted){for(const child of[...model.hasMany].sort()){const table=tableByModel.get(child);if(table)add(model.table,table,"||--o{","has many")}for(const child of[...model.hasOne].sort()){const table=tableByModel.get(child);if(table)add(model.table,table,"||--o|","has one")}}for(const model of sorted)for(const parent of[...model.belongsTo].sort()){const table=tableByModel.get(parent);if(table)add(table,model.table,"||--o{","has many")}return edges}export const MERMAID_MAX_TEXT_SIZE=50000;export function erdDetailFrom(options){if(options.detail)return options.detail;return options.columns===!1?"none":"full"}export function renderErd(models,options={}){const sorted=[...options.only&&options.only.length>0?models.filter((model)=>options.only.includes(model.table)||options.only.includes(model.name)):models].sort((a,b)=>a.table.localeCompare(b.table)),lines=["erDiagram"];for(const edge of relationEdges(sorted))lines.push(` ${edge.from} ${edge.cardinality} ${edge.to} : "${edge.label}"`);const detail=erdDetailFrom(options);if(detail==="none")return lines.join(`
2
+ `);for(const model of sorted){const columns=detail==="keys"?model.columns.filter((column)=>column.key):model.columns;lines.push(` ${model.table} {`);for(const column of columns)lines.push(` ${column.type} ${column.name}${column.key?` ${column.key}`:""}`);lines.push(" }")}return lines.join(`
3
3
  `)}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/database",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.369",
5
+ "version": "0.75.371",
6
6
  "description": "The Stacks database integration.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -66,26 +66,26 @@
66
66
  "prepublishOnly": "bun run build"
67
67
  },
68
68
  "dependencies": {
69
- "@stacksjs/config": "0.75.369",
70
- "@stacksjs/env": "0.75.369",
71
- "@stacksjs/error-handling": "0.75.369",
72
- "@stacksjs/faker": "0.75.369",
73
- "@stacksjs/features": "0.75.369",
74
- "@stacksjs/logging": "0.75.369",
75
- "@stacksjs/model-meta": "0.75.369",
76
- "@stacksjs/path": "0.75.369",
77
- "@stacksjs/query-builder": "0.75.369",
78
- "@stacksjs/security": "0.75.369",
79
- "@stacksjs/storage": "0.75.369",
80
- "@stacksjs/strings": "0.75.369",
69
+ "@stacksjs/config": "0.75.371",
70
+ "@stacksjs/env": "0.75.371",
71
+ "@stacksjs/error-handling": "0.75.371",
72
+ "@stacksjs/faker": "0.75.371",
73
+ "@stacksjs/features": "0.75.371",
74
+ "@stacksjs/logging": "0.75.371",
75
+ "@stacksjs/model-meta": "0.75.371",
76
+ "@stacksjs/path": "0.75.371",
77
+ "@stacksjs/query-builder": "0.75.371",
78
+ "@stacksjs/security": "0.75.371",
79
+ "@stacksjs/storage": "0.75.371",
80
+ "@stacksjs/strings": "0.75.371",
81
81
  "@stacksjs/ts-validation": "^0.5.6",
82
82
  "bun-query-builder": "^0.3.28",
83
83
  "dynamodb-tooling": "^0.3.6"
84
84
  },
85
85
  "devDependencies": {
86
- "@stacksjs/cli": "0.75.369",
87
- "@stacksjs/router": "0.75.369",
88
- "@stacksjs/utils": "0.75.369",
86
+ "@stacksjs/cli": "0.75.371",
87
+ "@stacksjs/router": "0.75.371",
88
+ "@stacksjs/utils": "0.75.371",
89
89
  "better-dx": "^0.2.24"
90
90
  }
91
91
  }