@mostajs/orm-samples 0.1.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/CHANGELOG.md +53 -0
- package/LICENSE +29 -0
- package/README.md +78 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +175 -0
- package/examples/01-quickstart-sqlite/.env.example +6 -0
- package/examples/01-quickstart-sqlite/01-quickstart-sqlite.sh +23 -0
- package/examples/01-quickstart-sqlite/README.md +52 -0
- package/examples/01-quickstart-sqlite/app.ts +52 -0
- package/examples/01-quickstart-sqlite/package.json +18 -0
- package/examples/01-quickstart-sqlite/schemas/user.schema.ts +27 -0
- package/examples/02-multi-dialect-switch/.env.example +18 -0
- package/examples/02-multi-dialect-switch/02-multi-dialect-switch.sh +13 -0
- package/examples/02-multi-dialect-switch/README.md +68 -0
- package/examples/02-multi-dialect-switch/app.ts +68 -0
- package/examples/02-multi-dialect-switch/package.json +22 -0
- package/examples/02-multi-dialect-switch/schemas/user.schema.ts +25 -0
- package/examples/03-isolated-connections/.env.example +2 -0
- package/examples/03-isolated-connections/03-isolated-connections.sh +12 -0
- package/examples/03-isolated-connections/README.md +56 -0
- package/examples/03-isolated-connections/app.ts +79 -0
- package/examples/03-isolated-connections/package.json +18 -0
- package/examples/03-isolated-connections/schemas/user.schema.ts +23 -0
- package/examples/04-schema-registry/.env.example +2 -0
- package/examples/04-schema-registry/04-schema-registry.sh +10 -0
- package/examples/04-schema-registry/README.md +56 -0
- package/examples/04-schema-registry/app.ts +78 -0
- package/examples/04-schema-registry/package.json +17 -0
- package/examples/04-schema-registry/schemas/index.ts +35 -0
- package/examples/05-types-cles-entity-schema/.env.example +7 -0
- package/examples/05-types-cles-entity-schema/05-types-cles-entity-schema.sh +12 -0
- package/examples/05-types-cles-entity-schema/README.md +60 -0
- package/examples/05-types-cles-entity-schema/app.ts +85 -0
- package/examples/05-types-cles-entity-schema/package.json +18 -0
- package/examples/05-types-cles-entity-schema/schemas/article.schema.ts +93 -0
- package/llms.txt +76 -0
- package/package.json +62 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Changelog — `@mostajs/orm-samples`
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] — 2026-05-25
|
|
6
|
+
|
|
7
|
+
### Added — Lot 1 : Fondamentaux (5 samples)
|
|
8
|
+
|
|
9
|
+
- **`01-quickstart-sqlite`** — Pattern de base reproduisant le snippet
|
|
10
|
+
`## PATTERN` du llms.txt @mostajs/orm. Démontre : `createConnection`,
|
|
11
|
+
`BaseRepository`, `EntitySchema`, `FieldType`, `FieldDef`, `create`,
|
|
12
|
+
`findOne`, `ConnectionConfig`, `SchemaStrategy: 'update'`.
|
|
13
|
+
|
|
14
|
+
- **`02-multi-dialect-switch`** — Un seul code TypeScript, dialect changé
|
|
15
|
+
via `.env`. Démontre : `getConfigFromEnv`, `DialectType`, `ConnectionConfig`,
|
|
16
|
+
`SchemaStrategy`, `DIALECT_CONFIGS`, `getSupportedDialects`,
|
|
17
|
+
`getDialectConfig`, `DialectConfig`, `getCurrentDialectType`.
|
|
18
|
+
|
|
19
|
+
- **`03-isolated-connections`** — Multi-tenant via `createIsolatedDialect`
|
|
20
|
+
+ named connections. Démontre : `createIsolatedDialect`, `getDialect`
|
|
21
|
+
singleton (piège), `registerNamedConnection`, `getNamedConnection`,
|
|
22
|
+
`listNamedConnections`, `clearNamedConnections`.
|
|
23
|
+
|
|
24
|
+
- **`04-schema-registry`** — Registre global de schémas. Démontre :
|
|
25
|
+
`registerSchema`, `registerSchemas`, `getSchema`, `getSchemaByCollection`,
|
|
26
|
+
`getAllSchemas`, `getEntityNames`, `hasSchema`, `validateSchemas`,
|
|
27
|
+
`clearRegistry`.
|
|
28
|
+
|
|
29
|
+
- **`05-types-cles-entity-schema`** — Tous les champs `EntitySchema` au moins
|
|
30
|
+
une fois. Démontre : `EntitySchema`, `FieldDef` exhaustif, `FieldType`
|
|
31
|
+
(string/text/number/boolean/date/json/array), `EmbeddedSchemaDef`,
|
|
32
|
+
`IndexDef`, `IndexType` (asc/desc/text), `discriminator`, `softDelete`,
|
|
33
|
+
`timestamps`.
|
|
34
|
+
|
|
35
|
+
### Added — Scaffold module
|
|
36
|
+
|
|
37
|
+
- `package.json` (peer dep `@mostajs/orm ≥ 2.1.0`, bin `mostajs-orm-samples`)
|
|
38
|
+
- `tsconfig.json` strict
|
|
39
|
+
- `src/cli.ts` — CLI `list | scaffold | check | help`
|
|
40
|
+
- `README.md`, `llms.txt`, `LICENSE` (AGPL-3.0-or-later)
|
|
41
|
+
- `.gitignore` (exclut `examples/**/node_modules`, `*.db`, etc.)
|
|
42
|
+
|
|
43
|
+
### Décisions design
|
|
44
|
+
|
|
45
|
+
- Module npm séparé de `@mostajs/orm` (peer dep)
|
|
46
|
+
- Substitut public des tests internes (qui restent propriétaires entreprise —
|
|
47
|
+
cf. règle `feedback_public_vs_private_repo`)
|
|
48
|
+
- Chaque sample est autonome : `npm install` dans le sample lui-même quand
|
|
49
|
+
l'utilisateur le copie
|
|
50
|
+
- Default SQLite (zéro install externe) ; alternatives Postgres/MySQL
|
|
51
|
+
commentées dans `.env.example`
|
|
52
|
+
|
|
53
|
+
**Author** : Dr Hamid MADANI <drmdh@msn.com>
|
package/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
GNU AFFERO GENERAL PUBLIC LICENSE
|
|
2
|
+
Version 3, 19 November 2007
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2026 Dr Hamid MADANI <drmdh@msn.com>
|
|
5
|
+
|
|
6
|
+
This program is free software: you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
(at your option) any later version.
|
|
10
|
+
|
|
11
|
+
This program is distributed in the hope that it will be useful,
|
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
GNU Affero General Public License for more details.
|
|
15
|
+
|
|
16
|
+
You should have received a copy of the GNU Affero General Public License
|
|
17
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
|
|
19
|
+
COMMERCIAL LICENSE
|
|
20
|
+
|
|
21
|
+
For organizations that cannot comply with the AGPL open-source requirements,
|
|
22
|
+
a commercial license is available. Contact: drmdh@msn.com
|
|
23
|
+
|
|
24
|
+
The commercial license allows you to:
|
|
25
|
+
- Use the software in proprietary/closed-source projects
|
|
26
|
+
- Modify without publishing your source code
|
|
27
|
+
- Get priority support and SLA
|
|
28
|
+
|
|
29
|
+
Contact: Dr Hamid MADANI <drmdh@msn.com>
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# `@mostajs/orm-samples`
|
|
2
|
+
|
|
3
|
+
> Runnable samples covering 100% of `@mostajs/orm`'s public API — copy-paste install per feature.
|
|
4
|
+
|
|
5
|
+
**Auteur** : Dr Hamid MADANI <drmdh@msn.com>
|
|
6
|
+
**Statut** : V1 — Lot 1 (samples 01-05) livré
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Pourquoi ce module ?
|
|
11
|
+
|
|
12
|
+
Chaque sample démontre **une fonctionnalité** de `@mostajs/orm` en moins de
|
|
13
|
+
100 lignes de code, runnable en une commande, **sans framework parasite**
|
|
14
|
+
(pas d'Express, pas de Next.js — juste l'ORM).
|
|
15
|
+
|
|
16
|
+
Couverture cible : **chaque ligne du `llms.txt` de `@mostajs/orm` est démontrée
|
|
17
|
+
par au moins un sample** (garde-fou via test pérenne).
|
|
18
|
+
|
|
19
|
+
## Install rapide
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# 1. Lister tous les samples
|
|
23
|
+
npx @mostajs/orm-samples list
|
|
24
|
+
|
|
25
|
+
# 2. Scaffolder un sample chez vous
|
|
26
|
+
npx @mostajs/orm-samples scaffold <feature> ~/my-app
|
|
27
|
+
|
|
28
|
+
# 3. Lancer
|
|
29
|
+
cd ~/my-app && ./<feature>.sh
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Pattern d'install copier-coller (par feature)
|
|
33
|
+
|
|
34
|
+
Chaque sample s'installe via 4 commandes :
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# 1. Install package (cwd ne compte pas — temporaire)
|
|
38
|
+
mkdir tmp && cd tmp && npm init -y && npm install @mostajs/orm-samples
|
|
39
|
+
|
|
40
|
+
# 2. Copy the scaffold to your project location
|
|
41
|
+
cp -r node_modules/@mostajs/orm-samples/examples/<feature> ~/my-<feature>-app
|
|
42
|
+
cd ~/my-<feature>-app
|
|
43
|
+
rm -rf ../tmp
|
|
44
|
+
|
|
45
|
+
# 3. Install external resources éventuelles (driver SGBD, ffmpeg, etc.)
|
|
46
|
+
sudo apt install <package> # ou : brew install <package>
|
|
47
|
+
|
|
48
|
+
# 4. Launch (auto-handles npm install)
|
|
49
|
+
./<feature>.sh
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Catalogue (Lot 1 — Fondamentaux)
|
|
53
|
+
|
|
54
|
+
| # | Sample | Démontre |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| 01 | [`01-quickstart-sqlite`](examples/01-quickstart-sqlite/) | Pattern de base : `createConnection` + `BaseRepository` + `create` + `findOne` |
|
|
57
|
+
| 02 | [`02-multi-dialect-switch`](examples/02-multi-dialect-switch/) | `getConfigFromEnv` + `DialectType` + `DIALECT_CONFIGS` — un seul code, plusieurs SGBD |
|
|
58
|
+
| 03 | [`03-isolated-connections`](examples/03-isolated-connections/) | `createIsolatedDialect` + connexions nommées pour multi-tenant |
|
|
59
|
+
| 04 | [`04-schema-registry`](examples/04-schema-registry/) | Registre global `registerSchema`/`getSchema`/`validateSchemas`/`clearRegistry` |
|
|
60
|
+
| 05 | [`05-types-cles-entity-schema`](examples/05-types-cles-entity-schema/) | Tous les `FieldType`/`FieldDef`/`IndexDef` + `softDelete` + `discriminator` |
|
|
61
|
+
|
|
62
|
+
Lots suivants (cf. ROADMAP propriétaire entreprise) : CRUD & queries (06-09),
|
|
63
|
+
Relations & lifecycle (10-15), Plugins & sous-modules (16-18), Validator
|
|
64
|
+
& erreurs (19-25).
|
|
65
|
+
|
|
66
|
+
## CLI `mostajs-orm-samples`
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
mostajs-orm-samples list # liste les samples
|
|
70
|
+
mostajs-orm-samples list --json # machine-readable
|
|
71
|
+
mostajs-orm-samples scaffold <feature> [dest] # copie le scaffold
|
|
72
|
+
mostajs-orm-samples check <feature> # ressources requises
|
|
73
|
+
mostajs-orm-samples help [feature] # aide globale ou par sample
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Licence
|
|
77
|
+
|
|
78
|
+
AGPL-3.0-or-later — voir [LICENSE](LICENSE).
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @mostajs/orm-samples — CLI
|
|
3
|
+
// Author: Dr Hamid MADANI <drmdh@msn.com>
|
|
4
|
+
//
|
|
5
|
+
// Commands :
|
|
6
|
+
// mostajs-orm-samples list [--json]
|
|
7
|
+
// mostajs-orm-samples scaffold <feature> [dest]
|
|
8
|
+
// mostajs-orm-samples check <feature>
|
|
9
|
+
// mostajs-orm-samples help [feature]
|
|
10
|
+
import { readdirSync, statSync, readFileSync, cpSync, existsSync, mkdirSync } from 'node:fs';
|
|
11
|
+
import { join, resolve, dirname } from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const examplesDir = resolve(__dirname, '..', 'examples');
|
|
15
|
+
function listSamples() {
|
|
16
|
+
if (!existsSync(examplesDir))
|
|
17
|
+
return [];
|
|
18
|
+
const entries = readdirSync(examplesDir).filter((e) => {
|
|
19
|
+
if (e.startsWith('_'))
|
|
20
|
+
return false;
|
|
21
|
+
const full = join(examplesDir, e);
|
|
22
|
+
try {
|
|
23
|
+
return statSync(full).isDirectory();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
entries.sort();
|
|
30
|
+
return entries.map((id) => {
|
|
31
|
+
const readmePath = join(examplesDir, id, 'README.md');
|
|
32
|
+
let pitch = '';
|
|
33
|
+
let covers = '';
|
|
34
|
+
if (existsSync(readmePath)) {
|
|
35
|
+
const content = readFileSync(readmePath, 'utf-8');
|
|
36
|
+
const pitchMatch = content.match(/^>\s+(.+)$/m);
|
|
37
|
+
pitch = pitchMatch ? pitchMatch[1].trim() : '';
|
|
38
|
+
const coversMatch = content.match(/^\*\*Couvre\*\*\s*:\s*(.+)$/m);
|
|
39
|
+
covers = coversMatch ? coversMatch[1].trim() : '';
|
|
40
|
+
}
|
|
41
|
+
return { id, name: id, pitch, covers };
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function cmdList(args) {
|
|
45
|
+
const samples = listSamples();
|
|
46
|
+
const json = args.includes('--json');
|
|
47
|
+
if (json) {
|
|
48
|
+
console.log(JSON.stringify(samples, null, 2));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (samples.length === 0) {
|
|
52
|
+
console.log('No samples found.');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
console.log(`\nAvailable samples (${samples.length}):\n`);
|
|
56
|
+
for (const s of samples) {
|
|
57
|
+
const pitch = s.pitch || '(no pitch)';
|
|
58
|
+
console.log(` ${s.id.padEnd(36)} ${pitch}`);
|
|
59
|
+
}
|
|
60
|
+
console.log('');
|
|
61
|
+
console.log(`Run \`mostajs-orm-samples help <feature>\` for details.`);
|
|
62
|
+
console.log(`Run \`mostajs-orm-samples scaffold <feature> [dest]\` to copy a sample.`);
|
|
63
|
+
}
|
|
64
|
+
function cmdScaffold(args) {
|
|
65
|
+
const feature = args[0];
|
|
66
|
+
if (!feature) {
|
|
67
|
+
console.error('Usage: mostajs-orm-samples scaffold <feature> [dest]');
|
|
68
|
+
process.exit(2);
|
|
69
|
+
}
|
|
70
|
+
const src = join(examplesDir, feature);
|
|
71
|
+
if (!existsSync(src)) {
|
|
72
|
+
console.error(`Sample '${feature}' not found. Run \`mostajs-orm-samples list\` to see available samples.`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
const dest = resolve(args[1] ?? join(process.cwd(), `my-${feature}-app`));
|
|
76
|
+
if (existsSync(dest)) {
|
|
77
|
+
console.error(`Destination '${dest}' already exists. Refusing to overwrite.`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
81
|
+
cpSync(src, dest, { recursive: true });
|
|
82
|
+
console.log(`\n✅ Scaffolded '${feature}' to:\n ${dest}\n`);
|
|
83
|
+
console.log('Next steps:');
|
|
84
|
+
console.log(` cd ${dest}`);
|
|
85
|
+
// Hint pour ressources externes éventuelles
|
|
86
|
+
const readmePath = join(dest, 'README.md');
|
|
87
|
+
if (existsSync(readmePath)) {
|
|
88
|
+
const content = readFileSync(readmePath, 'utf-8');
|
|
89
|
+
const extMatch = content.match(/## External resources\n([\s\S]*?)(?=\n##|$)/i);
|
|
90
|
+
if (extMatch && !/aucun/i.test(extMatch[1])) {
|
|
91
|
+
console.log('');
|
|
92
|
+
console.log('External resources required (cf. README.md):');
|
|
93
|
+
console.log(extMatch[1].trim().split('\n').map((l) => ' ' + l).join('\n'));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
console.log('');
|
|
97
|
+
console.log(` ./${feature}.sh # launch sample`);
|
|
98
|
+
console.log('');
|
|
99
|
+
}
|
|
100
|
+
function cmdCheck(args) {
|
|
101
|
+
const feature = args[0];
|
|
102
|
+
if (!feature) {
|
|
103
|
+
console.error('Usage: mostajs-orm-samples check <feature>');
|
|
104
|
+
process.exit(2);
|
|
105
|
+
}
|
|
106
|
+
const readmePath = join(examplesDir, feature, 'README.md');
|
|
107
|
+
if (!existsSync(readmePath)) {
|
|
108
|
+
console.error(`Sample '${feature}' not found.`);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
const content = readFileSync(readmePath, 'utf-8');
|
|
112
|
+
const extMatch = content.match(/## External resources\n([\s\S]*?)(?=\n##|$)/i);
|
|
113
|
+
if (!extMatch || /aucun/i.test(extMatch[1])) {
|
|
114
|
+
console.log(`Sample '${feature}': aucune ressource externe requise.`);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
console.log(`Sample '${feature}' — external resources required :\n`);
|
|
118
|
+
console.log(extMatch[1].trim());
|
|
119
|
+
}
|
|
120
|
+
function cmdHelp(args) {
|
|
121
|
+
const feature = args[0];
|
|
122
|
+
if (feature) {
|
|
123
|
+
const readmePath = join(examplesDir, feature, 'README.md');
|
|
124
|
+
if (!existsSync(readmePath)) {
|
|
125
|
+
console.error(`Sample '${feature}' not found.`);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
console.log(readFileSync(readmePath, 'utf-8'));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
console.log(`
|
|
132
|
+
@mostajs/orm-samples — runnable samples for @mostajs/orm
|
|
133
|
+
|
|
134
|
+
USAGE
|
|
135
|
+
mostajs-orm-samples <command> [args]
|
|
136
|
+
|
|
137
|
+
COMMANDS
|
|
138
|
+
list [--json] List all available samples
|
|
139
|
+
scaffold <feature> [dest] Copy a sample to dest (default: ./my-<feature>-app)
|
|
140
|
+
check <feature> Show external resources required by the sample
|
|
141
|
+
help [feature] Show this help, or the README of a specific sample
|
|
142
|
+
|
|
143
|
+
EXAMPLES
|
|
144
|
+
mostajs-orm-samples list
|
|
145
|
+
mostajs-orm-samples scaffold 01-quickstart-sqlite
|
|
146
|
+
mostajs-orm-samples scaffold 02-multi-dialect-switch ~/my-app
|
|
147
|
+
mostajs-orm-samples check 18-bridge-jdbc
|
|
148
|
+
mostajs-orm-samples help 09-findbyid-polymorphic
|
|
149
|
+
|
|
150
|
+
Author: Dr Hamid MADANI <drmdh@msn.com>
|
|
151
|
+
`);
|
|
152
|
+
}
|
|
153
|
+
// ─── Dispatcher ────────────────────────────────────────────────────
|
|
154
|
+
const [cmd, ...args] = process.argv.slice(2);
|
|
155
|
+
switch (cmd) {
|
|
156
|
+
case 'list':
|
|
157
|
+
cmdList(args);
|
|
158
|
+
break;
|
|
159
|
+
case 'scaffold':
|
|
160
|
+
cmdScaffold(args);
|
|
161
|
+
break;
|
|
162
|
+
case 'check':
|
|
163
|
+
cmdCheck(args);
|
|
164
|
+
break;
|
|
165
|
+
case 'help':
|
|
166
|
+
case undefined:
|
|
167
|
+
case '--help':
|
|
168
|
+
case '-h':
|
|
169
|
+
cmdHelp(args);
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
console.error(`Unknown command: ${cmd}`);
|
|
173
|
+
cmdHelp([]);
|
|
174
|
+
process.exit(2);
|
|
175
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -e
|
|
3
|
+
cd "$(dirname "$0")"
|
|
4
|
+
|
|
5
|
+
# ─── Install deps if missing ───
|
|
6
|
+
if [ ! -d node_modules ]; then
|
|
7
|
+
echo "─── Installing dependencies (first run) ───"
|
|
8
|
+
npm install --silent --no-audit --no-fund
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
# ─── Reset DB for clean re-run ───
|
|
12
|
+
rm -f app.db
|
|
13
|
+
|
|
14
|
+
# ─── Run sample ───
|
|
15
|
+
npx -y tsx app.ts
|
|
16
|
+
|
|
17
|
+
# ─── Verify file artefact ───
|
|
18
|
+
if [ ! -f app.db ]; then
|
|
19
|
+
echo "❌ app.db not created"
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
echo "✓ app.db présent ($(stat -c %s app.db) bytes)"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 01-quickstart-sqlite
|
|
2
|
+
|
|
3
|
+
> Pattern de base ORM en SQLite — createConnection + BaseRepository + create + findOne.
|
|
4
|
+
|
|
5
|
+
**Couvre** : `createConnection`, `BaseRepository`, `EntitySchema`, `FieldType`,
|
|
6
|
+
`FieldDef`, `create`, `findOne`, `ConnectionConfig`, `SchemaStrategy: 'update'`.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
mkdir tmp && cd tmp && npm init -y && npm install @mostajs/orm-samples
|
|
12
|
+
cp -r node_modules/@mostajs/orm-samples/examples/01-quickstart-sqlite ~/my-quickstart-app
|
|
13
|
+
cd ~/my-quickstart-app
|
|
14
|
+
rm -rf ../tmp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## External resources
|
|
18
|
+
|
|
19
|
+
aucune *(SQLite via better-sqlite3 inclus en dev dependency)*.
|
|
20
|
+
|
|
21
|
+
## Run
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
./01-quickstart-sqlite.sh
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Expected output
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
─── Quickstart SQLite — @mostajs/orm ───
|
|
31
|
+
✓ Connected to SQLite (./app.db)
|
|
32
|
+
✓ User created (id=…)
|
|
33
|
+
✓ findOne by email returned: { id: '…', email: 'alice@example.com', name: 'Alice' }
|
|
34
|
+
✓ count = 1
|
|
35
|
+
✅ Smoke OK
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## What it shows
|
|
39
|
+
|
|
40
|
+
- Le `EntitySchema` minimal (fields + indexes vides + timestamps)
|
|
41
|
+
- L'`createConnection` synchrone avec `SchemaStrategy: 'update'` qui crée la
|
|
42
|
+
table automatiquement
|
|
43
|
+
- L'instanciation du `BaseRepository<TUser>` typé
|
|
44
|
+
- Le cycle `create()` → `findOne()` → `count()` en 4 lignes
|
|
45
|
+
|
|
46
|
+
## Files
|
|
47
|
+
|
|
48
|
+
- `app.ts` — main code
|
|
49
|
+
- `schemas/user.schema.ts` — schéma User minimal
|
|
50
|
+
- `.env.example` — config (DB_DIALECT=sqlite par défaut)
|
|
51
|
+
|
|
52
|
+
**Author** : Dr Hamid MADANI <drmdh@msn.com>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Quickstart SQLite — pattern de base de @mostajs/orm.
|
|
2
|
+
//
|
|
3
|
+
// Démontre la séquence minimale :
|
|
4
|
+
// 1. EntitySchema (fields + indexes + timestamps)
|
|
5
|
+
// 2. createConnection(config, [schema])
|
|
6
|
+
// 3. new BaseRepository<TRow>(schema, dialect)
|
|
7
|
+
// 4. create / findOne / count
|
|
8
|
+
//
|
|
9
|
+
// Author: Dr Hamid MADANI <drmdh@msn.com>
|
|
10
|
+
|
|
11
|
+
import { createConnection, BaseRepository } from '@mostajs/orm'
|
|
12
|
+
import { UserSchema, type UserRow } from './schemas/user.schema.js'
|
|
13
|
+
|
|
14
|
+
async function main(): Promise<void> {
|
|
15
|
+
console.log('─── Quickstart SQLite — @mostajs/orm ───')
|
|
16
|
+
|
|
17
|
+
// 1. Connexion SQLite. schemaStrategy: 'update' crée/migre les tables.
|
|
18
|
+
const dialect = await createConnection(
|
|
19
|
+
{ dialect: 'sqlite', uri: './app.db', schemaStrategy: 'update' },
|
|
20
|
+
[UserSchema],
|
|
21
|
+
)
|
|
22
|
+
console.log('✓ Connected to SQLite (./app.db)')
|
|
23
|
+
|
|
24
|
+
// 2. BaseRepository typé.
|
|
25
|
+
const users = new BaseRepository<UserRow>(UserSchema, dialect)
|
|
26
|
+
|
|
27
|
+
// 3. Create — insère et retourne le row avec id généré.
|
|
28
|
+
const created = await users.create({ email: 'alice@example.com', name: 'Alice' })
|
|
29
|
+
console.log(`✓ User created (id=${created.id})`)
|
|
30
|
+
|
|
31
|
+
// 4. findOne — lookup par n'importe quel field, retourne null si absent.
|
|
32
|
+
const found = await users.findOne({ email: 'alice@example.com' })
|
|
33
|
+
console.log('✓ findOne by email returned:', { id: found?.id, email: found?.email, name: found?.name })
|
|
34
|
+
|
|
35
|
+
// 5. count — total des rows matching le filter.
|
|
36
|
+
const total = await users.count({})
|
|
37
|
+
console.log(`✓ count = ${total}`)
|
|
38
|
+
|
|
39
|
+
// Assertions smoke pour le .sh
|
|
40
|
+
if (!found || found.email !== 'alice@example.com') throw new Error('findOne assertion failed')
|
|
41
|
+
if (total !== 1) throw new Error(`count expected 1, got ${total}`)
|
|
42
|
+
|
|
43
|
+
console.log('✅ Smoke OK')
|
|
44
|
+
|
|
45
|
+
// Cleanup connexion (le sample se termine, la DB ./app.db reste pour inspection)
|
|
46
|
+
await dialect.disconnect?.()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
main().catch((err) => {
|
|
50
|
+
console.error('❌ Sample failed:', err)
|
|
51
|
+
process.exit(1)
|
|
52
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "01-quickstart-sqlite",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "tsx app.ts"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@mostajs/orm": "^2.1.0",
|
|
11
|
+
"better-sqlite3": "^12.0.0"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"tsx": "^4.0.0",
|
|
15
|
+
"typescript": "^5.6.0",
|
|
16
|
+
"@types/node": "^22.0.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Schéma User minimal — démontre EntitySchema + FieldType + FieldDef.
|
|
2
|
+
// Author: Dr Hamid MADANI <drmdh@msn.com>
|
|
3
|
+
|
|
4
|
+
import type { EntitySchema } from '@mostajs/orm'
|
|
5
|
+
|
|
6
|
+
export const UserSchema: EntitySchema = {
|
|
7
|
+
name: 'User',
|
|
8
|
+
collection: 'users',
|
|
9
|
+
// FieldDef avec required + unique. FieldType 'string' parmi
|
|
10
|
+
// ('string'|'text'|'number'|'boolean'|'date'|'json'|'array').
|
|
11
|
+
fields: {
|
|
12
|
+
email: { type: 'string', required: true, unique: true },
|
|
13
|
+
name: { type: 'string' },
|
|
14
|
+
},
|
|
15
|
+
relations: {},
|
|
16
|
+
indexes: [],
|
|
17
|
+
timestamps: true, // createdAt / updatedAt auto-gérés
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Type pour le BaseRepository<TUser>
|
|
21
|
+
export interface UserRow {
|
|
22
|
+
id: string
|
|
23
|
+
email: string
|
|
24
|
+
name?: string
|
|
25
|
+
createdAt?: Date
|
|
26
|
+
updatedAt?: Date
|
|
27
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Default — SQLite local, zéro install externe.
|
|
2
|
+
DB_DIALECT=sqlite
|
|
3
|
+
SGBD_URI=./app.db
|
|
4
|
+
|
|
5
|
+
# Postgres
|
|
6
|
+
# DB_DIALECT=postgres
|
|
7
|
+
# SGBD_URI=postgresql://postgres:password@localhost:5432/test
|
|
8
|
+
|
|
9
|
+
# MySQL / MariaDB
|
|
10
|
+
# DB_DIALECT=mysql
|
|
11
|
+
# SGBD_URI=mysql://root:password@localhost:3306/test
|
|
12
|
+
|
|
13
|
+
# MongoDB
|
|
14
|
+
# DB_DIALECT=mongodb
|
|
15
|
+
# SGBD_URI=mongodb://localhost:27017/test
|
|
16
|
+
|
|
17
|
+
# Profil pour cascade .env.<profile> via @mostajs/config
|
|
18
|
+
# MOSTA_ENV=production
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -e
|
|
3
|
+
cd "$(dirname "$0")"
|
|
4
|
+
|
|
5
|
+
if [ ! -d node_modules ]; then
|
|
6
|
+
echo "─── Installing dependencies (first run) ───"
|
|
7
|
+
npm install --silent --no-audit --no-fund
|
|
8
|
+
fi
|
|
9
|
+
|
|
10
|
+
# Reset only the local SQLite (les Postgres/MySQL externes ne sont pas reset ici)
|
|
11
|
+
rm -f app.db
|
|
12
|
+
|
|
13
|
+
npx -y tsx app.ts
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# 02-multi-dialect-switch
|
|
2
|
+
|
|
3
|
+
> Un seul code TypeScript, dialect changé via `.env` — démontre la portabilité multi-dialecte de @mostajs/orm.
|
|
4
|
+
|
|
5
|
+
**Couvre** : `getConfigFromEnv`, `DialectType`, `ConnectionConfig`,
|
|
6
|
+
`SchemaStrategy`, `DIALECT_CONFIGS`, `getSupportedDialects`,
|
|
7
|
+
`getDialectConfig`, `DialectConfig`, `getCurrentDialectType`.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
mkdir tmp && cd tmp && npm init -y && npm install @mostajs/orm-samples
|
|
13
|
+
cp -r node_modules/@mostajs/orm-samples/examples/02-multi-dialect-switch ~/my-multi-dialect-app
|
|
14
|
+
cd ~/my-multi-dialect-app
|
|
15
|
+
rm -rf ../tmp
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## External resources
|
|
19
|
+
|
|
20
|
+
- **Default SQLite** : aucune (better-sqlite3 inclus)
|
|
21
|
+
- **Postgres** *(optionnel)* : `brew install postgresql` ou Docker
|
|
22
|
+
`docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=test postgres:16`
|
|
23
|
+
- **MySQL** *(optionnel)* : `brew install mysql` ou Docker
|
|
24
|
+
`docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=test mysql:8`
|
|
25
|
+
|
|
26
|
+
## Run
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Default SQLite :
|
|
30
|
+
./02-multi-dialect-switch.sh
|
|
31
|
+
|
|
32
|
+
# Postgres :
|
|
33
|
+
DB_DIALECT=postgres SGBD_URI=postgresql://postgres:test@localhost:5432/test ./02-multi-dialect-switch.sh
|
|
34
|
+
|
|
35
|
+
# MySQL :
|
|
36
|
+
DB_DIALECT=mysql SGBD_URI=mysql://root:test@localhost:3306/test ./02-multi-dialect-switch.sh
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Expected output
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
─── Multi-dialect switch — @mostajs/orm ───
|
|
43
|
+
Dialects supportés :
|
|
44
|
+
- sqlite SQLite (better-sqlite3)
|
|
45
|
+
- postgres PostgreSQL (pg)
|
|
46
|
+
- mysql MySQL (mysql2)
|
|
47
|
+
…
|
|
48
|
+
✓ Config courante : { dialect: 'sqlite', uri: './app.db', … }
|
|
49
|
+
✓ Connecté à : sqlite
|
|
50
|
+
✓ User créé sur sqlite (id=…)
|
|
51
|
+
✅ Smoke OK — le même code marche sur n'importe quel dialect.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## What it shows
|
|
55
|
+
|
|
56
|
+
- `getSupportedDialects()` retourne les 13 dialects connus
|
|
57
|
+
- `getDialectConfig(name)` retourne la métadata d'un dialect (driver, etc.)
|
|
58
|
+
- `getConfigFromEnv()` lit `DB_DIALECT` + `SGBD_URI` (+ cascade MOSTA_ENV)
|
|
59
|
+
- Le **même code applicatif** tourne sur SQLite / Postgres / MySQL en ne
|
|
60
|
+
changeant que le `.env`
|
|
61
|
+
|
|
62
|
+
## Files
|
|
63
|
+
|
|
64
|
+
- `app.ts` — main code (entièrement dialect-agnostic)
|
|
65
|
+
- `schemas/user.schema.ts` — schéma User minimal
|
|
66
|
+
- `.env.example` — 3 dialects commentés
|
|
67
|
+
|
|
68
|
+
**Author** : Dr Hamid MADANI <drmdh@msn.com>
|