@xansql/bridge 1.0.1 → 1.0.2

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 CHANGED
@@ -1,359 +1,359 @@
1
- # xansql
2
-
3
- <p align="center">
4
- <strong>Type-safe, event-driven SQL ORM with automatic schema synchronization, composable relations, granular hooks, and optional client execution bridge.</strong>
5
- </p>
6
-
7
- <p align="center">
8
- <!-- Badges (replace placeholders when public) -->
9
- <a href="#"><img alt="license" src="https://img.shields.io/badge/license-MIT-blue"/></a>
10
- <a href="#"><img alt="status" src="https://img.shields.io/badge/status-beta-orange"/></a>
11
- <a href="#"><img alt="dialects" src="https://img.shields.io/badge/dialects-mysql%20%7C%20postgresql%20%7C%20sqlite-6A5ACD"/></a>
12
- </p>
13
-
14
- ---
15
-
16
- ## Executive Summary
17
- xansql is a minimalist but powerful ORM focusing on:
18
- - Deterministic schema definition (single source of truth) with non-destructive migration.
19
- - Relation traversal via declarative `select` trees (preventing circular graphs).
20
- - Rich predicate language in `where` supporting deep `EXISTS` on nested relations.
21
- - Event system & lifecycle hooks (global + per-model) for observability & cross-cutting concerns.
22
- - Pluggable caching, file storage, fetch bridge (browser safe), and socket integration.
23
- - Lightweight execution pipeline: thin SQL generation, no heavy runtime proxies.
24
-
25
- ---
26
- ## Contents
27
- 1. Features
28
- 2. Architecture Overview
29
- 3. Installation
30
- 4. Quick Start
31
- 5. Configuration Reference
32
- 6. Defining Models & Fields
33
- 7. Relations
34
- 8. Querying & Predicates
35
- 9. Aggregation & Helpers
36
- 10. Pagination & Convenience APIs
37
- 11. Transactions
38
- 12. Migrations
39
- 13. Events & Hooks
40
- 14. File Handling
41
- 15. Client Fetch Bridge
42
- 16. Caching Interface
43
- 17. Dialects & Custom Implementation
44
- 18. Error Handling & Validation
45
- 19. Security Considerations
46
- 20. Performance Guidance
47
- 21. FAQ
48
- 22. Roadmap
49
- 23. License
50
-
51
- ---
52
- ## 1. Features
53
- - Multi-dialect: MySQL, PostgreSQL, SQLite (custom adapter friendly)
54
- - Auto aliasing + integrity checks
55
- - Declarative relations (`xt.schema` / array reverse mapping)
56
- - Non-destructive migrate (add/modify/remove columns) + force rebuild
57
- - Granular lifecycle hooks & event emission
58
- - Rich `where` condition operators (logical AND/OR composition)
59
- - Nested relational filtering through `EXISTS` semantics
60
- - Aggregation inline or via helper methods
61
- - Optional caching module contract
62
- - Integrated file meta handling & streaming upload abstraction
63
- - Client-side safe execution (no raw SQL leakage) via signed execution meta
64
-
65
- ---
66
- ## 2. Architecture Overview
67
- Layered components:
68
- - Core: `Xansql` orchestrates config, model registry, transactions, migration, fetch bridge and events.
69
- - Model: Provides CRUD + query generation + relation resolution.
70
- - Executers: Specialized operation builders (Find / Create / Update / Delete / Aggregate).
71
- - Migration: Computes delta from declared schema vs dialect metadata and issues SQL.
72
- - Types System: Field factories (`xt.*`) with metadata (length, unique, index, validators, transforms).
73
- - Foreign Resolver: Normalizes forward & reverse relation mapping for join/exists generation.
74
- - Fetch Bridge: Validates request meta for client-originated operations (server controlled).
75
-
76
- ---
77
- ## 3. Installation
78
- ```bash
79
- npm install xansql mysql2 pg better-sqlite3
80
- # Or only the drivers you need
81
- ```
82
- SQLite usage recommends `better-sqlite3` for synchronous performance.
83
-
84
- ---
85
- ## 4. Quick Start
86
- ```ts
87
- import { Xansql, Model, xt } from 'xansql';
88
- import MysqlDialect from 'xansql/dist/libs/MysqlDialect';
89
-
90
- const db = new Xansql({
91
- dialect: MysqlDialect({ host: '127.0.0.1', user: 'root', password: '', database: 'app' })
92
- });
93
-
94
- const User = db.model('users', {
95
- id: xt.id(),
96
- username: xt.username(),
97
- email: xt.email().unique(),
98
- password: xt.password().strong(),
99
- role: xt.role(['admin', 'member']),
100
- createdAt: xt.createdAt(),
101
- updatedAt: xt.updatedAt()
102
- });
103
-
104
- await db.migrate();
105
- await User.create({ data: [{ username: 'alice', email: 'a@b.com', password: 'Pwd@1234', role: 'member' }] });
106
- const result = await User.find({ where: { username: { equals: 'alice' } } });
107
- ```
108
-
109
- ---
110
- ## 5. Configuration Reference
111
- ```ts
112
- new Xansql({
113
- dialect: MysqlDialect({...}), // REQUIRED
114
- fetch: { url: '/xansql', mode: 'production' }, // optional (client bridge)
115
- socket: { open, message, close }, // optional WebSocket handlers
116
- cache: { cache, clear, onFind, onCreate, onUpdate, onDelete }, // optional
117
- file: { maxFilesize, chunkSize, upload, delete }, // optional file storage
118
- maxLimit: { find, create, update, delete }, // safety caps (default 100)
119
- hooks: { beforeFind, afterFind, transform, ... } // global async hooks
120
- });
121
- ```
122
- Required dialect interface:
123
- ```ts
124
- interface XansqlDialect {
125
- engine: 'mysql' | 'postgresql' | 'sqlite';
126
- execute(sql: string): Promise<{ results: any[]; affectedRows: number; insertId: number | null }>;
127
- getSchema(): Promise<{ [table: string]: { name: string; type: string; notnull: boolean; default_value: any; pk: boolean; index: boolean; unique: boolean }[] }>
128
- }
129
- ```
130
-
131
- ---
132
- ## 6. Defining Models & Fields
133
- ```ts
134
- const Post = db.model('posts', {
135
- id: xt.id(),
136
- title: xt.title().index(),
137
- slug: xt.slug().unique(),
138
- author: xt.schema('users', 'id'), // FK forward
139
- tags: xt.array(xt.string(30)), // array (not in where predicate)
140
- images: xt.array(xt.file()), // file metadata entries
141
- createdAt: xt.createdAt(),
142
- updatedAt: xt.updatedAt()
143
- });
144
- ```
145
- Per-model hooks:
146
- ```ts
147
- Post.options.hooks = {
148
- beforeCreate: async (args) => args,
149
- transform: async (row) => { delete row.password; return row; }
150
- };
151
- ```
152
- Field factory highlights: `id, string, number, boolean, date, enum, array, object, record, tuple, union, file, schema` + semantic shortcuts (`username`, `email`, `password`, `slug`, `role`, `title`, `amount`, etc.). Most fields accept chainable validators (`min`, `max`, `unique`, `index`, `transform`).
153
-
154
- Foreign key patterns:
155
- - Forward: `xt.schema('users','id')`
156
- - Reverse (one-to-many): `xt.array(xt.schema('posts','id'))`
157
-
158
- ---
159
- ## 7. Relations
160
- Select nested relations:
161
- ```ts
162
- await User.find({
163
- select: {
164
- id: true,
165
- username: true,
166
- posts: {
167
- select: { id: true, title: true },
168
- where: { title: { contains: 'SQL' } },
169
- limit: { take: 5 }
170
- }
171
- }
172
- });
173
- ```
174
- Circular graphs are rejected early.
175
-
176
- ---
177
- ## 8. Querying & Predicates
178
- Operators: `equals, not, lt, lte, gt, gte, in, notIn, between, notBetween, contains, notContains, startsWith, endsWith, isNull, isNotNull, isEmpty, isNotEmpty, isTrue, isFalse`.
179
- - Object => AND
180
- - Array of objects => OR
181
- - Nested relation in `where` => EXISTS subquery
182
- Example:
183
- ```ts
184
- await Post.find({
185
- where: {
186
- author: { username: { startsWith: 'a' } },
187
- slug: { notContains: 'draft' },
188
- title: [{ contains: 'Guide' }, { contains: 'Intro' }]
189
- }
190
- });
191
- ```
192
-
193
- ---
194
- ## 9. Aggregation & Helpers
195
- Inline:
196
- ```ts
197
- await User.find({ aggregate: { id: { count: true } } });
198
- ```
199
- Helpers: `count(where)`, `min(col, where)`, `max`, `sum`, `avg`, `exists(where)`.
200
-
201
- ---
202
- ## 10. Pagination & Convenience
203
- ```ts
204
- const page = await User.paginate(2, { perpage: 20, where: { role: { equals: 'member' } } });
205
- // { page, perpage, pagecount, rowcount, results }
206
- ```
207
- Also: `findOne(args)`, `findById(id, args)`.
208
-
209
- ---
210
- ## 11. Transactions
211
- Automatic for create/update/delete unless within chained relation execution.
212
- Manual wrapper:
213
- ```ts
214
- await db.transaction(async () => {
215
- await User.create({ data: [{ username: 'temp' }] });
216
- await User.update({ data: { role: 'admin' }, where: { username: 'temp' } });
217
- });
218
- ```
219
- Rollback on error.
220
-
221
- ---
222
- ## 12. Migrations
223
- ```ts
224
- await db.migrate(); // sync non-destructively
225
- await db.migrate(true); // drop + recreate (files cleaned)
226
- const preview = await db.generateMigration(); // array of SQL statements
227
- ```
228
- Rules:
229
- - Skips ID column alterations.
230
- - Adds new columns; drops removed ones; issues ALTER for changed definition.
231
- - Force rebuild executes reverse-order drops then creates.
232
-
233
- ---
234
- ## 13. Events & Hooks
235
- Events emitted: `BEFORE_CREATE, CREATE, BEFORE_UPDATE, UPDATE, BEFORE_DELETE, DELETE, BEFORE_FIND, FIND, BEFORE_AGGREGATE, AGGREGATE, BEFORE_FETCH, FETCH`.
236
- Usage:
237
- ```ts
238
- db.on('CREATE', ({ model, results }) => { /* audit */ });
239
- ```
240
- Hooks (global & model-level) allow mutation of args/results or row transform.
241
-
242
- ---
243
- ## 14. File Handling
244
- Define file fields: `xt.file(size?)` / arrays.
245
- Configure storage:
246
- ```ts
247
- file: {
248
- maxFilesize: 2048, // KB
249
- chunkSize: 256, // KB (streaming)
250
- upload: async (chunk, meta) => {},
251
- delete: async (filename) => {}
252
- }
253
- ```
254
- Client helpers: `uploadFile(file, executeId)`, `deleteFile(name, executeId)`.
255
-
256
- ---
257
- ## 15. Client Fetch Bridge
258
- Provide `fetch: string | { url, mode }`.
259
- Client side raw SQL blocked; operations require internally generated `executeId` (granted per model action via metadata).
260
- Server integrates:
261
- ```ts
262
- const response = await db.onFetch(req.url, {
263
- body: req.body,
264
- headers: req.headers,
265
- cookies: parseCookies(req),
266
- isAuthorized: async (meta) => {/* check meta.action, meta.model */ return true; }
267
- });
268
- ```
269
-
270
- ---
271
- ## 16. Caching Interface
272
- Implement partial or full row caching:
273
- ```ts
274
- cache: {
275
- cache: async (sql, model) => /* rows or undefined */,
276
- clear: async (model) => {},
277
- onFind: async (sql, model, row) => {},
278
- onCreate: async (model, insertId) => {},
279
- onUpdate: async (model, rows) => {},
280
- onDelete: async (model, rows) => {},
281
- }
282
- ```
283
- You decide strategy (memory, redis, browser IndexedDB via example adapters).
284
-
285
- ---
286
- ## 17. Dialects & Custom Implementation
287
- Built-ins: `MysqlDialect`, `PostgresDialect`, `SqliteDialect`.
288
- Custom:
289
- ```ts
290
- const CustomDialect = () => ({
291
- engine: 'mysql',
292
- execute: async (sql) => {/* run */ return { results: [], affectedRows: 0, insertId: 0 };},
293
- getSchema: async () => ({ /* table: columns[] */ })
294
- });
295
- ```
296
- `getSchema` must supply column index/unique flags for migration diffing.
297
-
298
- ---
299
- ## 18. Error Handling & Validation
300
- Common thrown errors:
301
- - Missing dialect or execute function
302
- - Unsupported engine
303
- - Model without ID field
304
- - Duplicate model name / alias collision
305
- - Invalid where operator or disallowed field type in predicate (array/object/record/tuple)
306
- - Circular relation selection / where nesting
307
- - Client usage without fetch configuration
308
- - Raw query attempt from client without `executeId`
309
- - Invalid foreign key definition
310
-
311
- ---
312
- ## 19. Security Considerations
313
- - All value interpolation passes through escaping utilities.
314
- - Client cannot send arbitrary SQL (requires signed meta created server-side).
315
- - Hooks & events can enforce auditing, RBAC, masking.
316
- - Password field helper automatically hashes via SHA-256 transform.
317
- - Recommend additional app-layer input validation before invoking ORM.
318
-
319
- ---
320
- ## 20. Performance Guidance
321
- - Prefer selective `select` trees over full-table scans.
322
- - Use indexes via field `.index()` / `.unique()` early (migration will create).
323
- - Enable caching for heavy read patterns.
324
- - Use pagination helpers (`paginate`) to avoid large offset scans.
325
- - Keep relation depth shallow to limit EXISTS nesting.
326
- - Batch `create` with array `data` for reduced round trips.
327
-
328
- ---
329
- ## 21. FAQ
330
- Q: Does xansql generate JOINs?
331
- A: Relation filters use `EXISTS` subqueries; selection fetches related sets separately.
332
-
333
- Q: How are reverse (one-to-many) relations defined?
334
- A: `xt.array(xt.schema('childTable','id'))` inside the parent references children.
335
-
336
- Q: Can I rename columns automatically?
337
- A: Rename support is planned (see roadmap). Current diff treats rename as drop + add.
338
-
339
- Q: Can I use raw SQL?
340
- A: Server side `db.execute(sql)` is allowed; client side raw is blocked.
341
-
342
- ---
343
- ## 22. Roadmap
344
- - Column / index rename migration operations
345
- - CLI code generation & schema inspector
346
- - Enhanced diff reporting (explain changes)
347
- - Advanced relation eager constraints (depth limiting strategies)
348
- - Pluggable authorization middleware bundle
349
-
350
- ---
351
- ## 23. License
352
- MIT
353
-
354
- ---
355
- ## Attributions
356
- Internal field validation leverages concepts from `xanv`. File handling meta uses `securequ` upload structures.
357
-
358
- ---
359
- > Need adjustments (badges, examples, tutorials)? Open an issue or contribute.
1
+ # xansql
2
+
3
+ <p align="center">
4
+ <strong>Type-safe, event-driven SQL ORM with automatic schema synchronization, composable relations, granular hooks, and optional client execution bridge.</strong>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <!-- Badges (replace placeholders when public) -->
9
+ <a href="#"><img alt="license" src="https://img.shields.io/badge/license-MIT-blue"/></a>
10
+ <a href="#"><img alt="status" src="https://img.shields.io/badge/status-beta-orange"/></a>
11
+ <a href="#"><img alt="dialects" src="https://img.shields.io/badge/dialects-mysql%20%7C%20postgresql%20%7C%20sqlite-6A5ACD"/></a>
12
+ </p>
13
+
14
+ ---
15
+
16
+ ## Executive Summary
17
+ xansql is a minimalist but powerful ORM focusing on:
18
+ - Deterministic schema definition (single source of truth) with non-destructive migration.
19
+ - Relation traversal via declarative `select` trees (preventing circular graphs).
20
+ - Rich predicate language in `where` supporting deep `EXISTS` on nested relations.
21
+ - Event system & lifecycle hooks (global + per-model) for observability & cross-cutting concerns.
22
+ - Pluggable caching, file storage, fetch bridge (browser safe), and socket integration.
23
+ - Lightweight execution pipeline: thin SQL generation, no heavy runtime proxies.
24
+
25
+ ---
26
+ ## Contents
27
+ 1. Features
28
+ 2. Architecture Overview
29
+ 3. Installation
30
+ 4. Quick Start
31
+ 5. Configuration Reference
32
+ 6. Defining Models & Fields
33
+ 7. Relations
34
+ 8. Querying & Predicates
35
+ 9. Aggregation & Helpers
36
+ 10. Pagination & Convenience APIs
37
+ 11. Transactions
38
+ 12. Migrations
39
+ 13. Events & Hooks
40
+ 14. File Handling
41
+ 15. Client Fetch Bridge
42
+ 16. Caching Interface
43
+ 17. Dialects & Custom Implementation
44
+ 18. Error Handling & Validation
45
+ 19. Security Considerations
46
+ 20. Performance Guidance
47
+ 21. FAQ
48
+ 22. Roadmap
49
+ 23. License
50
+
51
+ ---
52
+ ## 1. Features
53
+ - Multi-dialect: MySQL, PostgreSQL, SQLite (custom adapter friendly)
54
+ - Auto aliasing + integrity checks
55
+ - Declarative relations (`xt.schema` / array reverse mapping)
56
+ - Non-destructive migrate (add/modify/remove columns) + force rebuild
57
+ - Granular lifecycle hooks & event emission
58
+ - Rich `where` condition operators (logical AND/OR composition)
59
+ - Nested relational filtering through `EXISTS` semantics
60
+ - Aggregation inline or via helper methods
61
+ - Optional caching module contract
62
+ - Integrated file meta handling & streaming upload abstraction
63
+ - Client-side safe execution (no raw SQL leakage) via signed execution meta
64
+
65
+ ---
66
+ ## 2. Architecture Overview
67
+ Layered components:
68
+ - Core: `Xansql` orchestrates config, model registry, transactions, migration, fetch bridge and events.
69
+ - Model: Provides CRUD + query generation + relation resolution.
70
+ - Executers: Specialized operation builders (Find / Create / Update / Delete / Aggregate).
71
+ - Migration: Computes delta from declared schema vs dialect metadata and issues SQL.
72
+ - Types System: Field factories (`xt.*`) with metadata (length, unique, index, validators, transforms).
73
+ - Foreign Resolver: Normalizes forward & reverse relation mapping for join/exists generation.
74
+ - Fetch Bridge: Validates request meta for client-originated operations (server controlled).
75
+
76
+ ---
77
+ ## 3. Installation
78
+ ```bash
79
+ npm install xansql mysql2 pg better-sqlite3
80
+ # Or only the drivers you need
81
+ ```
82
+ SQLite usage recommends `better-sqlite3` for synchronous performance.
83
+
84
+ ---
85
+ ## 4. Quick Start
86
+ ```ts
87
+ import { Xansql, Model, xt } from 'xansql';
88
+ import MysqlDialect from 'xansql/dist/libs/MysqlDialect';
89
+
90
+ const db = new Xansql({
91
+ dialect: MysqlDialect({ host: '127.0.0.1', user: 'root', password: '', database: 'app' })
92
+ });
93
+
94
+ const User = db.model('users', {
95
+ id: xt.id(),
96
+ username: xt.username(),
97
+ email: xt.email().unique(),
98
+ password: xt.password().strong(),
99
+ role: xt.role(['admin', 'member']),
100
+ createdAt: xt.createdAt(),
101
+ updatedAt: xt.updatedAt()
102
+ });
103
+
104
+ await db.migrate();
105
+ await User.create({ data: [{ username: 'alice', email: 'a@b.com', password: 'Pwd@1234', role: 'member' }] });
106
+ const result = await User.find({ where: { username: { equals: 'alice' } } });
107
+ ```
108
+
109
+ ---
110
+ ## 5. Configuration Reference
111
+ ```ts
112
+ new Xansql({
113
+ dialect: MysqlDialect({...}), // REQUIRED
114
+ fetch: { url: '/xansql', mode: 'production' }, // optional (client bridge)
115
+ socket: { open, message, close }, // optional WebSocket handlers
116
+ cache: { cache, clear, onFind, onCreate, onUpdate, onDelete }, // optional
117
+ file: { maxFilesize, chunkSize, upload, delete }, // optional file storage
118
+ maxLimit: { find, create, update, delete }, // safety caps (default 100)
119
+ hooks: { beforeFind, afterFind, transform, ... } // global async hooks
120
+ });
121
+ ```
122
+ Required dialect interface:
123
+ ```ts
124
+ interface XansqlDialect {
125
+ engine: 'mysql' | 'postgresql' | 'sqlite';
126
+ execute(sql: string): Promise<{ results: any[]; affectedRows: number; insertId: number | null }>;
127
+ getSchema(): Promise<{ [table: string]: { name: string; type: string; notnull: boolean; default_value: any; pk: boolean; index: boolean; unique: boolean }[] }>
128
+ }
129
+ ```
130
+
131
+ ---
132
+ ## 6. Defining Models & Fields
133
+ ```ts
134
+ const Post = db.model('posts', {
135
+ id: xt.id(),
136
+ title: xt.title().index(),
137
+ slug: xt.slug().unique(),
138
+ author: xt.schema('users', 'id'), // FK forward
139
+ tags: xt.array(xt.string(30)), // array (not in where predicate)
140
+ images: xt.array(xt.file()), // file metadata entries
141
+ createdAt: xt.createdAt(),
142
+ updatedAt: xt.updatedAt()
143
+ });
144
+ ```
145
+ Per-model hooks:
146
+ ```ts
147
+ Post.options.hooks = {
148
+ beforeCreate: async (args) => args,
149
+ transform: async (row) => { delete row.password; return row; }
150
+ };
151
+ ```
152
+ Field factory highlights: `id, string, number, boolean, date, enum, array, object, record, tuple, union, file, schema` + semantic shortcuts (`username`, `email`, `password`, `slug`, `role`, `title`, `amount`, etc.). Most fields accept chainable validators (`min`, `max`, `unique`, `index`, `transform`).
153
+
154
+ Foreign key patterns:
155
+ - Forward: `xt.schema('users','id')`
156
+ - Reverse (one-to-many): `xt.array(xt.schema('posts','id'))`
157
+
158
+ ---
159
+ ## 7. Relations
160
+ Select nested relations:
161
+ ```ts
162
+ await User.find({
163
+ select: {
164
+ id: true,
165
+ username: true,
166
+ posts: {
167
+ select: { id: true, title: true },
168
+ where: { title: { contains: 'SQL' } },
169
+ limit: { take: 5 }
170
+ }
171
+ }
172
+ });
173
+ ```
174
+ Circular graphs are rejected early.
175
+
176
+ ---
177
+ ## 8. Querying & Predicates
178
+ Operators: `equals, not, lt, lte, gt, gte, in, notIn, between, notBetween, contains, notContains, startsWith, endsWith, isNull, isNotNull, isEmpty, isNotEmpty, isTrue, isFalse`.
179
+ - Object => AND
180
+ - Array of objects => OR
181
+ - Nested relation in `where` => EXISTS subquery
182
+ Example:
183
+ ```ts
184
+ await Post.find({
185
+ where: {
186
+ author: { username: { startsWith: 'a' } },
187
+ slug: { notContains: 'draft' },
188
+ title: [{ contains: 'Guide' }, { contains: 'Intro' }]
189
+ }
190
+ });
191
+ ```
192
+
193
+ ---
194
+ ## 9. Aggregation & Helpers
195
+ Inline:
196
+ ```ts
197
+ await User.find({ aggregate: { id: { count: true } } });
198
+ ```
199
+ Helpers: `count(where)`, `min(col, where)`, `max`, `sum`, `avg`, `exists(where)`.
200
+
201
+ ---
202
+ ## 10. Pagination & Convenience
203
+ ```ts
204
+ const page = await User.paginate(2, { perpage: 20, where: { role: { equals: 'member' } } });
205
+ // { page, perpage, pagecount, rowcount, results }
206
+ ```
207
+ Also: `findOne(args)`, `findById(id, args)`.
208
+
209
+ ---
210
+ ## 11. Transactions
211
+ Automatic for create/update/delete unless within chained relation execution.
212
+ Manual wrapper:
213
+ ```ts
214
+ await db.transaction(async () => {
215
+ await User.create({ data: [{ username: 'temp' }] });
216
+ await User.update({ data: { role: 'admin' }, where: { username: 'temp' } });
217
+ });
218
+ ```
219
+ Rollback on error.
220
+
221
+ ---
222
+ ## 12. Migrations
223
+ ```ts
224
+ await db.migrate(); // sync non-destructively
225
+ await db.migrate(true); // drop + recreate (files cleaned)
226
+ const preview = await db.generateMigration(); // array of SQL statements
227
+ ```
228
+ Rules:
229
+ - Skips ID column alterations.
230
+ - Adds new columns; drops removed ones; issues ALTER for changed definition.
231
+ - Force rebuild executes reverse-order drops then creates.
232
+
233
+ ---
234
+ ## 13. Events & Hooks
235
+ Events emitted: `BEFORE_CREATE, CREATE, BEFORE_UPDATE, UPDATE, BEFORE_DELETE, DELETE, BEFORE_FIND, FIND, BEFORE_AGGREGATE, AGGREGATE, BEFORE_FETCH, FETCH`.
236
+ Usage:
237
+ ```ts
238
+ db.on('CREATE', ({ model, results }) => { /* audit */ });
239
+ ```
240
+ Hooks (global & model-level) allow mutation of args/results or row transform.
241
+
242
+ ---
243
+ ## 14. File Handling
244
+ Define file fields: `xt.file(size?)` / arrays.
245
+ Configure storage:
246
+ ```ts
247
+ file: {
248
+ maxFilesize: 2048, // KB
249
+ chunkSize: 256, // KB (streaming)
250
+ upload: async (chunk, meta) => {},
251
+ delete: async (filename) => {}
252
+ }
253
+ ```
254
+ Client helpers: `uploadFile(file, executeId)`, `deleteFile(name, executeId)`.
255
+
256
+ ---
257
+ ## 15. Client Fetch Bridge
258
+ Provide `fetch: string | { url, mode }`.
259
+ Client side raw SQL blocked; operations require internally generated `executeId` (granted per model action via metadata).
260
+ Server integrates:
261
+ ```ts
262
+ const response = await db.onFetch(req.url, {
263
+ body: req.body,
264
+ headers: req.headers,
265
+ cookies: parseCookies(req),
266
+ isAuthorized: async (meta) => {/* check meta.action, meta.model */ return true; }
267
+ });
268
+ ```
269
+
270
+ ---
271
+ ## 16. Caching Interface
272
+ Implement partial or full row caching:
273
+ ```ts
274
+ cache: {
275
+ cache: async (sql, model) => /* rows or undefined */,
276
+ clear: async (model) => {},
277
+ onFind: async (sql, model, row) => {},
278
+ onCreate: async (model, insertId) => {},
279
+ onUpdate: async (model, rows) => {},
280
+ onDelete: async (model, rows) => {},
281
+ }
282
+ ```
283
+ You decide strategy (memory, redis, browser IndexedDB via example adapters).
284
+
285
+ ---
286
+ ## 17. Dialects & Custom Implementation
287
+ Built-ins: `MysqlDialect`, `PostgresDialect`, `SqliteDialect`.
288
+ Custom:
289
+ ```ts
290
+ const CustomDialect = () => ({
291
+ engine: 'mysql',
292
+ execute: async (sql) => {/* run */ return { results: [], affectedRows: 0, insertId: 0 };},
293
+ getSchema: async () => ({ /* table: columns[] */ })
294
+ });
295
+ ```
296
+ `getSchema` must supply column index/unique flags for migration diffing.
297
+
298
+ ---
299
+ ## 18. Error Handling & Validation
300
+ Common thrown errors:
301
+ - Missing dialect or execute function
302
+ - Unsupported engine
303
+ - Model without ID field
304
+ - Duplicate model name / alias collision
305
+ - Invalid where operator or disallowed field type in predicate (array/object/record/tuple)
306
+ - Circular relation selection / where nesting
307
+ - Client usage without fetch configuration
308
+ - Raw query attempt from client without `executeId`
309
+ - Invalid foreign key definition
310
+
311
+ ---
312
+ ## 19. Security Considerations
313
+ - All value interpolation passes through escaping utilities.
314
+ - Client cannot send arbitrary SQL (requires signed meta created server-side).
315
+ - Hooks & events can enforce auditing, RBAC, masking.
316
+ - Password field helper automatically hashes via SHA-256 transform.
317
+ - Recommend additional app-layer input validation before invoking ORM.
318
+
319
+ ---
320
+ ## 20. Performance Guidance
321
+ - Prefer selective `select` trees over full-table scans.
322
+ - Use indexes via field `.index()` / `.unique()` early (migration will create).
323
+ - Enable caching for heavy read patterns.
324
+ - Use pagination helpers (`paginate`) to avoid large offset scans.
325
+ - Keep relation depth shallow to limit EXISTS nesting.
326
+ - Batch `create` with array `data` for reduced round trips.
327
+
328
+ ---
329
+ ## 21. FAQ
330
+ Q: Does xansql generate JOINs?
331
+ A: Relation filters use `EXISTS` subqueries; selection fetches related sets separately.
332
+
333
+ Q: How are reverse (one-to-many) relations defined?
334
+ A: `xt.array(xt.schema('childTable','id'))` inside the parent references children.
335
+
336
+ Q: Can I rename columns automatically?
337
+ A: Rename support is planned (see roadmap). Current diff treats rename as drop + add.
338
+
339
+ Q: Can I use raw SQL?
340
+ A: Server side `db.execute(sql)` is allowed; client side raw is blocked.
341
+
342
+ ---
343
+ ## 22. Roadmap
344
+ - Column / index rename migration operations
345
+ - CLI code generation & schema inspector
346
+ - Enhanced diff reporting (explain changes)
347
+ - Advanced relation eager constraints (depth limiting strategies)
348
+ - Pluggable authorization middleware bundle
349
+
350
+ ---
351
+ ## 23. License
352
+ MIT
353
+
354
+ ---
355
+ ## Attributions
356
+ Internal field validation leverages concepts from `xanv`. File handling meta uses `securequ` upload structures.
357
+
358
+ ---
359
+ > Need adjustments (badges, examples, tutorials)? Open an issue or contribute.