outlet-orm 7.0.0 → 9.0.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/README.md +130 -2
- package/docs/skills/outlet-orm/AI.md +452 -102
- package/docs/skills/outlet-orm/API.md +108 -0
- package/docs/skills/outlet-orm/QUERIES.md +64 -0
- package/docs/skills/outlet-orm/SEEDS.md +47 -0
- package/docs/skills/outlet-orm/SKILL.md +15 -7
- package/package.json +1 -1
- package/src/AI/AIPromptEnhancer.js +170 -0
- package/src/AI/AIQueryBuilder.js +234 -0
- package/src/AI/AIQueryOptimizer.js +185 -0
- package/src/AI/AISeeder.js +181 -0
- package/src/AI/AiBridgeManager.js +287 -0
- package/src/AI/Builders/TextBuilder.js +170 -0
- package/src/AI/Contracts/AudioProviderContract.js +29 -0
- package/src/AI/Contracts/ChatProviderContract.js +38 -0
- package/src/AI/Contracts/EmbeddingsProviderContract.js +19 -0
- package/src/AI/Contracts/ImageProviderContract.js +19 -0
- package/src/AI/Contracts/ModelsProviderContract.js +26 -0
- package/src/AI/Contracts/ToolContract.js +25 -0
- package/src/AI/Facades/AiBridge.js +79 -0
- package/src/AI/MCPServer.js +113 -0
- package/src/AI/Providers/ClaudeProvider.js +64 -0
- package/src/AI/Providers/CustomOpenAIProvider.js +238 -0
- package/src/AI/Providers/GeminiProvider.js +68 -0
- package/src/AI/Providers/GrokProvider.js +46 -0
- package/src/AI/Providers/MistralProvider.js +21 -0
- package/src/AI/Providers/OllamaProvider.js +249 -0
- package/src/AI/Providers/OllamaTurboProvider.js +32 -0
- package/src/AI/Providers/OnnProvider.js +46 -0
- package/src/AI/Providers/OpenAIProvider.js +471 -0
- package/src/AI/Support/AudioNormalizer.js +37 -0
- package/src/AI/Support/ChatNormalizer.js +42 -0
- package/src/AI/Support/Document.js +77 -0
- package/src/AI/Support/DocumentAttachmentMapper.js +101 -0
- package/src/AI/Support/EmbeddingsNormalizer.js +30 -0
- package/src/AI/Support/Exceptions/ProviderError.js +22 -0
- package/src/AI/Support/FileSecurity.js +56 -0
- package/src/AI/Support/ImageNormalizer.js +62 -0
- package/src/AI/Support/JsonSchemaValidator.js +73 -0
- package/src/AI/Support/Message.js +40 -0
- package/src/AI/Support/StreamChunk.js +45 -0
- package/src/AI/Support/ToolChatRunner.js +160 -0
- package/src/AI/Support/ToolRegistry.js +62 -0
- package/src/AI/Tools/SystemInfoTool.js +25 -0
- package/src/index.js +67 -1
- package/types/index.d.ts +326 -0
|
@@ -515,6 +515,114 @@ const db = new DatabaseConnection({
|
|
|
515
515
|
|
|
516
516
|
---
|
|
517
517
|
|
|
518
|
+
## AiBridgeManager
|
|
519
|
+
|
|
520
|
+
> Since v8.0.0
|
|
521
|
+
|
|
522
|
+
### Constructor
|
|
523
|
+
|
|
524
|
+
```javascript
|
|
525
|
+
const { AiBridgeManager } = require('outlet-orm');
|
|
526
|
+
const ai = new AiBridgeManager(config); // From config/aibridge.js or inline
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### Methods
|
|
530
|
+
|
|
531
|
+
| Method | Returns | Description |
|
|
532
|
+
|--------|---------|-------------|
|
|
533
|
+
|`chat(provider, messages, opts?)`| `{ text, tool_calls, raw }` | Send chat request |
|
|
534
|
+
|`stream(provider, messages, opts?)`| `AsyncGenerator<StreamChunk>` | SSE/NDJSON stream |
|
|
535
|
+
|`streamEvents(provider, messages, opts?)`| `AsyncGenerator<{type, data}>` | Structured stream events |
|
|
536
|
+
|`embeddings(provider, inputs, opts?)`| `{ vectors, usage, raw }` | Generate embeddings |
|
|
537
|
+
|`image(provider, prompt, opts?)`| `{ url, b64_json, raw }` | Generate image |
|
|
538
|
+
|`tts(provider, text, opts?)`| `{ audio, mime }` | Text-to-speech |
|
|
539
|
+
|`stt(provider, filePath, opts?)`| `{ text }` | Speech-to-text |
|
|
540
|
+
|`models(provider)`| `Array<{id, ...}>` | List available models |
|
|
541
|
+
|`model(provider, id)`| `Object` | Get single model info |
|
|
542
|
+
|`text()`| `TextBuilder` | Fluent text builder |
|
|
543
|
+
|`chatWithTools(provider, messages, opts?)`| `{ text, raw }` | Chat with tool calling loop |
|
|
544
|
+
|`registerTool(tool)`| `void` | Register a custom tool |
|
|
545
|
+
|`registerProvider(name, provider)`| `void` | Register a custom provider |
|
|
546
|
+
|`provider(name)`| `Provider` | Get registered provider |
|
|
547
|
+
|`tool(name)`| `ToolContract` | Get registered tool |
|
|
548
|
+
|`tools()`| `Array<ToolContract>` | Get all tools |
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## TextBuilder
|
|
553
|
+
|
|
554
|
+
| Method | Returns | Description |
|
|
555
|
+
|--------|---------|-------------|
|
|
556
|
+
|`.using(provider, model)`| `this` | Set provider and model |
|
|
557
|
+
|`.withPrompt(text, attachments?)`| `this` | Add user message |
|
|
558
|
+
|`.withSystemPrompt(text)`| `this` | Set system prompt |
|
|
559
|
+
|`.withMaxTokens(n)`| `this` | Max tokens limit |
|
|
560
|
+
|`.usingTemperature(t)`| `this` | Temperature (0–2) |
|
|
561
|
+
|`.usingTopP(p)`| `this` | Top-p sampling |
|
|
562
|
+
|`.withApiKey(key)`| `this` | Override API key |
|
|
563
|
+
|`.withEndpoint(url)`| `this` | Override endpoint |
|
|
564
|
+
|`.withBaseUrl(url)`| `this` | Override base URL |
|
|
565
|
+
|`.withAuthHeader(header, prefix?)`| `this` | Override auth header |
|
|
566
|
+
|`.withExtraHeaders(headers)`| `this` | Extra HTTP headers |
|
|
567
|
+
|`.asText()`| `{ text, raw, usage, finish_reason }` | Text response |
|
|
568
|
+
|`.asStream()`| `AsyncGenerator<StreamChunk>` | Streaming response |
|
|
569
|
+
|`.asRaw()`| `Object` | Raw provider response |
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
## AIQueryBuilder
|
|
574
|
+
|
|
575
|
+
| Method | Returns | Description |
|
|
576
|
+
|--------|---------|-------------|
|
|
577
|
+
|`using(provider, model)`| `this` | Set LLM provider |
|
|
578
|
+
|`safeMode(bool)`| `this` | Restrict to SELECT/WITH |
|
|
579
|
+
|`query(question)`| `{ sql, params, results, explanation }` | NL → SQL + execute |
|
|
580
|
+
|`toSql(question)`| `{ sql, params, explanation }` | NL → SQL only |
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## AISeeder
|
|
585
|
+
|
|
586
|
+
| Method | Returns | Description |
|
|
587
|
+
|--------|---------|-------------|
|
|
588
|
+
|`using(provider, model)`| `this` | Set LLM provider |
|
|
589
|
+
|`seed(table, count, ctx)`| `{ records, inserted }` | Generate + insert |
|
|
590
|
+
|`generate(table, count, ctx)`| `Array<Object>` | Preview only |
|
|
591
|
+
|
|
592
|
+
---
|
|
593
|
+
|
|
594
|
+
## AIQueryOptimizer
|
|
595
|
+
|
|
596
|
+
| Method | Returns | Description |
|
|
597
|
+
|--------|---------|-------------|
|
|
598
|
+
|`using(provider, model)`| `this` | Set LLM provider |
|
|
599
|
+
|`optimize(sql)`| `{ original, optimized, suggestions, indexes, explanation }` | Analyze + rewrite |
|
|
600
|
+
|`explain(sql)`| `{ plan, analysis }` | EXPLAIN + LLM analysis |
|
|
601
|
+
|
|
602
|
+
---
|
|
603
|
+
|
|
604
|
+
## AIPromptEnhancer
|
|
605
|
+
|
|
606
|
+
| Method | Returns | Description |
|
|
607
|
+
|--------|---------|-------------|
|
|
608
|
+
|`using(provider, model)`| `this` | Set LLM provider |
|
|
609
|
+
|`generateSchema(description)`| `{ tables, relations, seedHints }` | Schema from description |
|
|
610
|
+
|`generateModelCode(table, schema, rels)`| `string` | Model class code |
|
|
611
|
+
|`generateMigrationCode(table, schema)`| `string` | Migration class code |
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
## AISafetyGuardrails (Static)
|
|
616
|
+
|
|
617
|
+
| Method | Returns | Description |
|
|
618
|
+
|--------|---------|-------------|
|
|
619
|
+
|`detectAgent()`| `{ detected, agentName }` | Detect AI agent |
|
|
620
|
+
|`isDestructiveCommand(cmd)`| `boolean` | Check if destructive |
|
|
621
|
+
|`validateDestructiveAction(cmd, flags)`| `{ allowed, message }` | Validate with consent |
|
|
622
|
+
|`CONSENT_ENV_VAR`| `string` | Consent env var name |
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
518
626
|
## References
|
|
519
627
|
|
|
520
628
|
- <https://github.com/omgbwa-yasse/outlet-orm>
|
|
@@ -300,6 +300,70 @@ const native = await db.execute(
|
|
|
300
300
|
|
|
301
301
|
---
|
|
302
302
|
|
|
303
|
+
## AI Query Builder — Natural Language to SQL
|
|
304
|
+
|
|
305
|
+
> Since v8.0.0
|
|
306
|
+
|
|
307
|
+
Convert natural language into SQL queries using any LLM provider via AiBridge.
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
const { AiBridgeManager, AIQueryBuilder, DatabaseConnection } = require('outlet-orm');
|
|
311
|
+
|
|
312
|
+
const ai = new AiBridgeManager({ providers: { openai: { api_key: process.env.OPENAI_API_KEY, model: 'gpt-4o-mini' } } });
|
|
313
|
+
const db = new DatabaseConnection();
|
|
314
|
+
const qb = new AIQueryBuilder(ai, db);
|
|
315
|
+
|
|
316
|
+
// Convert and execute
|
|
317
|
+
const result = await qb.query('How many users signed up last month?');
|
|
318
|
+
console.log(result.sql); // SELECT COUNT(*) ...
|
|
319
|
+
console.log(result.results); // [{ count: 42 }]
|
|
320
|
+
|
|
321
|
+
// Generate SQL without executing
|
|
322
|
+
const { sql } = await qb.toSql('Find duplicate emails');
|
|
323
|
+
|
|
324
|
+
// Use a specific provider
|
|
325
|
+
const r = await qb.using('claude', 'claude-sonnet-4-20250514')
|
|
326
|
+
.query('List users without orders');
|
|
327
|
+
|
|
328
|
+
// Disable safe mode (allow writes)
|
|
329
|
+
qb.safeMode(false);
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### AI Query Builder Methods
|
|
333
|
+
|
|
334
|
+
| Method | Returns | Description |
|
|
335
|
+
|--------|---------|-------------|
|
|
336
|
+
|`using(provider, model)`| `this` | Set LLM provider |
|
|
337
|
+
|`safeMode(bool)`| `this` | Restrict to SELECT/WITH (default: `true`) |
|
|
338
|
+
|`query(question)`| `{ sql, params, results, explanation }` | NL → SQL + execute |
|
|
339
|
+
|`toSql(question)`| `{ sql, params, explanation }` | NL → SQL only |
|
|
340
|
+
|
|
341
|
+
See [AI.md](AI.md) for full details.
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## AI Query Optimizer
|
|
346
|
+
|
|
347
|
+
> Since v8.0.0
|
|
348
|
+
|
|
349
|
+
Analyze and optimize SQL queries with AI.
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
const { AIQueryOptimizer } = require('outlet-orm');
|
|
353
|
+
|
|
354
|
+
const optimizer = new AIQueryOptimizer(ai, db);
|
|
355
|
+
const result = await optimizer.optimize('SELECT * FROM orders WHERE ...');
|
|
356
|
+
console.log(result.optimized); // Rewritten SQL
|
|
357
|
+
console.log(result.suggestions); // [{ type, description, impact }]
|
|
358
|
+
console.log(result.indexes); // ['CREATE INDEX ...']
|
|
359
|
+
|
|
360
|
+
const { plan, analysis } = await optimizer.explain('SELECT ...');
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
See [AI.md](AI.md) for full details.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
303
367
|
## Query Builder Methods Summary
|
|
304
368
|
|
|
305
369
|
| Method | Description |
|
|
@@ -96,3 +96,50 @@ outlet-migrate seed
|
|
|
96
96
|
- Control FK order explicitly in`DatabaseSeeder`.
|
|
97
97
|
- Keep heavy bulk data in dedicated import scripts.
|
|
98
98
|
- Prefer unique constraints to prevent duplicate seed data.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## AI Seeder — LLM-Powered Data Generation
|
|
103
|
+
|
|
104
|
+
> Since v8.0.0
|
|
105
|
+
|
|
106
|
+
Generate realistic domain-specific seed data using AI instead of generic lorem ipsum.
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
const { AiBridgeManager, AISeeder, DatabaseConnection } = require('outlet-orm');
|
|
110
|
+
|
|
111
|
+
const ai = new AiBridgeManager({
|
|
112
|
+
providers: { openai: { api_key: process.env.OPENAI_API_KEY, model: 'gpt-4o-mini' } }
|
|
113
|
+
});
|
|
114
|
+
const seeder = new AISeeder(ai, new DatabaseConnection());
|
|
115
|
+
|
|
116
|
+
// Generate and insert 10 realistic user records
|
|
117
|
+
const { records, inserted } = await seeder.seed('users', 10, {
|
|
118
|
+
domain: 'e-commerce',
|
|
119
|
+
locale: 'fr_FR',
|
|
120
|
+
description: 'An online fashion store'
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Preview without inserting
|
|
124
|
+
const preview = await seeder.generate('products', 5, {
|
|
125
|
+
domain: 'electronics'
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### AI Seeder API
|
|
130
|
+
|
|
131
|
+
| Method | Returns | Description |
|
|
132
|
+
|--------|---------|-------------|
|
|
133
|
+
|`using(provider, model)`| `this` | Set LLM provider |
|
|
134
|
+
|`seed(table, count, context)`| `{ records, inserted }` | Generate + insert |
|
|
135
|
+
|`generate(table, count, context)`| `Array<Object>` | Generate only (preview) |
|
|
136
|
+
|
|
137
|
+
### Context Options
|
|
138
|
+
|
|
139
|
+
| Option | Type | Description |
|
|
140
|
+
|--------|------|-------------|
|
|
141
|
+
| `domain` | `string` | Business domain (`'e-commerce'`, `'healthcare'`, `'finance'`) |
|
|
142
|
+
| `locale` | `string` | Locale for names/addresses (`'fr_FR'`, `'ja_JP'`, `'pt_BR'`) |
|
|
143
|
+
| `description` | `string` | Detailed description for better data quality |
|
|
144
|
+
|
|
145
|
+
See [AI.md](AI.md) for full details.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: outlet-orm-best-practices
|
|
3
|
-
description: Outlet ORM is a Laravel Eloquent-inspired ORM for Node.js with MySQL, PostgreSQL, and SQLite support. Use this skill when working with Outlet ORM models, queries, relationships, migrations, backup,
|
|
3
|
+
description: Outlet ORM is a Laravel Eloquent-inspired ORM for Node.js with MySQL, PostgreSQL, and SQLite support. Use this skill when working with Outlet ORM models, queries, relationships, migrations, backup, AI integration (AiBridge multi-provider LLM, AI Query Builder, AI Seeder, AI Optimizer, MCP Server) and database operations.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: omgbwa-yasse
|
|
7
|
-
version: "
|
|
7
|
+
version: "9.0.0"
|
|
8
8
|
source: https://github.com/omgbwa-yasse/outlet-orm
|
|
9
9
|
npm: https://www.npmjs.com/package/outlet-orm
|
|
10
10
|
---
|
|
@@ -13,11 +13,15 @@ npm: https://www.npmjs.com/package/outlet-orm
|
|
|
13
13
|
|
|
14
14
|
Comprehensive guide for using Outlet ORM - a Laravel Eloquent-inspired ORM for Node.js/TypeScript with support for MySQL, PostgreSQL, and SQLite.
|
|
15
15
|
|
|
16
|
-
> 🆕 **
|
|
16
|
+
> 🆕 **v9.0.0**: Complete AI documentation — AiBridge multi-provider LLM, AI Query Builder, AI Seeder, AI Optimizer, AI Prompt Enhancer, AI Safety Guardrails. See [AI.md](AI.md).
|
|
17
|
+
>
|
|
18
|
+
> 🔖 **v8.0.0**: AiBridge multi-provider LLM abstraction (9 providers), AI Query Builder, AI Seeder, AI Query Optimizer, AI Prompt Enhancer.
|
|
19
|
+
>
|
|
20
|
+
> 🔖 **v7.0.0**: AI Integration — MCP Server (Model Context Protocol), AI Safety Guardrails, Prompt-based project initialization.
|
|
17
21
|
>
|
|
18
22
|
> 🔖 **v6.5.0**: Accessors & Mutators, firstOrCreate/firstOrNew/updateOrCreate, upsert, Observer pattern, cursor/stream.
|
|
19
23
|
>
|
|
20
|
-
> 🔖 **v6.0.0**: Full Backup module — `BackupManager`, `BackupScheduler`, AES-256-GCM `BackupEncryption`, `BackupSocketServer` TCP daemon
|
|
24
|
+
> 🔖 **v6.0.0**: Full Backup module — `BackupManager`, `BackupScheduler`, AES-256-GCM `BackupEncryption`, `BackupSocketServer` TCP daemon. See [BACKUP.md](BACKUP.md).
|
|
21
25
|
>
|
|
22
26
|
> 🔖 **v5.0.0**: Full TypeScript support with Generic Model, typed Schema Builder, MigrationInterface and Copilot Skills integration.
|
|
23
27
|
|
|
@@ -33,7 +37,7 @@ Comprehensive guide for using Outlet ORM - a Laravel Eloquent-inspired ORM for N
|
|
|
33
37
|
| **[TYPESCRIPT.md](TYPESCRIPT.md)** | TypeScript types, generics, typed models, migrations |
|
|
34
38
|
| **[SECURITY.md](SECURITY.md)** | 🔐 Security best practices, authentication, authorisation |
|
|
35
39
|
| **[BACKUP.md](BACKUP.md)** | 🗄️ Backups, scheduling, AES-256-GCM encryption, TCP daemon, restore |
|
|
36
|
-
| **[AI.md](AI.md)** | 🤖 MCP Server, AI Safety Guardrails
|
|
40
|
+
| **[AI.md](AI.md)** | 🤖 AiBridge (9 LLM providers), AI Query Builder, AI Seeder, AI Optimizer, AI Prompt Enhancer, MCP Server, AI Safety Guardrails |
|
|
37
41
|
| **[API.md](API.md)** | Complete API Reference |
|
|
38
42
|
|
|
39
43
|
---
|
|
@@ -52,8 +56,12 @@ Reference these guidelines when:
|
|
|
52
56
|
- Scheduling or encrypting database backups [BACKUP.md](BACKUP.md)
|
|
53
57
|
- Restoring a database from a backup file [BACKUP.md](BACKUP.md)
|
|
54
58
|
- Running a long-lived backup daemon over TCP [BACKUP.md](BACKUP.md)
|
|
59
|
+
- Configuring LLM providers (AiBridge) [AI.md](AI.md)
|
|
60
|
+
- Converting natural language to SQL (AI Query Builder) [AI.md](AI.md)
|
|
61
|
+
- Generating realistic seed data with AI [AI.md](AI.md)
|
|
62
|
+
- Optimizing SQL queries with AI [AI.md](AI.md)
|
|
63
|
+
- Generating schemas/models/migrations from descriptions [AI.md](AI.md)
|
|
55
64
|
- Exposing the ORM to AI agents via MCP [AI.md](AI.md)
|
|
56
|
-
- Generating projects from natural language prompts [AI.md](AI.md)
|
|
57
65
|
- Protecting against AI-initiated destructive operations [AI.md](AI.md)
|
|
58
66
|
|
|
59
67
|
---
|
|
@@ -194,7 +202,7 @@ outlet-migrate migrate
|
|
|
194
202
|
| 7 | Validation & Events | MEDIUM | [ADVANCED.md](ADVANCED.md) |
|
|
195
203
|
| 8 | Migrations & CLI | LOW-MEDIUM | [MIGRATIONS.md](MIGRATIONS.md) |
|
|
196
204
|
| 9 | Backup & Restore | MEDIUM | [BACKUP.md](BACKUP.md) |
|
|
197
|
-
| 10 | AI / MCP Integration | MEDIUM | [AI.md](AI.md) |
|
|
205
|
+
| 10 | AI / MCP Integration | MEDIUM-HIGH | [AI.md](AI.md) |
|
|
198
206
|
|
|
199
207
|
---
|
|
200
208
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AIPromptEnhancer
|
|
5
|
+
* LLM-powered enhancement of the existing regex-based PromptGenerator.
|
|
6
|
+
* Takes a natural language description and uses AI to generate richer schemas,
|
|
7
|
+
* model code, migrations, and seeders — beyond what pattern matching can do.
|
|
8
|
+
*
|
|
9
|
+
* @since 8.0.0
|
|
10
|
+
*/
|
|
11
|
+
class AIPromptEnhancer {
|
|
12
|
+
/**
|
|
13
|
+
* @param {import('./AiBridgeManager')} manager
|
|
14
|
+
*/
|
|
15
|
+
constructor(manager) {
|
|
16
|
+
this._manager = manager;
|
|
17
|
+
this._provider = 'openai';
|
|
18
|
+
this._model = 'gpt-4o-mini';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} provider
|
|
23
|
+
* @param {string} model
|
|
24
|
+
* @returns {this}
|
|
25
|
+
*/
|
|
26
|
+
using(provider, model) {
|
|
27
|
+
this._provider = provider;
|
|
28
|
+
this._model = model;
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generate a full project schema from a natural language description.
|
|
34
|
+
* Returns tables, columns, relations, and seed hints.
|
|
35
|
+
* @param {string} description - e.g., "A recipe sharing app with users, recipes, ingredients, and reviews"
|
|
36
|
+
* @param {Object} [options={}]
|
|
37
|
+
* @returns {Promise<{tables: Object, relations: Array, seedHints: Object}>}
|
|
38
|
+
*/
|
|
39
|
+
async generateSchema(description, options = {}) {
|
|
40
|
+
const systemPrompt = `You are an expert database architect. Given an application description, design a complete relational database schema.
|
|
41
|
+
|
|
42
|
+
RULES:
|
|
43
|
+
- Return a JSON object with:
|
|
44
|
+
"tables" — object where each key is a table name, value is an object with "columns" (array of "name:type:modifiers" strings, using outlet-orm format like "name:string", "email:string:unique", "user_id:foreignId", "content:text:nullable", "price:decimal(10,2)", "status:string:default(active)").
|
|
45
|
+
"relations" — array of objects with "type" (hasOne, hasMany, belongsTo, belongsToMany), "from", "to", and optionally "pivot" table name.
|
|
46
|
+
"seedHints" — object where each key is a table name, value is a short description of the kind of seed data to generate.
|
|
47
|
+
- Always include id, created_at, updated_at columns implicitly (don't list them).
|
|
48
|
+
- Use snake_case for column/table names.
|
|
49
|
+
- Include foreign keys where appropriate.
|
|
50
|
+
- Design for at least 3rd normal form.`;
|
|
51
|
+
|
|
52
|
+
const messages = [
|
|
53
|
+
{ role: 'system', content: systemPrompt },
|
|
54
|
+
{ role: 'user', content: `Design a database schema for: ${description}` },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const res = await this._manager.chat(this._provider, messages, {
|
|
58
|
+
model: options.model || this._model,
|
|
59
|
+
temperature: 0.5,
|
|
60
|
+
max_tokens: 4096,
|
|
61
|
+
response_format: 'json',
|
|
62
|
+
json_schema: {
|
|
63
|
+
name: 'schema_design',
|
|
64
|
+
schema: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: {
|
|
67
|
+
tables: { type: 'object' },
|
|
68
|
+
relations: { type: 'array', items: { type: 'object' } },
|
|
69
|
+
seedHints: { type: 'object' },
|
|
70
|
+
},
|
|
71
|
+
required: ['tables'],
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return this._extractJson(res);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Generate model source code for a given table schema.
|
|
81
|
+
* @param {string} tableName
|
|
82
|
+
* @param {Object} tableSchema - { columns: [...] }
|
|
83
|
+
* @param {Array} [relations=[]]
|
|
84
|
+
* @returns {Promise<string>}
|
|
85
|
+
*/
|
|
86
|
+
async generateModelCode(tableName, tableSchema, relations = []) {
|
|
87
|
+
const systemPrompt = `You are an expert in outlet-orm (a Node.js Eloquent-inspired ORM).
|
|
88
|
+
Generate a complete model class for the given table. Use CommonJS (module.exports).
|
|
89
|
+
|
|
90
|
+
Example format:
|
|
91
|
+
const { Model } = require('outlet-orm');
|
|
92
|
+
class User extends Model {
|
|
93
|
+
static tableName = 'users';
|
|
94
|
+
static fillable = ['name', 'email', 'password'];
|
|
95
|
+
static hidden = ['password'];
|
|
96
|
+
static casts = { created_at: 'datetime' };
|
|
97
|
+
posts() { return this.hasMany('Post', 'user_id'); }
|
|
98
|
+
}
|
|
99
|
+
module.exports = User;
|
|
100
|
+
|
|
101
|
+
Include fillable, hidden (for sensitive fields), casts, and relation methods.`;
|
|
102
|
+
|
|
103
|
+
const messages = [
|
|
104
|
+
{ role: 'system', content: systemPrompt },
|
|
105
|
+
{
|
|
106
|
+
role: 'user',
|
|
107
|
+
content: `Generate an outlet-orm model for table "${tableName}":\nColumns: ${JSON.stringify(tableSchema.columns || [])}\nRelations: ${JSON.stringify(relations)}`,
|
|
108
|
+
},
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
const res = await this._manager.chat(this._provider, messages, {
|
|
112
|
+
model: this._model,
|
|
113
|
+
temperature: 0.3,
|
|
114
|
+
max_tokens: 2048,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return res?.output_text || res?.choices?.[0]?.message?.content || res?.content?.[0]?.text || '';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Generate migration code for a given table schema.
|
|
122
|
+
* @param {string} tableName
|
|
123
|
+
* @param {Object} tableSchema
|
|
124
|
+
* @returns {Promise<string>}
|
|
125
|
+
*/
|
|
126
|
+
async generateMigrationCode(tableName, tableSchema) {
|
|
127
|
+
const systemPrompt = `You are an expert in outlet-orm migrations. Generate a migration file.
|
|
128
|
+
|
|
129
|
+
Example format:
|
|
130
|
+
const { Migration, Schema } = require('outlet-orm');
|
|
131
|
+
class CreateUsersTable extends Migration {
|
|
132
|
+
async up(schema) {
|
|
133
|
+
await schema.create('users', (table) => {
|
|
134
|
+
table.increments('id');
|
|
135
|
+
table.string('name');
|
|
136
|
+
table.string('email').unique();
|
|
137
|
+
table.timestamps();
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async down(schema) {
|
|
141
|
+
await schema.dropIfExists('users');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
module.exports = CreateUsersTable;
|
|
145
|
+
|
|
146
|
+
Use proper column types: string, text, integer, bigInteger, decimal, boolean, date, datetime, timestamp, json, foreignId.`;
|
|
147
|
+
|
|
148
|
+
const messages = [
|
|
149
|
+
{ role: 'system', content: systemPrompt },
|
|
150
|
+
{ role: 'user', content: `Generate a migration for table "${tableName}":\nColumns: ${JSON.stringify(tableSchema.columns || [])}` },
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
const res = await this._manager.chat(this._provider, messages, {
|
|
154
|
+
model: this._model,
|
|
155
|
+
temperature: 0.2,
|
|
156
|
+
max_tokens: 2048,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return res?.output_text || res?.choices?.[0]?.message?.content || res?.content?.[0]?.text || '';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** @private */
|
|
163
|
+
_extractJson(res) {
|
|
164
|
+
let content = res?.output_text || res?.choices?.[0]?.message?.content || res?.content?.[0]?.text || res?.message?.content || '';
|
|
165
|
+
if (typeof content !== 'string') content = JSON.stringify(content);
|
|
166
|
+
try { return JSON.parse(content); } catch { return { tables: {}, relations: [], seedHints: {} }; }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
module.exports = AIPromptEnhancer;
|