@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.
@@ -1,15 +1,24 @@
1
1
  export interface BaseSchema {
2
- id: string;
2
+ id?: string;
3
3
  data?: any;
4
- createdAt: Date;
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: Record<keyof T, string>;
21
+ readonly schema: FlexibleSchema<T>;
13
22
  readonly foreignKeys: ForeignKeyDefinition[];
14
- constructor(name: string, schema: Record<keyof T, string>, foreignKeys?: ForeignKeyDefinition[]);
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<void>;
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<void>;
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
  }
@@ -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
- const sql = `INSERT INTO \`${this.model.name}\` (${keys.join(",")}) VALUES (${keys.map(() => "?").join(",")})`;
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
- const setClause = setKeys.map(k => `${k} = ?`).join(", ");
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;
@@ -1,2 +1,3 @@
1
1
  export * from './getNextId';
2
2
  export * from './syncSchema';
3
+ export * from './types';
@@ -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);
@@ -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
- async function syncSchema() {
6
- const models = (0, core_1.getAllModels)();
7
- const pool = (0, core_1.getPool)();
8
- for (const [name, model] of models.entries()) {
9
- const columns = [];
10
- const foreignKeys = [];
11
- for (const [key, type] of Object.entries(model.schema)) {
12
- columns.push(`\`${key}\` ${mapType(type)}`);
13
- }
14
- for (const fk of model.foreignKeys) {
15
- foreignKeys.push(`FOREIGN KEY (\`${fk.column}\`) REFERENCES ${fk.reference}`);
16
- }
17
- const columnDefs = [...columns, ...foreignKeys].join(",\n ");
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; // fallback for raw SQL types if provided
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
  }
@@ -0,0 +1,3 @@
1
+ export type JSONValue = string | number | boolean | null | JSONValue[] | {
2
+ [key: string]: JSONValue;
3
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shadow-dev/orm",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Lightweight dynamic MySQL ORM designed for ShadowCore and modular apps.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",