@shadow-dev/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/dist/core/Model.d.ts +13 -4
- package/dist/core/Repository.d.ts +3 -2
- package/dist/core/Repository.js +43 -3
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/syncSchema.js +37 -18
- package/dist/utils/types.d.ts +3 -0
- package/dist/utils/types.js +2 -0
- package/package.json +1 -1
package/dist/core/Model.d.ts
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
export interface BaseSchema {
|
|
2
|
-
id
|
|
2
|
+
id?: string;
|
|
3
3
|
data?: any;
|
|
4
|
-
createdAt
|
|
4
|
+
createdAt?: Date;
|
|
5
5
|
}
|
|
6
6
|
export interface ForeignKeyDefinition {
|
|
7
7
|
column: string;
|
|
8
8
|
reference: string;
|
|
9
9
|
}
|
|
10
|
+
export type SimpleFieldType = "string" | "int" | "float" | "boolean" | "json" | "datetime";
|
|
11
|
+
export interface FieldOptions {
|
|
12
|
+
type: SimpleFieldType;
|
|
13
|
+
pk?: boolean;
|
|
14
|
+
required?: boolean;
|
|
15
|
+
default?: any;
|
|
16
|
+
}
|
|
17
|
+
export type SchemaValue = SimpleFieldType | FieldOptions;
|
|
18
|
+
export type FlexibleSchema<T> = Record<keyof T, SchemaValue>;
|
|
10
19
|
export declare class Model<T extends Partial<BaseSchema> = BaseSchema> {
|
|
11
20
|
readonly name: string;
|
|
12
|
-
readonly schema:
|
|
21
|
+
readonly schema: FlexibleSchema<T>;
|
|
13
22
|
readonly foreignKeys: ForeignKeyDefinition[];
|
|
14
|
-
constructor(name: string, schema:
|
|
23
|
+
constructor(name: string, schema: FlexibleSchema<T>, foreignKeys?: ForeignKeyDefinition[]);
|
|
15
24
|
}
|
|
@@ -2,13 +2,14 @@ import { Model } from "./Model";
|
|
|
2
2
|
export declare class Repository<T extends object> {
|
|
3
3
|
readonly model: Model<T>;
|
|
4
4
|
constructor(model: Model<T>);
|
|
5
|
-
create(data: T): Promise<
|
|
5
|
+
create(data: T): Promise<T>;
|
|
6
6
|
find(where?: Partial<T>): Promise<T[]>;
|
|
7
7
|
findOne(where: Partial<T>): Promise<T | null>;
|
|
8
|
-
update(where: Partial<T>, data: Partial<T>): Promise<
|
|
8
|
+
update(where: Partial<T>, data: Partial<T>): Promise<T | null>;
|
|
9
9
|
delete(where: Partial<T>): Promise<void>;
|
|
10
10
|
count(where?: Partial<T>): Promise<number>;
|
|
11
11
|
exists(where: Partial<T>): Promise<boolean>;
|
|
12
12
|
private normalizeValue;
|
|
13
13
|
private buildWhereClause;
|
|
14
|
+
private getPrimaryKeyField;
|
|
14
15
|
}
|
package/dist/core/Repository.js
CHANGED
|
@@ -6,12 +6,38 @@ const Database_1 = require("./Database");
|
|
|
6
6
|
class Repository {
|
|
7
7
|
constructor(model) {
|
|
8
8
|
this.model = model;
|
|
9
|
+
// Validate PK at construction
|
|
10
|
+
const pk = this.getPrimaryKeyField();
|
|
11
|
+
if (!pk) {
|
|
12
|
+
throw new Error(`Model "${model.name}" has no primary key defined (pk: true)`);
|
|
13
|
+
}
|
|
9
14
|
}
|
|
10
15
|
async create(data) {
|
|
11
16
|
const keys = Object.keys(data);
|
|
12
|
-
|
|
17
|
+
if (keys.length === 0)
|
|
18
|
+
throw new Error("create(): empty data");
|
|
19
|
+
const sql = `INSERT INTO \`${this.model.name}\` (${keys.map(k => `\`${k}\``).join(",")})
|
|
20
|
+
VALUES (${keys.map(() => "?").join(",")})`;
|
|
13
21
|
const values = keys.map((key) => this.normalizeValue(data[key]));
|
|
14
|
-
await (0, Database_1.getPool)().execute(sql, values);
|
|
22
|
+
const [res] = await (0, Database_1.getPool)().execute(sql, values);
|
|
23
|
+
const pk = this.getPrimaryKeyField();
|
|
24
|
+
// If PK exists in data, refetch using it
|
|
25
|
+
if (pk && data[pk] != null) {
|
|
26
|
+
const row = await this.findOne({ [pk]: data[pk] });
|
|
27
|
+
if (row)
|
|
28
|
+
return row;
|
|
29
|
+
}
|
|
30
|
+
// If PK is auto-increment and insertId is present
|
|
31
|
+
if (pk && res.insertId && res.insertId !== 0) {
|
|
32
|
+
const row = await this.findOne({ [pk]: res.insertId });
|
|
33
|
+
if (row)
|
|
34
|
+
return row;
|
|
35
|
+
}
|
|
36
|
+
// Fallback — return data + insertId if available
|
|
37
|
+
if (res.insertId && res.insertId !== 0) {
|
|
38
|
+
return { ...data, id: res.insertId };
|
|
39
|
+
}
|
|
40
|
+
return data;
|
|
15
41
|
}
|
|
16
42
|
async find(where = {}) {
|
|
17
43
|
const { sql, params } = this.buildWhereClause(where);
|
|
@@ -27,12 +53,18 @@ class Repository {
|
|
|
27
53
|
return results.length > 0 ? results[0] : null;
|
|
28
54
|
}
|
|
29
55
|
async update(where, data) {
|
|
56
|
+
if (!where || Object.keys(where).length === 0) {
|
|
57
|
+
throw new Error("update(): missing WHERE");
|
|
58
|
+
}
|
|
30
59
|
const setKeys = Object.keys(data);
|
|
31
|
-
|
|
60
|
+
if (setKeys.length === 0)
|
|
61
|
+
return this.findOne(where);
|
|
62
|
+
const setClause = setKeys.map(k => `\`${k}\` = ?`).join(", ");
|
|
32
63
|
const setValues = setKeys.map(k => this.normalizeValue(data[k]));
|
|
33
64
|
const { sql: whereClause, params: whereValues } = this.buildWhereClause(where);
|
|
34
65
|
const query = `UPDATE \`${this.model.name}\` SET ${setClause} ${whereClause}`;
|
|
35
66
|
await (0, Database_1.getPool)().execute(query, [...setValues, ...whereValues.map(this.normalizeValue)]);
|
|
67
|
+
return this.findOne(where);
|
|
36
68
|
}
|
|
37
69
|
async delete(where) {
|
|
38
70
|
const { sql, params } = this.buildWhereClause(where);
|
|
@@ -69,5 +101,13 @@ class Repository {
|
|
|
69
101
|
params: values,
|
|
70
102
|
};
|
|
71
103
|
}
|
|
104
|
+
getPrimaryKeyField() {
|
|
105
|
+
for (const key of Object.keys(this.model.schema)) {
|
|
106
|
+
if (this.model.schema[key]?.pk) {
|
|
107
|
+
return key;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
72
112
|
}
|
|
73
113
|
exports.Repository = Repository;
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./getNextId"), exports);
|
|
18
18
|
__exportStar(require("./syncSchema"), exports);
|
|
19
|
+
__exportStar(require("./types"), exports);
|
package/dist/utils/syncSchema.js
CHANGED
|
@@ -2,23 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.syncSchema = syncSchema;
|
|
4
4
|
const core_1 = require("../core");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const sql = `CREATE TABLE IF NOT EXISTS \`${name}\` (\n ${columnDefs}\n);`;
|
|
19
|
-
await pool.execute(sql);
|
|
20
|
-
}
|
|
21
|
-
console.log("✅ Schema synchronized.");
|
|
5
|
+
function normalizeField(value) {
|
|
6
|
+
if (typeof value === "string")
|
|
7
|
+
return { type: value };
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
function formatDefault(value) {
|
|
11
|
+
if (typeof value === "string")
|
|
12
|
+
return `'${value}'`;
|
|
13
|
+
if (typeof value === "boolean")
|
|
14
|
+
return value ? "TRUE" : "FALSE";
|
|
15
|
+
if (value === null || value === undefined)
|
|
16
|
+
return "NULL";
|
|
17
|
+
return value.toString();
|
|
22
18
|
}
|
|
23
19
|
function mapType(type) {
|
|
24
20
|
switch (type.toLowerCase()) {
|
|
@@ -26,7 +22,30 @@ function mapType(type) {
|
|
|
26
22
|
case "json": return "JSON";
|
|
27
23
|
case "datetime": return "DATETIME";
|
|
28
24
|
case "number": return "INT";
|
|
25
|
+
case "float": return "FLOAT";
|
|
29
26
|
case "boolean": return "BOOLEAN";
|
|
30
|
-
default: return type;
|
|
27
|
+
default: return type;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function syncSchema() {
|
|
31
|
+
const models = (0, core_1.getAllModels)();
|
|
32
|
+
const pool = (0, core_1.getPool)();
|
|
33
|
+
for (const [name, model] of models.entries()) {
|
|
34
|
+
const columns = [];
|
|
35
|
+
for (const [key, value] of Object.entries(model.schema)) {
|
|
36
|
+
const { type, pk, default: def, required } = normalizeField(value);
|
|
37
|
+
let col = `\`${key}\` ${mapType(type)}`;
|
|
38
|
+
if (required || pk)
|
|
39
|
+
col += " NOT NULL";
|
|
40
|
+
if (pk)
|
|
41
|
+
col += " PRIMARY KEY";
|
|
42
|
+
if (def !== undefined)
|
|
43
|
+
col += ` DEFAULT ${formatDefault(def)}`;
|
|
44
|
+
columns.push(col);
|
|
45
|
+
}
|
|
46
|
+
const fks = model.foreignKeys.map(fk => `FOREIGN KEY (\`${fk.column}\`) REFERENCES ${fk.reference}`);
|
|
47
|
+
const sql = `CREATE TABLE IF NOT EXISTS \`${name}\` (\n ${[...columns, ...fks].join(',\n ')}\n);`;
|
|
48
|
+
await pool.execute(sql);
|
|
31
49
|
}
|
|
50
|
+
console.log("✅ Schema synchronized.");
|
|
32
51
|
}
|