@an5/orm 1.0.7 → 1.0.9

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 (46) hide show
  1. package/README.md +97 -83
  2. package/dist/an5Metadata.d.ts +10 -0
  3. package/dist/an5Metadata.js +93 -0
  4. package/dist/an5Orm.d.ts +95 -3
  5. package/dist/an5Orm.js +808 -512
  6. package/dist/config.d.ts +2 -0
  7. package/dist/config.js +24 -0
  8. package/dist/errors.d.ts +14 -0
  9. package/dist/errors.js +16 -0
  10. package/dist/generator/src/code-generator.d.ts +1 -0
  11. package/dist/generator/src/code-generator.js +44 -20
  12. package/dist/generator/src/dotnet-generator.d.ts +2 -0
  13. package/dist/generator/src/dotnet-generator.js +332 -6
  14. package/dist/generator/src/index.js +18 -2
  15. package/dist/generator/src/metadata-generator.d.ts +4 -1
  16. package/dist/generator/src/metadata-generator.js +22 -8
  17. package/dist/generator/src/python-generator.d.ts +10 -0
  18. package/dist/generator/src/python-generator.js +242 -2
  19. package/dist/index.d.ts +6 -2
  20. package/dist/index.js +23 -8
  21. package/dist/logger.d.ts +53 -0
  22. package/dist/logger.js +117 -0
  23. package/dist/metadata.d.ts +24 -0
  24. package/dist/metadata.js +15 -0
  25. package/dist/migration-core.d.ts +87 -0
  26. package/dist/migration-core.js +692 -0
  27. package/dist/sql-utils.d.ts +31 -0
  28. package/dist/sql-utils.js +290 -0
  29. package/generator/src/code-generator.ts +45 -20
  30. package/generator/src/dotnet-generator.ts +344 -6
  31. package/generator/src/golang-generator.ts +1242 -0
  32. package/generator/src/index.ts +8 -1
  33. package/generator/src/metadata-generator.ts +29 -12
  34. package/generator/src/python-generator.ts +314 -4
  35. package/package.json +12 -10
  36. package/dist/cleanup.d.ts +0 -2
  37. package/dist/cleanup.js +0 -120
  38. package/dist/cli.js +0 -64
  39. package/dist/migrate.d.ts +0 -11
  40. package/dist/migrate.js +0 -301
  41. package/dist/pull.d.ts +0 -2
  42. package/dist/pull.js +0 -339
  43. package/dist/push.d.ts +0 -2
  44. package/dist/push.js +0 -281
  45. package/dist/seed.d.ts +0 -2
  46. package/dist/seed.js +0 -401
package/dist/cli.js DELETED
@@ -1,64 +0,0 @@
1
- #!/usr/bin/env node
2
- const path = require('path');
3
- const { spawnSync } = require('child_process');
4
-
5
- const root = path.resolve(__dirname, '..');
6
- const command = process.argv[2];
7
- const args = process.argv.slice(3);
8
-
9
- const commands = {
10
- generate: path.join(__dirname, 'generator', 'src', 'index.js'),
11
- 'db:generate': path.join(__dirname, 'generator', 'src', 'index.js'),
12
- 'db:push': path.join(__dirname, 'push.js'),
13
- 'db:pull': path.join(__dirname, 'pull.js'),
14
- 'db:seed': path.join(__dirname, 'seed.js'),
15
- 'db:cleanup': path.join(__dirname, 'cleanup.js'),
16
- 'db:migrate': path.join(__dirname, 'migrate.js'),
17
- };
18
-
19
- function help() {
20
- console.log(`AN5 ORM CLI
21
-
22
- Usage:
23
- an5 <command>
24
- an5-orm <command>
25
-
26
- Commands:
27
- generate Generate clients from an5Schema
28
- db:generate Alias for generate
29
- db:push Push schema to database
30
- db:pull Pull schema from database
31
- db:seed Seed database
32
- db:cleanup Drop tables not in schema
33
- db:migrate Migration commands: diff, generate, status
34
-
35
- Examples:
36
- npx an5 generate
37
- npx an5 db:migrate diff
38
- `);
39
- }
40
-
41
- if (!command || command === '-h' || command === '--help' || command === 'help') {
42
- help();
43
- process.exit(0);
44
- }
45
-
46
- const script = commands[command];
47
- if (!script) {
48
- console.error(`Unknown command: ${command}`);
49
- help();
50
- process.exit(1);
51
- }
52
-
53
- const result = spawnSync(process.execPath, [script, ...args], {
54
- cwd: process.cwd(),
55
- env: process.env,
56
- stdio: 'inherit',
57
- });
58
-
59
- if (result.error) {
60
- console.error(result.error.message);
61
- process.exit(1);
62
- }
63
-
64
- process.exit(result.status ?? 0);
package/dist/migrate.d.ts DELETED
@@ -1,11 +0,0 @@
1
- /**
2
- * an5Orm Migration Tool
3
- * Compares schema files with database and generates migration SQL.
4
- *
5
- * Usage:
6
- * npx tsx migrate.ts diff # Show differences
7
- * npx tsx migrate.ts generate # Generate migration file
8
- * npx tsx migrate.ts status # Show migration status
9
- */
10
- import 'dotenv/config';
11
- //# sourceMappingURL=migrate.d.ts.map
package/dist/migrate.js DELETED
@@ -1,301 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- /**
7
- * an5Orm Migration Tool
8
- * Compares schema files with database and generates migration SQL.
9
- *
10
- * Usage:
11
- * npx tsx migrate.ts diff # Show differences
12
- * npx tsx migrate.ts generate # Generate migration file
13
- * npx tsx migrate.ts status # Show migration status
14
- */
15
- require("dotenv/config");
16
- const fs_1 = __importDefault(require("fs"));
17
- const path_1 = __importDefault(require("path"));
18
- const an5_adapters_1 = require("@an5/adapters");
19
- const rootDir = process.cwd();
20
- let config = {};
21
- try {
22
- let configPath = path_1.default.join(rootDir, 'an5Orm.config.js');
23
- if (!fs_1.default.existsSync(configPath)) {
24
- configPath = path_1.default.join(rootDir, 'an5Orm.config.cjs');
25
- }
26
- if (fs_1.default.existsSync(configPath)) {
27
- config = require(configPath);
28
- }
29
- }
30
- catch { /* ignore */ }
31
- const schemaDir = path_1.default.resolve(rootDir, config.schemaDir || 'an5Schema');
32
- const migrationsDir = path_1.default.resolve(rootDir, 'migrations');
33
- let _adapter = null;
34
- async function getDb() {
35
- if (!_adapter) {
36
- _adapter = new an5_adapters_1.An5Adapter({ connectionString: process.env.DATABASE_URL });
37
- await _adapter.$connect();
38
- }
39
- return _adapter;
40
- }
41
- // ─── Supported SQL Server Types ──────────────────────────────────────────────
42
- const AN5_TYPES = new Set([
43
- 'NVARCHAR', 'VARCHAR', 'CHAR', 'NCHAR', 'TEXT', 'NTEXT', 'XML',
44
- 'INT', 'SMALLINT', 'TINYINT', 'BIGINT', 'FLOAT', 'REAL', 'DECIMAL', 'NUMERIC',
45
- 'MONEY', 'SMALLMONEY', 'BIT',
46
- 'DATETIME', 'DATETIME2', 'SMALLDATETIME', 'DATE', 'TIME', 'DATETIMEOFFSET',
47
- 'VARBINARY', 'BINARY', 'IMAGE',
48
- 'UNIQUEIDENTIFIER', 'SQL_VARIANT', 'ROWVERSION',
49
- 'HIERARCHYID', 'GEOGRAPHY', 'GEOMETRY', 'VECTOR',
50
- ]);
51
- function parseSqlType(raw) {
52
- const match = raw.match(/^(\w+)/);
53
- return match ? match[1].toUpperCase() : raw.toUpperCase();
54
- }
55
- function parseSchema() {
56
- const models = [];
57
- if (!fs_1.default.existsSync(schemaDir))
58
- return models;
59
- const files = fs_1.default.readdirSync(schemaDir).filter(f => f.endsWith('.an5'));
60
- let text = '';
61
- for (const file of files) {
62
- text += fs_1.default.readFileSync(path_1.default.join(schemaDir, file), 'utf8') + '\n';
63
- }
64
- const lines = text.split('\n');
65
- let current = null;
66
- for (let line of lines) {
67
- line = line.trim();
68
- if (!line || line.startsWith('//'))
69
- continue;
70
- const modelMatch = line.match(/^model\s+(\w+)\s*\{/);
71
- if (modelMatch) {
72
- current = {
73
- name: modelMatch[1],
74
- tableName: modelMatch[1].toLowerCase() + 's',
75
- fields: [],
76
- compoundUniques: [],
77
- indexes: [],
78
- };
79
- models.push(current);
80
- continue;
81
- }
82
- if (line === '}') {
83
- current = null;
84
- continue;
85
- }
86
- if (!current)
87
- continue;
88
- if (line.startsWith('@@map')) {
89
- const m = line.match(/@@map\("(.+)"\)/);
90
- if (m)
91
- current.tableName = m[1];
92
- continue;
93
- }
94
- if (line.startsWith('@@unique')) {
95
- const m = line.match(/@@unique\(\[([\w,\s]+)\]\)/);
96
- if (m)
97
- current.compoundUniques.push(m[1].split(',').map(f => f.trim()));
98
- continue;
99
- }
100
- if (line.startsWith('@@index')) {
101
- const m = line.match(/@@index\(\[([\w,\s]+)\]\)/);
102
- if (m)
103
- current.indexes.push(m[1].split(',').map(f => f.trim()));
104
- continue;
105
- }
106
- if (line.startsWith('@@'))
107
- continue;
108
- const parts = line.split(/\s+/);
109
- const fieldName = parts[0];
110
- const fieldType = parts[1];
111
- if (!fieldName || !fieldType)
112
- continue;
113
- // Parse SQL Server type directly
114
- const cleanType = fieldType.replace('[]', '').replace('?', '');
115
- const sqlBase = parseSqlType(cleanType);
116
- // Skip if not a known SQL Server type (might be a relation)
117
- if (!AN5_TYPES.has(sqlBase))
118
- continue;
119
- current.fields.push({
120
- name: fieldName,
121
- sqlType: cleanType.toUpperCase(),
122
- isOptional: fieldType.endsWith('?'),
123
- isId: line.includes('@id'),
124
- isUnique: line.includes('@unique'),
125
- defaultValue: line.match(/@default\((.*)\)/)?.[1],
126
- });
127
- }
128
- return models;
129
- }
130
- async function introspectTable(tableName) {
131
- return (await getDb()).$queryRawUnsafe(`
132
- SELECT
133
- c.name AS columnName,
134
- ty.name AS dataType,
135
- c.is_nullable AS isNullable,
136
- pk.is_primary_key AS isPrimaryKey,
137
- c.is_identity AS isIdentity,
138
- d.definition AS defaultValue
139
- FROM sys.columns c
140
- JOIN sys.types ty ON c.user_type_id = ty.user_type_id
141
- LEFT JOIN (
142
- SELECT ic.object_id, ic.column_id, i.is_primary_key
143
- FROM sys.index_columns ic
144
- JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
145
- WHERE i.is_primary_key = 1
146
- ) pk ON c.object_id = pk.object_id AND c.column_id = pk.column_id
147
- LEFT JOIN sys.default_constraints d ON c.default_object_id = d.object_id
148
- WHERE c.object_id = OBJECT_ID(@p_0)
149
- ORDER BY c.column_id
150
- `, tableName);
151
- }
152
- async function getExistingTables() {
153
- const rows = await (await getDb()).$queryRawUnsafe(`
154
- SELECT name FROM sys.tables WHERE is_ms_shipped = 0 ORDER BY name
155
- `);
156
- return rows.map(r => r.name);
157
- }
158
- function generateDiff(schemaModels, dbTables) {
159
- const ops = [];
160
- const schemaTableNames = new Set(schemaModels.map(m => m.tableName));
161
- // New tables
162
- for (const model of schemaModels) {
163
- if (!dbTables.includes(model.tableName)) {
164
- const colDefs = model.fields.map(f => {
165
- let def = `[${f.name}] ${f.sqlType}`;
166
- if (f.isId)
167
- def += ' PRIMARY KEY';
168
- if (f.defaultValue)
169
- def += ` ${mapDefault(f.defaultValue)}`;
170
- if (!f.isOptional && !f.defaultValue && !f.isId)
171
- def += ' NOT NULL';
172
- if (f.isUnique && !f.isId)
173
- def += ' UNIQUE';
174
- return def;
175
- });
176
- const sql = `CREATE TABLE [${model.tableName}] (\n ${colDefs.join(',\n ')}\n)`;
177
- ops.push({ type: 'CREATE_TABLE', table: model.tableName, sql });
178
- }
179
- }
180
- // Dropped tables
181
- for (const tableName of dbTables) {
182
- if (!schemaTableNames.has(tableName)) {
183
- ops.push({
184
- type: 'DROP_COLUMN',
185
- table: tableName,
186
- details: `Table not in schema - consider dropping`,
187
- sql: `-- DROP TABLE [${tableName}]`,
188
- });
189
- }
190
- }
191
- return ops;
192
- }
193
- function mapDefault(val) {
194
- if (val === 'uuid()')
195
- return 'DEFAULT NEWID()';
196
- if (val === 'cuid()')
197
- return 'DEFAULT NEWID()';
198
- if (val === 'now()')
199
- return 'DEFAULT CURRENT_TIMESTAMP';
200
- if (val === 'autoincrement()')
201
- return 'IDENTITY(1,1)';
202
- if (val === 'true')
203
- return 'DEFAULT 1';
204
- if (val === 'false')
205
- return 'DEFAULT 0';
206
- if (/^".*"$/.test(val))
207
- return `DEFAULT '${val.slice(1, -1)}'`;
208
- return `DEFAULT ${val}`;
209
- }
210
- // ─── Commands ────────────────────────────────────────────────────────────────
211
- async function cmdDiff() {
212
- console.log('\n🔍 Comparing schema with database...\n');
213
- const schemaModels = parseSchema();
214
- const dbTables = await getExistingTables();
215
- console.log(`Schema: ${schemaModels.length} models`);
216
- console.log(`Database: ${dbTables.length} tables\n`);
217
- const ops = generateDiff(schemaModels, dbTables);
218
- if (ops.length === 0) {
219
- console.log('✅ Schema is in sync with database.');
220
- return;
221
- }
222
- console.log(`Found ${ops.length} difference(s):\n`);
223
- for (const op of ops) {
224
- console.log(` ${op.type}: ${op.table}`);
225
- if (op.details)
226
- console.log(` ${op.details}`);
227
- if (op.sql)
228
- console.log(` SQL: ${op.sql}`);
229
- }
230
- }
231
- async function cmdGenerate() {
232
- console.log('\n📝 Generating migration file...\n');
233
- const schemaModels = parseSchema();
234
- const dbTables = await getExistingTables();
235
- const ops = generateDiff(schemaModels, dbTables);
236
- if (ops.length === 0) {
237
- console.log('No migrations needed.');
238
- return;
239
- }
240
- if (!fs_1.default.existsSync(migrationsDir)) {
241
- fs_1.default.mkdirSync(migrationsDir, { recursive: true });
242
- }
243
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
244
- const filename = `${timestamp}_migration.sql`;
245
- const filepath = path_1.default.join(migrationsDir, filename);
246
- const lines = [`-- Migration: ${timestamp}`, `-- Generated by an5Orm migrate`, ''];
247
- for (const op of ops) {
248
- lines.push(`-- ${op.type}: ${op.table}`);
249
- if (op.sql)
250
- lines.push(op.sql);
251
- lines.push('');
252
- }
253
- fs_1.default.writeFileSync(filepath, lines.join('\n'));
254
- console.log(`✅ Migration written to: ${filepath}`);
255
- }
256
- async function cmdStatus() {
257
- console.log('\n📊 Migration Status\n');
258
- const schemaModels = parseSchema();
259
- const dbTables = await getExistingTables();
260
- console.log('Schema Models:');
261
- for (const model of schemaModels) {
262
- const exists = dbTables.includes(model.tableName);
263
- const icon = exists ? '✅' : '⚠️';
264
- console.log(` ${icon} ${model.name} → ${model.tableName} (${model.fields.length} fields)`);
265
- }
266
- console.log('\nDatabase Tables:');
267
- for (const table of dbTables) {
268
- const inSchema = schemaModels.some(m => m.tableName === table);
269
- const icon = inSchema ? '✅' : '⚠️';
270
- console.log(` ${icon} ${table}`);
271
- }
272
- if (!fs_1.default.existsSync(migrationsDir)) {
273
- fs_1.default.mkdirSync(migrationsDir, { recursive: true });
274
- }
275
- const migrations = fs_1.default.readdirSync(migrationsDir).filter(f => f.endsWith('.sql'));
276
- console.log(`\nMigration files: ${migrations.length}`);
277
- }
278
- // ─── Main ────────────────────────────────────────────────────────────────────
279
- async function main() {
280
- const command = process.argv[2] || 'diff';
281
- switch (command) {
282
- case 'diff':
283
- await cmdDiff();
284
- break;
285
- case 'generate':
286
- await cmdGenerate();
287
- break;
288
- case 'status':
289
- await cmdStatus();
290
- break;
291
- default:
292
- console.log('Usage: npx tsx migrate.ts [diff|generate|status]');
293
- process.exit(1);
294
- }
295
- process.exit(0);
296
- }
297
- main().catch((err) => {
298
- console.error('❌ Migration failed:', err);
299
- process.exit(1);
300
- });
301
- //# sourceMappingURL=migrate.js.map
package/dist/pull.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import "dotenv/config";
2
- //# sourceMappingURL=pull.d.ts.map