@promakeai/orm 1.0.0

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 ADDED
@@ -0,0 +1,154 @@
1
+ # @promakeai/orm
2
+
3
+ Core ORM package with schema DSL, query builder, and multi-language support.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @promakeai/orm
9
+ ```
10
+
11
+ ## Schema Definition
12
+
13
+ ```typescript
14
+ import { defineSchema, f } from '@promakeai/orm';
15
+
16
+ const schema = defineSchema({
17
+ name: 'myapp',
18
+ languages: ['en', 'tr'],
19
+ defaultLanguage: 'en',
20
+ tables: {
21
+ users: {
22
+ id: f.id(),
23
+ email: f.string().required().unique(),
24
+ name: f.string().required(),
25
+ role: f.string().default('user').enum(['user', 'admin']),
26
+ createdAt: f.timestamp().default('now'),
27
+ },
28
+ products: {
29
+ id: f.id(),
30
+ sku: f.string().required().unique(),
31
+ price: f.decimal().required(),
32
+ stock: f.int().default(0),
33
+ name: f.string().translatable(), // Multi-language
34
+ description: f.text().translatable(), // Multi-language
35
+ categoryId: f.int().ref('categories'), // Reference
36
+ },
37
+ categories: {
38
+ id: f.id(),
39
+ slug: f.string().required().unique(),
40
+ name: f.string().translatable(),
41
+ },
42
+ },
43
+ });
44
+ ```
45
+
46
+ ## Field Types
47
+
48
+ | Type | Description |
49
+ |------|-------------|
50
+ | `f.id()` | Auto-increment primary key |
51
+ | `f.string()` | Short text |
52
+ | `f.text()` | Long text |
53
+ | `f.int()` | Integer |
54
+ | `f.decimal()` | Decimal number |
55
+ | `f.bool()` | Boolean |
56
+ | `f.timestamp()` | ISO datetime |
57
+ | `f.json()` | JSON data |
58
+
59
+ ## Field Modifiers
60
+
61
+ ```typescript
62
+ f.string()
63
+ .required() // NOT NULL
64
+ .unique() // UNIQUE constraint
65
+ .default('value') // Default value
66
+ .enum(['a', 'b', 'c']) // Allowed values
67
+ .min(1).max(100) // Value bounds
68
+ .translatable() // Multi-language field
69
+ .ref('table') // Reference to another table
70
+ .ref({ table: 'users', field: 'id', onDelete: 'CASCADE' })
71
+ ```
72
+
73
+ ## Query Builder (MongoDB-style)
74
+
75
+ ```typescript
76
+ import { buildWhere } from '@promakeai/orm';
77
+
78
+ // Simple equality
79
+ buildWhere({ status: 'active' });
80
+ // WHERE status = 'active'
81
+
82
+ // Comparison operators
83
+ buildWhere({ price: { $gt: 100 } }); // > 100
84
+ buildWhere({ price: { $gte: 100 } }); // >= 100
85
+ buildWhere({ price: { $lt: 100 } }); // < 100
86
+ buildWhere({ price: { $lte: 100 } }); // <= 100
87
+ buildWhere({ status: { $ne: 'deleted' } }); // != 'deleted'
88
+
89
+ // Array operators
90
+ buildWhere({ id: { $in: [1, 2, 3] } }); // IN (1, 2, 3)
91
+ buildWhere({ id: { $nin: [1, 2, 3] } }); // NOT IN (1, 2, 3)
92
+
93
+ // String matching
94
+ buildWhere({ name: { $like: '%john%' } }); // LIKE '%john%'
95
+ buildWhere({ name: { $notLike: '%test%' } }); // NOT LIKE '%test%'
96
+
97
+ // Range and null
98
+ buildWhere({ price: { $between: [10, 100] } }); // BETWEEN 10 AND 100
99
+ buildWhere({ deletedAt: { $isNull: true } }); // IS NULL
100
+ buildWhere({ email: { $isNull: false } }); // IS NOT NULL
101
+
102
+ // Logical operators
103
+ buildWhere({ $or: [{ active: true }, { role: 'admin' }] });
104
+ buildWhere({ $and: [{ price: { $gt: 50 } }, { stock: { $gt: 0 } }] });
105
+ buildWhere({ $nor: [{ banned: true }, { suspended: true }] });
106
+ ```
107
+
108
+ ## Multi-Language Support
109
+
110
+ Schema fields marked with `.translatable()` are stored in separate translation tables:
111
+
112
+ ```typescript
113
+ // Schema
114
+ products: {
115
+ id: f.id(),
116
+ price: f.decimal(),
117
+ name: f.string().translatable(), // Stored in products_translations
118
+ description: f.text().translatable(), // Stored in products_translations
119
+ }
120
+
121
+ // Creates tables:
122
+ // - products (id, price)
123
+ // - products_translations (id, product_id, lang, name, description)
124
+ ```
125
+
126
+ Query with language:
127
+
128
+ ```typescript
129
+ const products = await dm.query('products', {
130
+ lang: 'tr',
131
+ fallbackLang: 'en', // Falls back if translation missing
132
+ });
133
+ ```
134
+
135
+ ## Types
136
+
137
+ ```typescript
138
+ import type {
139
+ Schema,
140
+ TableDefinition,
141
+ FieldDefinition,
142
+ QueryOptions,
143
+ WhereClause,
144
+ } from '@promakeai/orm';
145
+ ```
146
+
147
+ ## Related Packages
148
+
149
+ - [@promakeai/dbcli](../dbcli) - CLI tool
150
+ - [@promakeai/dbreact](../dbreact) - React integration
151
+
152
+ ## License
153
+
154
+ MIT
package/dist/ORM.d.ts ADDED
@@ -0,0 +1,190 @@
1
+ /**
2
+ * ORM Class - Main Entry Point
3
+ *
4
+ * Database-agnostic ORM that works with any adapter implementing IDataAdapter.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { ORM } from '@promakeai/orm';
9
+ * import { SqliteAdapter } from '@promakeai/dbcli';
10
+ *
11
+ * const adapter = new SqliteAdapter('./database.db');
12
+ * const db = new ORM(adapter);
13
+ *
14
+ * // List with filters and populate
15
+ * const posts = await db.list('posts', {
16
+ * where: { published: true },
17
+ * populate: ['userId', 'categoryIds'],
18
+ * orderBy: [{ field: 'created_at', direction: 'DESC' }],
19
+ * limit: 10,
20
+ * });
21
+ *
22
+ * // Create
23
+ * const post = await db.create('posts', { title: 'Hello', published: true });
24
+ *
25
+ * // Transaction
26
+ * await db.transaction(async (tx) => {
27
+ * await tx.create('posts', { title: 'Post 1' });
28
+ * await tx.create('posts', { title: 'Post 2' });
29
+ * });
30
+ * ```
31
+ */
32
+ import type { IDataAdapter } from "./adapters/IDataAdapter";
33
+ import type { QueryOptions, PaginatedResult, SchemaDefinition, ORMConfig } from "./types";
34
+ /**
35
+ * Main ORM class - Completely adapter agnostic
36
+ */
37
+ export declare class ORM {
38
+ private adapter;
39
+ private schema?;
40
+ private defaultLang;
41
+ private fallbackLang?;
42
+ /**
43
+ * Create ORM instance with any adapter
44
+ *
45
+ * @param adapter - Any object implementing IDataAdapter interface
46
+ * @param config - Optional configuration
47
+ */
48
+ constructor(adapter: IDataAdapter, config?: ORMConfig);
49
+ /**
50
+ * List records from table
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * // Simple list
55
+ * const products = await db.list('products');
56
+ *
57
+ * // With populate
58
+ * const products = await db.list('products', {
59
+ * where: { active: true },
60
+ * populate: ['categoryId', 'brandId'],
61
+ * limit: 10,
62
+ * });
63
+ * // Each product has .category and .brand objects
64
+ *
65
+ * // Nested populate
66
+ * const orders = await db.list('orders', {
67
+ * populate: [
68
+ * 'userId',
69
+ * { path: 'items', populate: ['productId'] }
70
+ * ]
71
+ * });
72
+ * ```
73
+ */
74
+ list<T = unknown>(table: string, options?: QueryOptions): Promise<T[]>;
75
+ /**
76
+ * Get single record by ID
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const product = await db.get('products', 1, {
81
+ * populate: ['categoryId']
82
+ * });
83
+ * console.log(product.category.name);
84
+ * ```
85
+ */
86
+ get<T = unknown>(table: string, id: string | number, options?: QueryOptions): Promise<T | null>;
87
+ /**
88
+ * Count records
89
+ */
90
+ count(table: string, options?: QueryOptions): Promise<number>;
91
+ /**
92
+ * Paginated query
93
+ */
94
+ paginate<T = unknown>(table: string, page: number, limit: number, options?: QueryOptions): Promise<PaginatedResult<T>>;
95
+ /**
96
+ * Create new record
97
+ */
98
+ create<T = unknown>(table: string, data: Record<string, unknown>): Promise<T>;
99
+ /**
100
+ * Update record by ID
101
+ */
102
+ update<T = unknown>(table: string, id: string | number, data: Record<string, unknown>): Promise<T>;
103
+ /**
104
+ * Delete record by ID
105
+ */
106
+ delete(table: string, id: string | number): Promise<boolean>;
107
+ /**
108
+ * Create multiple records
109
+ */
110
+ createMany<T = unknown>(table: string, records: Record<string, unknown>[], options?: {
111
+ ignore?: boolean;
112
+ }): Promise<{
113
+ created: number;
114
+ ids: (number | bigint)[];
115
+ }>;
116
+ /**
117
+ * Update multiple records
118
+ */
119
+ updateMany(table: string, updates: {
120
+ id: number | string;
121
+ data: Record<string, unknown>;
122
+ }[]): Promise<{
123
+ updated: number;
124
+ }>;
125
+ /**
126
+ * Delete multiple records
127
+ */
128
+ deleteMany(table: string, ids: (number | string)[]): Promise<{
129
+ deleted: number;
130
+ }>;
131
+ /**
132
+ * Execute raw query
133
+ */
134
+ raw<T = unknown>(query: string, params?: unknown[]): Promise<T[]>;
135
+ /**
136
+ * Execute raw statement
137
+ */
138
+ execute(query: string, params?: unknown[]): Promise<{
139
+ changes: number;
140
+ lastInsertRowid: number | bigint;
141
+ }>;
142
+ /**
143
+ * Transaction wrapper
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * await db.transaction(async (tx) => {
148
+ * const user = await tx.create('users', { name: 'John' });
149
+ * await tx.create('posts', { title: 'Hello', userId: user.id });
150
+ * });
151
+ * ```
152
+ */
153
+ transaction<T>(callback: (orm: ORM) => Promise<T>): Promise<T>;
154
+ /**
155
+ * Get all table names
156
+ */
157
+ getTables(): Promise<string[]>;
158
+ /**
159
+ * Get table schema
160
+ */
161
+ getTableSchema(table: string): Promise<unknown[]>;
162
+ /**
163
+ * Close connection
164
+ */
165
+ close(): Promise<void>;
166
+ /**
167
+ * Normalize query options
168
+ */
169
+ private normalizeOptions;
170
+ /**
171
+ * Validate data against schema
172
+ */
173
+ private validateData;
174
+ /**
175
+ * Resolve populate for records
176
+ */
177
+ private resolvePopulateForRecords;
178
+ /**
179
+ * Get the underlying adapter (for advanced usage)
180
+ */
181
+ getAdapter(): IDataAdapter;
182
+ /**
183
+ * Get current schema (if set)
184
+ */
185
+ getSchema(): SchemaDefinition | undefined;
186
+ /**
187
+ * Set schema
188
+ */
189
+ setSchema(schema: SchemaDefinition): void;
190
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Data Adapter Interface
3
+ *
4
+ * All data sources must implement this interface.
5
+ * This is the contract between ORM and adapters.
6
+ *
7
+ * Features:
8
+ * - Built-in multi-language support via lang option
9
+ * - Automatic translation handling for translatable fields
10
+ * - MongoDB-style populate for references
11
+ */
12
+ import type { QueryOptions, PaginatedResult, SchemaDefinition } from "../types";
13
+ /**
14
+ * Generic Data Adapter Interface
15
+ */
16
+ export interface IDataAdapter {
17
+ /**
18
+ * Schema definition for translation support (optional)
19
+ */
20
+ schema?: SchemaDefinition;
21
+ /**
22
+ * Default language for translations
23
+ */
24
+ defaultLang?: string;
25
+ /**
26
+ * Set schema after construction
27
+ */
28
+ setSchema?(schema: SchemaDefinition): void;
29
+ /**
30
+ * Initialize the adapter (optional)
31
+ */
32
+ connect?(): void | Promise<void>;
33
+ /**
34
+ * List records from table
35
+ */
36
+ list<T = unknown>(table: string, options?: QueryOptions): Promise<T[]>;
37
+ /**
38
+ * Get single record by ID
39
+ */
40
+ get<T = unknown>(table: string, id: string | number, options?: QueryOptions): Promise<T | null>;
41
+ /**
42
+ * Count records matching condition
43
+ */
44
+ count(table: string, options?: QueryOptions): Promise<number>;
45
+ /**
46
+ * Query with pagination
47
+ */
48
+ paginate<T = unknown>(table: string, page: number, limit: number, options?: QueryOptions): Promise<PaginatedResult<T>>;
49
+ /**
50
+ * Create new record
51
+ */
52
+ create<T = unknown>(table: string, data: Record<string, unknown>): Promise<T>;
53
+ /**
54
+ * Update record by ID
55
+ */
56
+ update<T = unknown>(table: string, id: string | number, data: Record<string, unknown>): Promise<T>;
57
+ /**
58
+ * Delete record by ID
59
+ */
60
+ delete(table: string, id: string | number): Promise<boolean>;
61
+ /**
62
+ * Create multiple records
63
+ */
64
+ createMany<T = unknown>(table: string, records: Record<string, unknown>[], options?: {
65
+ ignore?: boolean;
66
+ }): Promise<{
67
+ created: number;
68
+ ids: (number | bigint)[];
69
+ }>;
70
+ /**
71
+ * Update multiple records
72
+ */
73
+ updateMany(table: string, updates: {
74
+ id: number | string;
75
+ data: Record<string, unknown>;
76
+ }[]): Promise<{
77
+ updated: number;
78
+ }>;
79
+ /**
80
+ * Delete multiple records
81
+ */
82
+ deleteMany(table: string, ids: (number | string)[]): Promise<{
83
+ deleted: number;
84
+ }>;
85
+ /**
86
+ * Create record with translations in a single transaction
87
+ * If translations not provided but data contains translatable fields,
88
+ * those fields are automatically added as defaultLang translation
89
+ */
90
+ createWithTranslations<T = unknown>(table: string, data: Record<string, unknown>, translations?: Record<string, Record<string, unknown>>): Promise<T>;
91
+ /**
92
+ * Update or insert translation for specific language
93
+ */
94
+ upsertTranslation(table: string, id: string | number, lang: string, data: Record<string, unknown>): Promise<void>;
95
+ /**
96
+ * Get all translations for a record
97
+ */
98
+ getTranslations<T = unknown>(table: string, id: string | number): Promise<T[]>;
99
+ /**
100
+ * Execute raw query (adapter-specific)
101
+ */
102
+ raw<T = unknown>(query: string, params?: unknown[]): Promise<T[]>;
103
+ /**
104
+ * Execute raw statement (for INSERT/UPDATE/DELETE)
105
+ */
106
+ execute(query: string, params?: unknown[]): Promise<{
107
+ changes: number;
108
+ lastInsertRowid: number | bigint;
109
+ }>;
110
+ /**
111
+ * Begin transaction
112
+ */
113
+ beginTransaction(): Promise<void>;
114
+ /**
115
+ * Commit transaction
116
+ */
117
+ commit(): Promise<void>;
118
+ /**
119
+ * Rollback transaction
120
+ */
121
+ rollback(): Promise<void>;
122
+ /**
123
+ * Get all table names
124
+ */
125
+ getTables?(): Promise<string[]>;
126
+ /**
127
+ * Get table schema/structure
128
+ */
129
+ getTableSchema?(table: string): Promise<unknown[]>;
130
+ /**
131
+ * Close connection
132
+ */
133
+ close(): void | Promise<void>;
134
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @promakeai/orm - Database-Agnostic ORM
3
+ *
4
+ * Works in browser and Node.js with any adapter implementing IDataAdapter.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { ORM, defineSchema, f } from '@promakeai/orm';
9
+ *
10
+ * // Define schema
11
+ * const schema = defineSchema({
12
+ * languages: ['en', 'tr'],
13
+ * tables: {
14
+ * products: {
15
+ * id: f.id(),
16
+ * name: f.string().translatable().required(),
17
+ * price: f.decimal().required(),
18
+ * categoryId: f.int().ref('categories'),
19
+ * },
20
+ * categories: {
21
+ * id: f.id(),
22
+ * name: f.string().translatable().required(),
23
+ * },
24
+ * },
25
+ * });
26
+ *
27
+ * // Use with adapter
28
+ * const db = new ORM(adapter, { schema });
29
+ * const products = await db.list('products', {
30
+ * where: { price: { $gt: 100 } },
31
+ * populate: ['categoryId'],
32
+ * });
33
+ * ```
34
+ */
35
+ export { ORM } from "./ORM";
36
+ export type { IDataAdapter } from "./adapters/IDataAdapter";
37
+ export { defineSchema, f, mergeSchemas, createSchemaUnsafe, } from "./schema";
38
+ export type { FieldBuilder } from "./schema";
39
+ export { validateSchema, assertValidSchema, isValidSchema, validateTable, ValidationErrorCode, } from "./schema";
40
+ export type { ValidationError } from "./schema";
41
+ export { singularize, pluralize, toPascalCase, toCamelCase, toSnakeCase, toInterfaceName, toDbInterfaceName, toPascalCasePlural, toTranslationTableName, toTranslationFKName, } from "./schema";
42
+ export { getTranslatableFields, getNonTranslatableFields, getInsertableFields, hasTranslatableFields, getPrimaryKeyField, getReferenceFields, getMainTableFields, getTranslationTableFields, isRequiredField, getRequiredFields, getRefTarget, getRefTargetFull, } from "./schema";
43
+ export { buildWhereClause } from "./utils/whereBuilder";
44
+ export type { WhereResult } from "./utils/whereBuilder";
45
+ export { buildTranslationQuery, buildTranslationQueryById, buildTranslationInsert, buildTranslationUpsert, extractTranslatableData, } from "./utils/translationQuery";
46
+ export type { TranslationQueryOptions, TranslationQueryResult, } from "./utils/translationQuery";
47
+ export { resolvePopulate, getPopulatableFields, validatePopulate, } from "./utils/populateResolver";
48
+ export type { PopulateAdapter } from "./utils/populateResolver";
49
+ export { parseJSONSchema } from "./utils/jsonConverter";
50
+ export type { FieldType, FieldDefinition, FieldReference, FieldBuilderLike, TableDefinition, LanguageConfig, SchemaDefinition, SchemaInput, JSONFieldDefinition, JSONTableDefinition, JSONSchemaDefinition, WhereCondition, OrderByOption, PopulateOption, PopulateNested, QueryOptions, PaginatedResult, ORMConfig, } from "./types";