@an5/orm 1.0.1 → 1.0.3
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/README.md +24 -15
- package/dist/push.js +43 -23
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @an5/orm
|
|
2
2
|
|
|
3
3
|
SQL Server ORM. Proxy client. CRUD. Vector search. Middleware. Raw queries. Transactions.
|
|
4
4
|
|
|
@@ -13,7 +13,13 @@ SQL Server ORM. Proxy client. CRUD. Vector search. Middleware. Raw queries. Tran
|
|
|
13
13
|
- **Transactions.** `$transaction`. Rollback support.
|
|
14
14
|
- **Schema Generator.** Parse `.an5` files. Generate TypeScript/Python/.NET code.
|
|
15
15
|
|
|
16
|
-
## Quick Start
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @an5/orm
|
|
22
|
+
```
|
|
17
23
|
|
|
18
24
|
### Configuration
|
|
19
25
|
|
|
@@ -25,17 +31,20 @@ cp .env.example .env
|
|
|
25
31
|
### Development Commands
|
|
26
32
|
|
|
27
33
|
```bash
|
|
28
|
-
# Generate code from schema
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
# Push schema to database
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
# Pull schema from database
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# Seed database
|
|
38
|
-
|
|
34
|
+
# Generate code from schema
|
|
35
|
+
npx an5 generate
|
|
36
|
+
|
|
37
|
+
# Push schema to database
|
|
38
|
+
npx an5 db:push
|
|
39
|
+
|
|
40
|
+
# Pull schema from database
|
|
41
|
+
npx an5 db:pull
|
|
42
|
+
|
|
43
|
+
# Seed database
|
|
44
|
+
npx an5 db:seed
|
|
45
|
+
|
|
46
|
+
# Compare schema with database
|
|
47
|
+
npx an5 db:migrate diff
|
|
39
48
|
|
|
40
49
|
# Run tests
|
|
41
50
|
npm test
|
|
@@ -44,7 +53,7 @@ npm test
|
|
|
44
53
|
## Usage
|
|
45
54
|
|
|
46
55
|
```typescript
|
|
47
|
-
import { An5ORM } from '
|
|
56
|
+
import { An5ORM } from '@an5/orm';
|
|
48
57
|
|
|
49
58
|
const db = new An5ORM();
|
|
50
59
|
|
|
@@ -135,4 +144,4 @@ npm test
|
|
|
135
144
|
|
|
136
145
|
## License
|
|
137
146
|
|
|
138
|
-
MIT
|
|
147
|
+
MIT
|
package/dist/push.js
CHANGED
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
require("dotenv/config");
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const
|
|
9
|
+
const adapters_1 = require("@an5/adapters");
|
|
10
10
|
const rootDir = process.cwd();
|
|
11
11
|
let config = {};
|
|
12
12
|
try {
|
|
@@ -22,7 +22,7 @@ const schemaDir = path_1.default.resolve(rootDir, config.schemaDir || "an5Schema
|
|
|
22
22
|
let _adapter = null;
|
|
23
23
|
async function getDb() {
|
|
24
24
|
if (!_adapter) {
|
|
25
|
-
_adapter = new
|
|
25
|
+
_adapter = new adapters_1.An5Adapter({ connectionString: process.env.DATABASE_URL });
|
|
26
26
|
await _adapter.$connect();
|
|
27
27
|
}
|
|
28
28
|
return _adapter;
|
|
@@ -42,6 +42,25 @@ function parseSqlType(raw) {
|
|
|
42
42
|
const match = raw.match(/^(\w+)/);
|
|
43
43
|
return match ? match[1].toUpperCase() : raw.toUpperCase();
|
|
44
44
|
}
|
|
45
|
+
function parseTableName(raw) {
|
|
46
|
+
const cleaned = raw.replace(/[\[\]"]/g, "");
|
|
47
|
+
const parts = cleaned.split(".").filter(Boolean);
|
|
48
|
+
if (parts.length >= 2) {
|
|
49
|
+
return { schema: parts[parts.length - 2], name: parts[parts.length - 1] };
|
|
50
|
+
}
|
|
51
|
+
return { name: cleaned };
|
|
52
|
+
}
|
|
53
|
+
function tableSqlName(raw) {
|
|
54
|
+
const table = parseTableName(raw);
|
|
55
|
+
return table.schema ? `[${table.schema}].[${table.name}]` : `[${table.name}]`;
|
|
56
|
+
}
|
|
57
|
+
function tableObjectName(raw) {
|
|
58
|
+
const table = parseTableName(raw);
|
|
59
|
+
return table.schema ? `${table.schema}.${table.name}` : table.name;
|
|
60
|
+
}
|
|
61
|
+
function safeIdentifierName(raw) {
|
|
62
|
+
return raw.replace(/[^A-Za-z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
63
|
+
}
|
|
45
64
|
async function push() {
|
|
46
65
|
let schemaText = "";
|
|
47
66
|
if (fs_1.default.existsSync(schemaDir)) {
|
|
@@ -161,11 +180,13 @@ async function push() {
|
|
|
161
180
|
}
|
|
162
181
|
console.log(`🚀 Pushing schema to database...`);
|
|
163
182
|
for (const model of models) {
|
|
164
|
-
|
|
183
|
+
const sqlTableName = tableSqlName(model.tableName);
|
|
184
|
+
const objectName = tableObjectName(model.tableName);
|
|
185
|
+
console.log(`Processing table ${sqlTableName}...`);
|
|
165
186
|
// Check if table exists
|
|
166
|
-
const tableExists = await (await getDb()).$queryRawUnsafe(`SELECT name FROM sys.tables WHERE
|
|
187
|
+
const tableExists = await (await getDb()).$queryRawUnsafe(`SELECT name FROM sys.tables WHERE object_id = OBJECT_ID('${objectName}')`);
|
|
167
188
|
if (tableExists.length === 0) {
|
|
168
|
-
console.log(`Creating table
|
|
189
|
+
console.log(`Creating table ${sqlTableName}...`);
|
|
169
190
|
const colDefs = model.fields.map((f) => {
|
|
170
191
|
let def = `[${f.name}] ${f.sqlType}`;
|
|
171
192
|
if (f.isId)
|
|
@@ -181,32 +202,32 @@ async function push() {
|
|
|
181
202
|
// Add compound uniques as table constraints
|
|
182
203
|
if (model.compoundUniques && model.compoundUniques.length > 0) {
|
|
183
204
|
model.compoundUniques.forEach((fields, idx) => {
|
|
184
|
-
const constraintName = `UQ_${model.tableName}_compound_${idx}`;
|
|
205
|
+
const constraintName = `UQ_${safeIdentifierName(model.tableName)}_compound_${idx}`;
|
|
185
206
|
const fieldsStr = fields.map(f => `[${f}]`).join(", ");
|
|
186
207
|
colDefs.push(`CONSTRAINT [${constraintName}] UNIQUE (${fieldsStr})`);
|
|
187
208
|
});
|
|
188
209
|
}
|
|
189
|
-
const createSql = `CREATE TABLE
|
|
210
|
+
const createSql = `CREATE TABLE ${sqlTableName} (\n ${colDefs.join(",\n ")}\n)`;
|
|
190
211
|
await (await getDb()).$executeRawUnsafe(createSql);
|
|
191
|
-
console.log(`✅ Table
|
|
212
|
+
console.log(`✅ Table ${sqlTableName} created.`);
|
|
192
213
|
// Create indexes
|
|
193
214
|
if (model.indexes && model.indexes.length > 0) {
|
|
194
215
|
for (let idx = 0; idx < model.indexes.length; idx++) {
|
|
195
216
|
const fields = model.indexes[idx];
|
|
196
|
-
const indexName = `IX_${model.tableName}_${fields.join("_")}`;
|
|
217
|
+
const indexName = `IX_${safeIdentifierName(model.tableName)}_${fields.join("_")}`;
|
|
197
218
|
const fieldsStr = fields.map((f) => `[${f}]`).join(", ");
|
|
198
|
-
console.log(`Creating index [${indexName}] on table
|
|
199
|
-
await (await getDb()).$executeRawUnsafe(`CREATE INDEX [${indexName}] ON
|
|
219
|
+
console.log(`Creating index [${indexName}] on table ${sqlTableName}...`);
|
|
220
|
+
await (await getDb()).$executeRawUnsafe(`CREATE INDEX [${indexName}] ON ${sqlTableName} (${fieldsStr})`);
|
|
200
221
|
}
|
|
201
222
|
}
|
|
202
223
|
}
|
|
203
224
|
else {
|
|
204
225
|
// 1. Check for missing columns
|
|
205
226
|
for (const field of model.fields) {
|
|
206
|
-
const colExists = await (await getDb()).$queryRawUnsafe(`SELECT name FROM sys.columns WHERE object_id = OBJECT_ID('${
|
|
227
|
+
const colExists = await (await getDb()).$queryRawUnsafe(`SELECT name FROM sys.columns WHERE object_id = OBJECT_ID('${objectName}') AND name = '${field.name}'`);
|
|
207
228
|
if (colExists.length === 0) {
|
|
208
|
-
console.log(`Adding column [${field.name}] to table
|
|
209
|
-
let alterSql = `ALTER TABLE
|
|
229
|
+
console.log(`Adding column [${field.name}] to table ${sqlTableName}...`);
|
|
230
|
+
let alterSql = `ALTER TABLE ${sqlTableName} ADD [${field.name}] ${field.sqlType}`;
|
|
210
231
|
if (field.defaultValue)
|
|
211
232
|
alterSql += ` ${field.defaultValue}`;
|
|
212
233
|
if (field.isUnique && !field.isId)
|
|
@@ -224,12 +245,12 @@ async function push() {
|
|
|
224
245
|
if (model.compoundUniques && model.compoundUniques.length > 0) {
|
|
225
246
|
for (let idx = 0; idx < model.compoundUniques.length; idx++) {
|
|
226
247
|
const fields = model.compoundUniques[idx];
|
|
227
|
-
const constraintName = `UQ_${model.tableName}_compound_${idx}`;
|
|
228
|
-
const constraintExists = await (await getDb()).$queryRawUnsafe(`SELECT name FROM sys.objects WHERE type = 'UQ' AND parent_object_id = OBJECT_ID('${
|
|
248
|
+
const constraintName = `UQ_${safeIdentifierName(model.tableName)}_compound_${idx}`;
|
|
249
|
+
const constraintExists = await (await getDb()).$queryRawUnsafe(`SELECT name FROM sys.objects WHERE type = 'UQ' AND parent_object_id = OBJECT_ID('${objectName}') AND name = '${constraintName}'`);
|
|
229
250
|
if (constraintExists.length === 0) {
|
|
230
|
-
console.log(`Adding compound unique constraint [${constraintName}] to table
|
|
251
|
+
console.log(`Adding compound unique constraint [${constraintName}] to table ${sqlTableName}...`);
|
|
231
252
|
const fieldsStr = fields.map((f) => `[${f}]`).join(", ");
|
|
232
|
-
await (await getDb()).$executeRawUnsafe(`ALTER TABLE
|
|
253
|
+
await (await getDb()).$executeRawUnsafe(`ALTER TABLE ${sqlTableName} ADD CONSTRAINT [${constraintName}] UNIQUE (${fieldsStr})`);
|
|
233
254
|
}
|
|
234
255
|
}
|
|
235
256
|
}
|
|
@@ -237,12 +258,12 @@ async function push() {
|
|
|
237
258
|
if (model.indexes && model.indexes.length > 0) {
|
|
238
259
|
for (let idx = 0; idx < model.indexes.length; idx++) {
|
|
239
260
|
const fields = model.indexes[idx];
|
|
240
|
-
const indexName = `IX_${model.tableName}_${fields.join("_")}`;
|
|
241
|
-
const indexExists = await (await getDb()).$queryRawUnsafe(`SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('${
|
|
261
|
+
const indexName = `IX_${safeIdentifierName(model.tableName)}_${fields.join("_")}`;
|
|
262
|
+
const indexExists = await (await getDb()).$queryRawUnsafe(`SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('${objectName}') AND name = '${indexName}'`);
|
|
242
263
|
if (indexExists.length === 0) {
|
|
243
|
-
console.log(`Creating index [${indexName}] on table
|
|
264
|
+
console.log(`Creating index [${indexName}] on table ${sqlTableName}...`);
|
|
244
265
|
const fieldsStr = fields.map((f) => `[${f}]`).join(", ");
|
|
245
|
-
await (await getDb()).$executeRawUnsafe(`CREATE INDEX [${indexName}] ON
|
|
266
|
+
await (await getDb()).$executeRawUnsafe(`CREATE INDEX [${indexName}] ON ${sqlTableName} (${fieldsStr})`);
|
|
246
267
|
}
|
|
247
268
|
}
|
|
248
269
|
}
|
|
@@ -255,4 +276,3 @@ push().catch((err) => {
|
|
|
255
276
|
console.error("❌ Push failed:", err);
|
|
256
277
|
process.exit(1);
|
|
257
278
|
});
|
|
258
|
-
//# sourceMappingURL=push.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@an5/orm",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "The lightweight ORM for SQL Server with support for TypeScript, Python, and .NET (C#).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"test:generator": "node test/generator.test.js"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@an5/adapters": "^0.1.
|
|
38
|
+
"@an5/adapters": "^0.1.2",
|
|
39
39
|
"bcryptjs": "^2.4.3",
|
|
40
40
|
"dotenv": "^16.4.5",
|
|
41
41
|
"mssql": "^12.5.5"
|