@gl-life/gl-life-database 1.0.0 → 1.1.1
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/API.md +450 -1
- package/README.md +173 -3
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +21 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cache/index.d.ts +0 -4
- package/dist/cache/index.d.ts.map +0 -1
- package/dist/cache/invalidation.d.ts +0 -156
- package/dist/cache/invalidation.d.ts.map +0 -1
- package/dist/cache/kv-cache.d.ts +0 -79
- package/dist/cache/kv-cache.d.ts.map +0 -1
- package/dist/cache/memory-cache.d.ts +0 -68
- package/dist/cache/memory-cache.d.ts.map +0 -1
- package/dist/cloudforge/d1-adapter.d.ts +0 -67
- package/dist/cloudforge/d1-adapter.d.ts.map +0 -1
- package/dist/cloudforge/do-storage.d.ts +0 -51
- package/dist/cloudforge/do-storage.d.ts.map +0 -1
- package/dist/cloudforge/index.d.ts +0 -4
- package/dist/cloudforge/index.d.ts.map +0 -1
- package/dist/cloudforge/r2-backup.d.ts +0 -38
- package/dist/cloudforge/r2-backup.d.ts.map +0 -1
- package/dist/connection/index.d.ts +0 -2
- package/dist/connection/index.d.ts.map +0 -1
- package/dist/connection/manager.d.ts +0 -54
- package/dist/connection/manager.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/migration/index.d.ts +0 -4
- package/dist/migration/index.d.ts.map +0 -1
- package/dist/migration/loader.d.ts +0 -88
- package/dist/migration/loader.d.ts.map +0 -1
- package/dist/migration/runner.d.ts +0 -91
- package/dist/migration/runner.d.ts.map +0 -1
- package/dist/migration/seeder.d.ts +0 -95
- package/dist/migration/seeder.d.ts.map +0 -1
- package/dist/query/builder.d.ts +0 -47
- package/dist/query/builder.d.ts.map +0 -1
- package/dist/query/index.d.ts +0 -3
- package/dist/query/index.d.ts.map +0 -1
- package/dist/query/raw.d.ts +0 -92
- package/dist/query/raw.d.ts.map +0 -1
- package/dist/tenant/context.d.ts +0 -52
- package/dist/tenant/context.d.ts.map +0 -1
- package/dist/tenant/index.d.ts +0 -4
- package/dist/tenant/index.d.ts.map +0 -1
- package/dist/tenant/query-wrapper.d.ts +0 -96
- package/dist/tenant/query-wrapper.d.ts.map +0 -1
- package/dist/tenant/schema-manager.d.ts +0 -185
- package/dist/tenant/schema-manager.d.ts.map +0 -1
- package/dist/transaction/index.d.ts +0 -2
- package/dist/transaction/index.d.ts.map +0 -1
- package/dist/transaction/transaction.d.ts +0 -51
- package/dist/transaction/transaction.d.ts.map +0 -1
- package/dist/types/cache.d.ts +0 -214
- package/dist/types/cache.d.ts.map +0 -1
- package/dist/types/cloudforge.d.ts +0 -753
- package/dist/types/cloudforge.d.ts.map +0 -1
- package/dist/types/connection.d.ts +0 -91
- package/dist/types/connection.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -10
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/migration.d.ts +0 -225
- package/dist/types/migration.d.ts.map +0 -1
- package/dist/types/plugin.d.ts +0 -432
- package/dist/types/plugin.d.ts.map +0 -1
- package/dist/types/query-builder.d.ts +0 -217
- package/dist/types/query-builder.d.ts.map +0 -1
- package/dist/types/seed.d.ts +0 -187
- package/dist/types/seed.d.ts.map +0 -1
- package/dist/types/tenant.d.ts +0 -140
- package/dist/types/tenant.d.ts.map +0 -1
- package/dist/types/transaction.d.ts +0 -144
- package/dist/types/transaction.d.ts.map +0 -1
package/API.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @gl-life/gl-life-database API Reference
|
|
2
2
|
|
|
3
|
-
**Version**: 1.
|
|
3
|
+
**Version**: 1.1.1
|
|
4
4
|
**Package**: `@gl-life/gl-life-database`
|
|
5
5
|
**License**: Apache-2.0
|
|
6
6
|
**Homepage**: https://gl.life
|
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
- [Core Types](#core-types)
|
|
11
11
|
- [Connection Management](#connection-management)
|
|
12
|
+
- [Enterprise Database Support](#enterprise-database-support)
|
|
12
13
|
- [Query Builder](#query-builder)
|
|
13
14
|
- [Transactions](#transactions)
|
|
14
15
|
- [Multi-Tenancy](#multi-tenancy)
|
|
15
16
|
- [Caching](#caching)
|
|
16
17
|
- [Migrations](#migrations)
|
|
18
|
+
- [Flex Table System](#flex-table-system)
|
|
17
19
|
- [CloudForge Adapters](#cloudforge-adapters)
|
|
18
20
|
- [Error Handling](#error-handling)
|
|
19
21
|
- [Usage Patterns](#usage-patterns)
|
|
@@ -137,6 +139,205 @@ Returns an available connection from the pool.
|
|
|
137
139
|
|
|
138
140
|
---
|
|
139
141
|
|
|
142
|
+
## Enterprise Database Support
|
|
143
|
+
|
|
144
|
+
Full support for enterprise databases with bring-your-own-database (BYOD) deployments.
|
|
145
|
+
|
|
146
|
+
### Supported Databases
|
|
147
|
+
|
|
148
|
+
#### SQL Server (Microsoft)
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
interface SQLServerConfig {
|
|
152
|
+
type: 'sqlserver';
|
|
153
|
+
host: string;
|
|
154
|
+
port?: number; // Default: 1433
|
|
155
|
+
database: string;
|
|
156
|
+
username: string;
|
|
157
|
+
password: string;
|
|
158
|
+
options?: {
|
|
159
|
+
encrypt?: boolean; // Required for Azure SQL
|
|
160
|
+
trustServerCertificate?: boolean;
|
|
161
|
+
connectionTimeout?: number;
|
|
162
|
+
requestTimeout?: number;
|
|
163
|
+
pool?: {
|
|
164
|
+
max?: number;
|
|
165
|
+
min?: number;
|
|
166
|
+
idleTimeoutMillis?: number;
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Example**:
|
|
173
|
+
```typescript
|
|
174
|
+
const connection = await manager.connect({
|
|
175
|
+
type: 'sqlserver',
|
|
176
|
+
host: 'sql-server.database.windows.net',
|
|
177
|
+
port: 1433,
|
|
178
|
+
database: 'production',
|
|
179
|
+
username: 'admin',
|
|
180
|
+
password: process.env.DB_PASSWORD,
|
|
181
|
+
options: {
|
|
182
|
+
encrypt: true,
|
|
183
|
+
trustServerCertificate: false,
|
|
184
|
+
connectionTimeout: 30000,
|
|
185
|
+
pool: {
|
|
186
|
+
max: 20,
|
|
187
|
+
min: 5,
|
|
188
|
+
idleTimeoutMillis: 30000
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### PostgreSQL
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
interface PostgreSQLConfig {
|
|
198
|
+
type: 'postgres';
|
|
199
|
+
host: string;
|
|
200
|
+
port?: number; // Default: 5432
|
|
201
|
+
database: string;
|
|
202
|
+
username: string;
|
|
203
|
+
password: string;
|
|
204
|
+
options?: {
|
|
205
|
+
ssl?: boolean | object;
|
|
206
|
+
poolSize?: number;
|
|
207
|
+
idleTimeoutMillis?: number;
|
|
208
|
+
connectionTimeoutMillis?: number;
|
|
209
|
+
schema?: string;
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Example**:
|
|
215
|
+
```typescript
|
|
216
|
+
const connection = await manager.connect({
|
|
217
|
+
type: 'postgres',
|
|
218
|
+
host: 'postgres-cluster.company.com',
|
|
219
|
+
port: 5432,
|
|
220
|
+
database: 'production',
|
|
221
|
+
username: 'dbuser',
|
|
222
|
+
password: process.env.DB_PASSWORD,
|
|
223
|
+
options: {
|
|
224
|
+
ssl: { rejectUnauthorized: false },
|
|
225
|
+
poolSize: 20,
|
|
226
|
+
schema: 'public'
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### MySQL / MariaDB
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
interface MySQLConfig {
|
|
235
|
+
type: 'mysql';
|
|
236
|
+
host: string;
|
|
237
|
+
port?: number; // Default: 3306
|
|
238
|
+
database: string;
|
|
239
|
+
username: string;
|
|
240
|
+
password: string;
|
|
241
|
+
options?: {
|
|
242
|
+
connectionLimit?: number;
|
|
243
|
+
charset?: string;
|
|
244
|
+
timezone?: string;
|
|
245
|
+
ssl?: boolean | object;
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Example**:
|
|
251
|
+
```typescript
|
|
252
|
+
const connection = await manager.connect({
|
|
253
|
+
type: 'mysql',
|
|
254
|
+
host: 'mysql-primary.internal.com',
|
|
255
|
+
port: 3306,
|
|
256
|
+
database: 'production',
|
|
257
|
+
username: 'app_user',
|
|
258
|
+
password: process.env.DB_PASSWORD,
|
|
259
|
+
options: {
|
|
260
|
+
connectionLimit: 10,
|
|
261
|
+
charset: 'utf8mb4',
|
|
262
|
+
timezone: 'Z'
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### Oracle Database
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
interface OracleConfig {
|
|
271
|
+
type: 'oracle';
|
|
272
|
+
host: string;
|
|
273
|
+
port?: number; // Default: 1521
|
|
274
|
+
database: string; // Service name
|
|
275
|
+
username: string;
|
|
276
|
+
password: string;
|
|
277
|
+
options?: {
|
|
278
|
+
poolMax?: number;
|
|
279
|
+
poolMin?: number;
|
|
280
|
+
poolIncrement?: number;
|
|
281
|
+
poolTimeout?: number;
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**Example**:
|
|
287
|
+
```typescript
|
|
288
|
+
const connection = await manager.connect({
|
|
289
|
+
type: 'oracle',
|
|
290
|
+
host: 'oracle-db.company.com',
|
|
291
|
+
port: 1521,
|
|
292
|
+
database: 'ORCL',
|
|
293
|
+
username: 'system',
|
|
294
|
+
password: process.env.DB_PASSWORD,
|
|
295
|
+
options: {
|
|
296
|
+
poolMax: 10,
|
|
297
|
+
poolMin: 2,
|
|
298
|
+
poolIncrement: 1
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Enterprise Features
|
|
304
|
+
|
|
305
|
+
All features work identically across all database engines:
|
|
306
|
+
|
|
307
|
+
- ✅ **Flex Table System** - Dynamic schemas work on any database
|
|
308
|
+
- ✅ **Multi-Tenancy** - Row-Level Security on all engines
|
|
309
|
+
- ✅ **Caching** - Cache layer independent of database type
|
|
310
|
+
- ✅ **Migrations** - Version control for any database
|
|
311
|
+
- ✅ **Transactions** - ACID compliance on all supported databases
|
|
312
|
+
- ✅ **Connection Pooling** - Automatic connection management
|
|
313
|
+
|
|
314
|
+
### Hybrid Deployments
|
|
315
|
+
|
|
316
|
+
Mix cloud and on-premise databases in the same application:
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
// Cloud database for non-sensitive data
|
|
320
|
+
const cloudConn = await manager.connect({
|
|
321
|
+
type: 'd1',
|
|
322
|
+
binding: env.DB
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Enterprise database for sensitive data
|
|
326
|
+
const enterpriseConn = await manager.connect({
|
|
327
|
+
type: 'sqlserver',
|
|
328
|
+
host: 'on-premise-sql.company.local',
|
|
329
|
+
database: 'customer_data',
|
|
330
|
+
username: 'app_user',
|
|
331
|
+
password: process.env.DB_PASSWORD
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// Use both in same application
|
|
335
|
+
const products = await cloudConn.execute('SELECT * FROM products');
|
|
336
|
+
const customers = await enterpriseConn.execute('SELECT * FROM customers WHERE tenant_id = ?', [tenantId]);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
140
341
|
## Query Builder
|
|
141
342
|
|
|
142
343
|
### TypeSafeQueryBuilder
|
|
@@ -805,6 +1006,254 @@ Rollback migrations.
|
|
|
805
1006
|
|
|
806
1007
|
---
|
|
807
1008
|
|
|
1009
|
+
## Flex Table System
|
|
1010
|
+
|
|
1011
|
+
The Flex Table System provides dynamic schema capabilities without ALTER TABLE operations. From `gl-life-data`.
|
|
1012
|
+
|
|
1013
|
+
### MetaDataService
|
|
1014
|
+
|
|
1015
|
+
Manages metadata mappings between logical and physical field names.
|
|
1016
|
+
|
|
1017
|
+
#### Constructor
|
|
1018
|
+
|
|
1019
|
+
```typescript
|
|
1020
|
+
class MetaDataService {
|
|
1021
|
+
constructor(dbPath: string);
|
|
1022
|
+
}
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
**Parameters**:
|
|
1026
|
+
- `dbPath: string` - Path to SQLite database containing metadata
|
|
1027
|
+
|
|
1028
|
+
#### Methods
|
|
1029
|
+
|
|
1030
|
+
##### createMapping()
|
|
1031
|
+
|
|
1032
|
+
```typescript
|
|
1033
|
+
createMapping(input: CreateMappingInput): Promise<MetadataSelect>
|
|
1034
|
+
```
|
|
1035
|
+
|
|
1036
|
+
Creates a new metadata mapping, automatically assigning the next available physical field.
|
|
1037
|
+
|
|
1038
|
+
**Parameters**:
|
|
1039
|
+
```typescript
|
|
1040
|
+
interface CreateMappingInput {
|
|
1041
|
+
tableName: string;
|
|
1042
|
+
logicalFieldName: string;
|
|
1043
|
+
dataType: 'string' | 'int' | 'decimal' | 'date' | 'boolean' | 'text' | 'datetime' | 'float' | 'bigint' | 'uuid';
|
|
1044
|
+
isRequired?: boolean;
|
|
1045
|
+
defaultValue?: string | null;
|
|
1046
|
+
validationRules?: ValidationRules;
|
|
1047
|
+
description?: string;
|
|
1048
|
+
displayOrder?: number;
|
|
1049
|
+
isIndexed?: boolean;
|
|
1050
|
+
isUnique?: boolean;
|
|
1051
|
+
foreignKeyRef?: string | null;
|
|
1052
|
+
createdBy?: string;
|
|
1053
|
+
}
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
**Returns**: `Promise<MetadataSelect>` - Created metadata entry
|
|
1057
|
+
|
|
1058
|
+
**Example**:
|
|
1059
|
+
```typescript
|
|
1060
|
+
const metaDataService = new MetaDataService('./database.db');
|
|
1061
|
+
|
|
1062
|
+
await metaDataService.createMapping({
|
|
1063
|
+
tableName: 'products',
|
|
1064
|
+
logicalFieldName: 'productName',
|
|
1065
|
+
dataType: 'string', // Will map to string_field_1
|
|
1066
|
+
isRequired: true,
|
|
1067
|
+
description: 'Product name'
|
|
1068
|
+
});
|
|
1069
|
+
```
|
|
1070
|
+
|
|
1071
|
+
##### getMappingByLogicalField()
|
|
1072
|
+
|
|
1073
|
+
```typescript
|
|
1074
|
+
getMappingByLogicalField(tableName: string, logicalFieldName: string): MetadataSelect | null
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
**Parameters**:
|
|
1078
|
+
- `tableName: string` - Entity table name
|
|
1079
|
+
- `logicalFieldName: string` - Logical field name to look up
|
|
1080
|
+
|
|
1081
|
+
**Returns**: `MetadataSelect | null` - Metadata entry or null if not found
|
|
1082
|
+
|
|
1083
|
+
##### getTableMappings()
|
|
1084
|
+
|
|
1085
|
+
```typescript
|
|
1086
|
+
getTableMappings(tableName: string): MetadataSelect[]
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
**Parameters**:
|
|
1090
|
+
- `tableName: string` - Entity table name
|
|
1091
|
+
|
|
1092
|
+
**Returns**: `MetadataSelect[]` - All metadata mappings for the table
|
|
1093
|
+
|
|
1094
|
+
### Using Flex Tables with TypeSafeQueryBuilder
|
|
1095
|
+
|
|
1096
|
+
```typescript
|
|
1097
|
+
import { TypeSafeQueryBuilder, Logger } from '@gl-life/gl-life-database';
|
|
1098
|
+
import { MetaDataService } from 'gl-life-data';
|
|
1099
|
+
|
|
1100
|
+
const logger = new Logger({ level: 'info' });
|
|
1101
|
+
const metaDataService = new MetaDataService('./database.db');
|
|
1102
|
+
|
|
1103
|
+
// Create mappings
|
|
1104
|
+
await metaDataService.createMapping({
|
|
1105
|
+
tableName: 'products',
|
|
1106
|
+
logicalFieldName: 'name',
|
|
1107
|
+
dataType: 'string' // Maps to string_field_1
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
await metaDataService.createMapping({
|
|
1111
|
+
tableName: 'products',
|
|
1112
|
+
logicalFieldName: 'price',
|
|
1113
|
+
dataType: 'decimal' // Maps to decimal_field_1
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
// Query using logical field names
|
|
1117
|
+
const builder = new TypeSafeQueryBuilder('products', metaDataService, logger);
|
|
1118
|
+
const sql = builder
|
|
1119
|
+
.select(['name', 'price']) // Logical names
|
|
1120
|
+
.where('price', '>', 100)
|
|
1121
|
+
.toSQL();
|
|
1122
|
+
|
|
1123
|
+
// Generates: SELECT string_field_1, decimal_field_1
|
|
1124
|
+
// FROM flex_table
|
|
1125
|
+
// WHERE decimal_field_1 > ?
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
### Flex Table Schema
|
|
1129
|
+
|
|
1130
|
+
Universal schema for all Flex tables:
|
|
1131
|
+
|
|
1132
|
+
```sql
|
|
1133
|
+
CREATE TABLE flex_table (
|
|
1134
|
+
id TEXT PRIMARY KEY,
|
|
1135
|
+
tenant_id TEXT,
|
|
1136
|
+
|
|
1137
|
+
-- String fields (10 slots)
|
|
1138
|
+
string_field_1 TEXT,
|
|
1139
|
+
string_field_2 TEXT,
|
|
1140
|
+
string_field_3 TEXT,
|
|
1141
|
+
...
|
|
1142
|
+
string_field_10 TEXT,
|
|
1143
|
+
|
|
1144
|
+
-- Integer fields (10 slots)
|
|
1145
|
+
int_field_1 INTEGER,
|
|
1146
|
+
int_field_2 INTEGER,
|
|
1147
|
+
...
|
|
1148
|
+
int_field_10 INTEGER,
|
|
1149
|
+
|
|
1150
|
+
-- Decimal fields (10 slots)
|
|
1151
|
+
decimal_field_1 REAL,
|
|
1152
|
+
...
|
|
1153
|
+
decimal_field_10 REAL,
|
|
1154
|
+
|
|
1155
|
+
-- Date fields (10 slots)
|
|
1156
|
+
date_field_1 TEXT,
|
|
1157
|
+
...
|
|
1158
|
+
date_field_10 TEXT,
|
|
1159
|
+
|
|
1160
|
+
-- Boolean fields (10 slots)
|
|
1161
|
+
boolean_field_1 INTEGER,
|
|
1162
|
+
...
|
|
1163
|
+
boolean_field_10 INTEGER,
|
|
1164
|
+
|
|
1165
|
+
-- Text fields (10 slots)
|
|
1166
|
+
text_field_1 TEXT,
|
|
1167
|
+
...
|
|
1168
|
+
text_field_10 TEXT,
|
|
1169
|
+
|
|
1170
|
+
-- Additional field types (10 slots each):
|
|
1171
|
+
-- datetime_field_1 through datetime_field_10
|
|
1172
|
+
-- float_field_1 through float_field_10
|
|
1173
|
+
-- bigint_field_1 through bigint_field_10
|
|
1174
|
+
-- uuid_field_1 through uuid_field_10
|
|
1175
|
+
|
|
1176
|
+
-- Overflow for extra fields
|
|
1177
|
+
json_data TEXT,
|
|
1178
|
+
|
|
1179
|
+
-- Timestamps
|
|
1180
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
1181
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
1182
|
+
);
|
|
1183
|
+
```
|
|
1184
|
+
|
|
1185
|
+
### Metadata Table Schema
|
|
1186
|
+
|
|
1187
|
+
```sql
|
|
1188
|
+
CREATE TABLE metadata (
|
|
1189
|
+
id TEXT PRIMARY KEY,
|
|
1190
|
+
tenant_id TEXT, -- NULL for shared, or specific tenant ID
|
|
1191
|
+
table_name TEXT NOT NULL,
|
|
1192
|
+
logical_field_name TEXT NOT NULL,
|
|
1193
|
+
physical_column_name TEXT NOT NULL,
|
|
1194
|
+
data_type TEXT NOT NULL,
|
|
1195
|
+
is_required INTEGER NOT NULL DEFAULT 0,
|
|
1196
|
+
default_value TEXT,
|
|
1197
|
+
validation_rules TEXT, -- JSON
|
|
1198
|
+
description TEXT,
|
|
1199
|
+
display_order INTEGER,
|
|
1200
|
+
is_indexed INTEGER NOT NULL DEFAULT 0,
|
|
1201
|
+
is_unique INTEGER NOT NULL DEFAULT 0,
|
|
1202
|
+
foreign_key_ref TEXT,
|
|
1203
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
1204
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
1205
|
+
created_by TEXT,
|
|
1206
|
+
updated_by TEXT,
|
|
1207
|
+
UNIQUE(tenant_id, table_name, logical_field_name),
|
|
1208
|
+
UNIQUE(tenant_id, table_name, physical_column_name)
|
|
1209
|
+
);
|
|
1210
|
+
```
|
|
1211
|
+
|
|
1212
|
+
### Flex Tables + Multi-Tenancy
|
|
1213
|
+
|
|
1214
|
+
Combine Flex tables with multi-tenancy for per-tenant custom fields:
|
|
1215
|
+
|
|
1216
|
+
```typescript
|
|
1217
|
+
// Shared field for all tenants
|
|
1218
|
+
await metaDataService.createMapping({
|
|
1219
|
+
tableName: 'products',
|
|
1220
|
+
logicalFieldName: 'name',
|
|
1221
|
+
dataType: 'string'
|
|
1222
|
+
});
|
|
1223
|
+
|
|
1224
|
+
// Tenant-specific field (Tenant A only)
|
|
1225
|
+
await connection.execute(`
|
|
1226
|
+
INSERT INTO metadata (
|
|
1227
|
+
id, tenant_id, table_name, logical_field_name,
|
|
1228
|
+
physical_column_name, data_type
|
|
1229
|
+
) VALUES (?, ?, ?, ?, ?, ?)
|
|
1230
|
+
`, [
|
|
1231
|
+
'tenantA_products_warranty',
|
|
1232
|
+
'tenant-A',
|
|
1233
|
+
'products',
|
|
1234
|
+
'warrantyMonths',
|
|
1235
|
+
'int_field_1', // Tenant A uses int_field_1
|
|
1236
|
+
'int'
|
|
1237
|
+
]);
|
|
1238
|
+
|
|
1239
|
+
// Tenant-specific field (Tenant B only)
|
|
1240
|
+
await connection.execute(`
|
|
1241
|
+
INSERT INTO metadata (
|
|
1242
|
+
id, tenant_id, table_name, logical_field_name,
|
|
1243
|
+
physical_column_name, data_type
|
|
1244
|
+
) VALUES (?, ?, ?, ?, ?, ?)
|
|
1245
|
+
`, [
|
|
1246
|
+
'tenantB_products_size',
|
|
1247
|
+
'tenant-B',
|
|
1248
|
+
'products',
|
|
1249
|
+
'size',
|
|
1250
|
+
'string_field_2', // Tenant B uses string_field_2
|
|
1251
|
+
'string'
|
|
1252
|
+
]);
|
|
1253
|
+
```
|
|
1254
|
+
|
|
1255
|
+
---
|
|
1256
|
+
|
|
808
1257
|
## CloudForge Adapters
|
|
809
1258
|
|
|
810
1259
|
### D1Adapter
|
package/README.md
CHANGED
|
@@ -4,15 +4,17 @@ Enhanced gl-life-data wrapper with CloudForge features - Type-safe database abst
|
|
|
4
4
|
|
|
5
5
|
## About
|
|
6
6
|
|
|
7
|
-
`@gl-life/gl-life-database` is a comprehensive database abstraction layer that extends gl-life-data with enterprise features for multi-tenant SaaS applications
|
|
7
|
+
`@gl-life/gl-life-database` is a comprehensive database abstraction layer that extends gl-life-data with enterprise features for multi-tenant SaaS applications. Built with TypeScript and designed for type safety, it supports both cloud-native deployments (Cloudflare Workers) and enterprise bring-your-own-database (BYOD) scenarios with SQL Server, MySQL, PostgreSQL, Oracle, and more. Perfect for pro users who want to leverage their existing infrastructure while gaining powerful features like Flex tables, multi-tenancy, and intelligent caching.
|
|
8
8
|
|
|
9
9
|
### Key Features
|
|
10
10
|
|
|
11
11
|
- 🗄️ **Type-Safe Query Builder** - Fluent API with full TypeScript support extending gl-life-data
|
|
12
|
+
- 🔀 **Flex Table System** - Dynamic schema without ALTER TABLE, metadata-driven field mapping
|
|
13
|
+
- 🏢 **Enterprise Database Support** - Full support for SQL Server, MySQL, PostgreSQL, Oracle, and more
|
|
12
14
|
- 👥 **Multi-Tenancy** - Built-in tenant isolation with Row-Level Security (RLS)
|
|
13
|
-
- ⚡ **Caching
|
|
15
|
+
- ⚡ **Flexible Caching** - Memory cache, Redis, or Cloudflare KV backends
|
|
14
16
|
- 🔄 **Migrations** - Version-controlled database migrations with rollback support
|
|
15
|
-
- ☁️ **
|
|
17
|
+
- ☁️ **Cloud + On-Premise** - Deploy on Cloudflare Workers OR bring your own infrastructure
|
|
16
18
|
- 🔒 **SQL Injection Protection** - Parameterized queries with automatic sanitization
|
|
17
19
|
- 🧪 **Well-Tested** - >95% test coverage with comprehensive security tests
|
|
18
20
|
- 📊 **Performance Optimized** - Query building overhead <1ms (P95)
|
|
@@ -180,6 +182,174 @@ export default {
|
|
|
180
182
|
};
|
|
181
183
|
```
|
|
182
184
|
|
|
185
|
+
### Enterprise Database Support (BYOD - Bring Your Own Database)
|
|
186
|
+
|
|
187
|
+
Pro users can connect to their existing enterprise databases instead of using Cloudflare Workers. Full support for:
|
|
188
|
+
|
|
189
|
+
#### SQL Server (Microsoft)
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import { ConnectionManager, Logger } from '@gl-life/gl-life-database';
|
|
193
|
+
|
|
194
|
+
const logger = new Logger({ level: 'info' });
|
|
195
|
+
const manager = new ConnectionManager(logger);
|
|
196
|
+
|
|
197
|
+
const connection = await manager.connect({
|
|
198
|
+
type: 'sqlserver',
|
|
199
|
+
host: 'your-sql-server.database.windows.net',
|
|
200
|
+
port: 1433,
|
|
201
|
+
database: 'production_db',
|
|
202
|
+
username: 'admin',
|
|
203
|
+
password: process.env.DB_PASSWORD,
|
|
204
|
+
options: {
|
|
205
|
+
encrypt: true, // Azure SQL requires encryption
|
|
206
|
+
trustServerCertificate: false,
|
|
207
|
+
connectionTimeout: 30000
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// All features work identically: Flex tables, multi-tenancy, caching, migrations
|
|
212
|
+
const builder = new TypeSafeQueryBuilder('users', metaDataService, logger);
|
|
213
|
+
// ... same as any other database
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### PostgreSQL
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const connection = await manager.connect({
|
|
220
|
+
type: 'postgres',
|
|
221
|
+
host: 'your-postgres-instance.com',
|
|
222
|
+
port: 5432,
|
|
223
|
+
database: 'production_db',
|
|
224
|
+
username: 'dbuser',
|
|
225
|
+
password: process.env.DB_PASSWORD,
|
|
226
|
+
options: {
|
|
227
|
+
ssl: { rejectUnauthorized: false },
|
|
228
|
+
poolSize: 20,
|
|
229
|
+
idleTimeoutMillis: 30000
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### MySQL / MariaDB
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
const connection = await manager.connect({
|
|
238
|
+
type: 'mysql',
|
|
239
|
+
host: 'mysql-cluster.internal.com',
|
|
240
|
+
port: 3306,
|
|
241
|
+
database: 'production_db',
|
|
242
|
+
username: 'dbuser',
|
|
243
|
+
password: process.env.DB_PASSWORD,
|
|
244
|
+
options: {
|
|
245
|
+
connectionLimit: 10,
|
|
246
|
+
charset: 'utf8mb4',
|
|
247
|
+
timezone: 'Z'
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### Oracle Database
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
const connection = await manager.connect({
|
|
256
|
+
type: 'oracle',
|
|
257
|
+
host: 'oracle-enterprise.company.com',
|
|
258
|
+
port: 1521,
|
|
259
|
+
database: 'ORCL', // Service name
|
|
260
|
+
username: 'system',
|
|
261
|
+
password: process.env.DB_PASSWORD,
|
|
262
|
+
options: {
|
|
263
|
+
poolMax: 10,
|
|
264
|
+
poolMin: 2,
|
|
265
|
+
poolIncrement: 1
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### SQLite (Development/Testing)
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
const connection = await manager.connect({
|
|
274
|
+
type: 'sqlite',
|
|
275
|
+
filename: './dev.db' // Or ':memory:' for in-memory
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Key Benefits for Enterprise Users:**
|
|
280
|
+
- ✅ **Use Existing Infrastructure** - No migration required, connect to your current databases
|
|
281
|
+
- ✅ **All Features Work** - Flex tables, multi-tenancy, caching, migrations work on any database
|
|
282
|
+
- ✅ **Security Compliant** - Keep data on-premise, meet regulatory requirements
|
|
283
|
+
- ✅ **Cost Control** - Use your existing database licenses and hardware
|
|
284
|
+
- ✅ **Hybrid Deployments** - Mix cloud (D1) and on-premise databases in same application
|
|
285
|
+
- ✅ **Connection Pooling** - Built-in connection management for all enterprise databases
|
|
286
|
+
|
|
287
|
+
### Flex Table System
|
|
288
|
+
|
|
289
|
+
The Flex Table System is a powerful feature from gl-life-data that provides dynamic schema capabilities without ALTER TABLE operations. Perfect for multi-tenant SaaS applications where each tenant needs custom fields.
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { TypeSafeQueryBuilder, Logger } from '@gl-life/gl-life-database';
|
|
293
|
+
import { MetaDataService } from 'gl-life-data';
|
|
294
|
+
|
|
295
|
+
// Initialize metadata service
|
|
296
|
+
const metaDataService = new MetaDataService('./database.db');
|
|
297
|
+
|
|
298
|
+
// Create metadata mapping: logical field → physical column
|
|
299
|
+
await metaDataService.createMapping({
|
|
300
|
+
tableName: 'products',
|
|
301
|
+
logicalFieldName: 'productName',
|
|
302
|
+
dataType: 'string', // Maps to string_field_1
|
|
303
|
+
isRequired: true,
|
|
304
|
+
description: 'Product name'
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
await metaDataService.createMapping({
|
|
308
|
+
tableName: 'products',
|
|
309
|
+
logicalFieldName: 'price',
|
|
310
|
+
dataType: 'decimal', // Maps to decimal_field_1
|
|
311
|
+
isRequired: true
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Query using logical field names
|
|
315
|
+
const builder = new TypeSafeQueryBuilder('products', metaDataService, logger);
|
|
316
|
+
const sql = builder
|
|
317
|
+
.select(['productName', 'price']) // Uses logical names
|
|
318
|
+
.where('price', '>', 100)
|
|
319
|
+
.toSQL();
|
|
320
|
+
// Generates: SELECT string_field_1, decimal_field_1 FROM flex_table WHERE decimal_field_1 > ?
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Key Benefits:**
|
|
324
|
+
- **Universal Schema**: All tables use same physical structure (string_field_1, int_field_1, etc.)
|
|
325
|
+
- **No ALTER TABLE**: Add fields by creating metadata entries
|
|
326
|
+
- **Type Safety**: 10 fields per data type (string, int, decimal, date, boolean, text, datetime, float, bigint, uuid)
|
|
327
|
+
- **Multi-Tenant Ready**: Different tenants can have different custom fields
|
|
328
|
+
- **Query Transparency**: Use logical field names, metadata handles physical mapping
|
|
329
|
+
|
|
330
|
+
**Flex Table Schema:**
|
|
331
|
+
```sql
|
|
332
|
+
CREATE TABLE flex_table (
|
|
333
|
+
id TEXT PRIMARY KEY,
|
|
334
|
+
tenant_id TEXT,
|
|
335
|
+
-- 10 string fields
|
|
336
|
+
string_field_1 TEXT,
|
|
337
|
+
string_field_2 TEXT,
|
|
338
|
+
...
|
|
339
|
+
string_field_10 TEXT,
|
|
340
|
+
-- 10 int fields
|
|
341
|
+
int_field_1 INTEGER,
|
|
342
|
+
...
|
|
343
|
+
int_field_10 INTEGER,
|
|
344
|
+
-- Plus: decimal, date, boolean, text, datetime, float, bigint, uuid fields
|
|
345
|
+
json_data TEXT, -- Overflow for extra fields
|
|
346
|
+
created_at TEXT,
|
|
347
|
+
updated_at TEXT
|
|
348
|
+
);
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
See [examples/06-flex-tables.ts](./examples/06-flex-tables.ts) and [examples/07-flex-with-multi-tenancy.ts](./examples/07-flex-with-multi-tenancy.ts) for complete workflows.
|
|
352
|
+
|
|
183
353
|
## Usage
|
|
184
354
|
|
|
185
355
|
### Query Builder
|