@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.
Files changed (37) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/LICENSE +29 -0
  3. package/README.md +78 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +175 -0
  6. package/examples/01-quickstart-sqlite/.env.example +6 -0
  7. package/examples/01-quickstart-sqlite/01-quickstart-sqlite.sh +23 -0
  8. package/examples/01-quickstart-sqlite/README.md +52 -0
  9. package/examples/01-quickstart-sqlite/app.ts +52 -0
  10. package/examples/01-quickstart-sqlite/package.json +18 -0
  11. package/examples/01-quickstart-sqlite/schemas/user.schema.ts +27 -0
  12. package/examples/02-multi-dialect-switch/.env.example +18 -0
  13. package/examples/02-multi-dialect-switch/02-multi-dialect-switch.sh +13 -0
  14. package/examples/02-multi-dialect-switch/README.md +68 -0
  15. package/examples/02-multi-dialect-switch/app.ts +68 -0
  16. package/examples/02-multi-dialect-switch/package.json +22 -0
  17. package/examples/02-multi-dialect-switch/schemas/user.schema.ts +25 -0
  18. package/examples/03-isolated-connections/.env.example +2 -0
  19. package/examples/03-isolated-connections/03-isolated-connections.sh +12 -0
  20. package/examples/03-isolated-connections/README.md +56 -0
  21. package/examples/03-isolated-connections/app.ts +79 -0
  22. package/examples/03-isolated-connections/package.json +18 -0
  23. package/examples/03-isolated-connections/schemas/user.schema.ts +23 -0
  24. package/examples/04-schema-registry/.env.example +2 -0
  25. package/examples/04-schema-registry/04-schema-registry.sh +10 -0
  26. package/examples/04-schema-registry/README.md +56 -0
  27. package/examples/04-schema-registry/app.ts +78 -0
  28. package/examples/04-schema-registry/package.json +17 -0
  29. package/examples/04-schema-registry/schemas/index.ts +35 -0
  30. package/examples/05-types-cles-entity-schema/.env.example +7 -0
  31. package/examples/05-types-cles-entity-schema/05-types-cles-entity-schema.sh +12 -0
  32. package/examples/05-types-cles-entity-schema/README.md +60 -0
  33. package/examples/05-types-cles-entity-schema/app.ts +85 -0
  34. package/examples/05-types-cles-entity-schema/package.json +18 -0
  35. package/examples/05-types-cles-entity-schema/schemas/article.schema.ts +93 -0
  36. package/llms.txt +76 -0
  37. package/package.json +62 -0
@@ -0,0 +1,68 @@
1
+ // Multi-dialect switch — un seul code, plusieurs SGBD via .env.
2
+ //
3
+ // Démontre :
4
+ // - getSupportedDialects() : énumération des dialects supportés
5
+ // - getDialectConfig(name) : métadata d'un dialect (driver, etc.)
6
+ // - getConfigFromEnv() : lit DB_DIALECT + SGBD_URI depuis .env
7
+ // - createConnection(config) : config-driven, dialect-agnostic
8
+ // - getCurrentDialectType() : type du dialect actuellement connecté
9
+ //
10
+ // Author: Dr Hamid MADANI <drmdh@msn.com>
11
+
12
+ import {
13
+ createConnection,
14
+ getConfigFromEnv,
15
+ getSupportedDialects,
16
+ getDialectConfig,
17
+ getCurrentDialectType,
18
+ BaseRepository,
19
+ } from '@mostajs/orm'
20
+ import { UserSchema, type UserRow } from './schemas/user.schema.js'
21
+
22
+ async function main(): Promise<void> {
23
+ console.log('─── Multi-dialect switch — @mostajs/orm ───')
24
+
25
+ // 1. Liste exhaustive des dialects supportés par la version installée.
26
+ console.log('\nDialects supportés :')
27
+ for (const name of getSupportedDialects()) {
28
+ const cfg = getDialectConfig(name)
29
+ console.log(` - ${name.padEnd(12)} ${cfg?.label ?? cfg?.driver ?? ''}`)
30
+ }
31
+
32
+ // 2. Config lue depuis .env (DB_DIALECT + SGBD_URI). Si rien n'est défini,
33
+ // on fournit un fallback sqlite local — utile pour la première exécution
34
+ // sans configurer .env.
35
+ let config
36
+ try {
37
+ config = getConfigFromEnv()
38
+ } catch {
39
+ console.log('\nℹ DB_DIALECT non défini — fallback SQLite local.')
40
+ config = { dialect: 'sqlite' as const, uri: './app.db' }
41
+ }
42
+ config.schemaStrategy = 'update'
43
+
44
+ console.log('\n✓ Config courante :', config)
45
+
46
+ // 3. Connexion sur le dialect choisi.
47
+ const dialect = await createConnection(config, [UserSchema])
48
+ const currentDialect = getCurrentDialectType()
49
+ console.log(`✓ Connecté à : ${currentDialect}`)
50
+
51
+ // 4. Le code applicatif est strictement le même quel que soit le SGBD.
52
+ const users = new BaseRepository<UserRow>(UserSchema, dialect)
53
+ const email = `multi-${currentDialect}-${Date.now()}@example.com`
54
+ const created = await users.create({ email, name: 'MultiDialect' })
55
+ console.log(`✓ User créé sur ${currentDialect} (id=${created.id})`)
56
+
57
+ const found = await users.findOne({ email })
58
+ if (!found) throw new Error('findOne failed after create')
59
+
60
+ console.log('✅ Smoke OK — le même code marche sur n\'importe quel dialect.')
61
+
62
+ await dialect.disconnect?.()
63
+ }
64
+
65
+ main().catch((err) => {
66
+ console.error('❌ Sample failed:', err)
67
+ process.exit(1)
68
+ })
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "02-multi-dialect-switch",
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
+ "optionalDependencies": {
14
+ "pg": "^8.20.0",
15
+ "mysql2": "^3.0.0"
16
+ },
17
+ "devDependencies": {
18
+ "tsx": "^4.0.0",
19
+ "typescript": "^5.6.0",
20
+ "@types/node": "^22.0.0"
21
+ }
22
+ }
@@ -0,0 +1,25 @@
1
+ // Schéma User identique au sample 01 — la portabilité dialect repose sur
2
+ // le fait que le SAME EntitySchema fonctionne pour tous les dialects SQL.
3
+ // Author: Dr Hamid MADANI <drmdh@msn.com>
4
+
5
+ import type { EntitySchema } from '@mostajs/orm'
6
+
7
+ export const UserSchema: EntitySchema = {
8
+ name: 'User',
9
+ collection: 'users',
10
+ fields: {
11
+ email: { type: 'string', required: true, unique: true },
12
+ name: { type: 'string' },
13
+ },
14
+ relations: {},
15
+ indexes: [{ fields: { email: 'asc' }, unique: true }],
16
+ timestamps: true,
17
+ }
18
+
19
+ export interface UserRow {
20
+ id: string
21
+ email: string
22
+ name?: string
23
+ createdAt?: Date
24
+ updatedAt?: Date
25
+ }
@@ -0,0 +1,2 @@
1
+ # Ce sample utilise des paths SQLite codés en dur (tenant-a.db, tenant-b.db).
2
+ # Pour adapter à d'autres dialects, modifier directement app.ts.
@@ -0,0 +1,12 @@
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
+ rm -f tenant-a.db tenant-b.db
11
+
12
+ npx -y tsx app.ts
@@ -0,0 +1,56 @@
1
+ # 03-isolated-connections
2
+
3
+ > Multi-tenant via `createIsolatedDialect` + connexions nommées — démontre la différence entre singleton `getDialect()` et instances isolées.
4
+
5
+ **Couvre** : `createIsolatedDialect`, `getDialect` (piège singleton),
6
+ `registerNamedConnection`, `getNamedConnection`, `removeNamedConnection`,
7
+ `listNamedConnections`, `clearNamedConnections`.
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/03-isolated-connections ~/my-isolated-app
14
+ cd ~/my-isolated-app
15
+ rm -rf ../tmp
16
+ ```
17
+
18
+ ## External resources
19
+
20
+ aucune *(SQLite via better-sqlite3)*.
21
+
22
+ ## Run
23
+
24
+ ```bash
25
+ ./03-isolated-connections.sh
26
+ ```
27
+
28
+ ## Expected output
29
+
30
+ ```
31
+ ─── Isolated connections — @mostajs/orm ───
32
+ ✓ tenant-a connecté à ./tenant-a.db
33
+ ✓ tenant-b connecté à ./tenant-b.db
34
+ ✓ named connections enregistrées : tenant-a, tenant-b
35
+ ✓ count tenant-a = 1
36
+ ✓ count tenant-b = 2
37
+ ✓ DBs physiquement distinctes (count diffère)
38
+ ✅ Smoke OK
39
+ ```
40
+
41
+ ## What it shows
42
+
43
+ - **Piège singleton** : `getDialect()` retourne **toujours la même
44
+ instance**. Pour deux tenants, utiliser `createIsolatedDialect()` qui
45
+ bypass le singleton.
46
+ - **Named connections** : registre clé→dialect pour récupérer une
47
+ connexion par nom métier sans la passer en paramètre partout.
48
+ - **Lifecycle complet** : register → use → unregister → clear.
49
+
50
+ ## Files
51
+
52
+ - `app.ts` — main code multi-tenant
53
+ - `schemas/user.schema.ts` — schéma partagé entre les 2 tenants
54
+ - `.env.example` — config
55
+
56
+ **Author** : Dr Hamid MADANI <drmdh@msn.com>
@@ -0,0 +1,79 @@
1
+ // Isolated connections — multi-tenant via createIsolatedDialect + named connections.
2
+ //
3
+ // Démontre :
4
+ // - Piège getDialect() singleton vs createIsolatedDialect()
5
+ // - registerNamedConnection / getNamedConnection / listNamedConnections /
6
+ // removeNamedConnection / clearNamedConnections
7
+ //
8
+ // Cas d'usage : SaaS multi-tenant où chaque client a sa propre DB.
9
+ //
10
+ // Author: Dr Hamid MADANI <drmdh@msn.com>
11
+
12
+ import {
13
+ createIsolatedDialect,
14
+ registerNamedConnection,
15
+ getNamedConnection,
16
+ listNamedConnections,
17
+ removeNamedConnection,
18
+ clearNamedConnections,
19
+ BaseRepository,
20
+ } from '@mostajs/orm'
21
+ import { UserSchema, type UserRow } from './schemas/user.schema.js'
22
+
23
+ async function main(): Promise<void> {
24
+ console.log('─── Isolated connections — @mostajs/orm ───')
25
+
26
+ // 1. Deux tenants = deux DB physiquement séparées. createIsolatedDialect
27
+ // bypass le singleton interne — chaque appel retourne une instance neuve.
28
+ const dialectA = await createIsolatedDialect(
29
+ { dialect: 'sqlite', uri: './tenant-a.db', schemaStrategy: 'update' },
30
+ [UserSchema],
31
+ )
32
+ console.log('✓ tenant-a connecté à ./tenant-a.db')
33
+
34
+ const dialectB = await createIsolatedDialect(
35
+ { dialect: 'sqlite', uri: './tenant-b.db', schemaStrategy: 'update' },
36
+ [UserSchema],
37
+ )
38
+ console.log('✓ tenant-b connecté à ./tenant-b.db')
39
+
40
+ // 2. Registre nommé pour récupérer une connexion par nom métier.
41
+ registerNamedConnection('tenant-a', dialectA)
42
+ registerNamedConnection('tenant-b', dialectB)
43
+ console.log('✓ named connections enregistrées :', listNamedConnections().join(', '))
44
+
45
+ // 3. Repositories tirés depuis les named connections.
46
+ const repoA = new BaseRepository<UserRow>(UserSchema, getNamedConnection('tenant-a')!)
47
+ const repoB = new BaseRepository<UserRow>(UserSchema, getNamedConnection('tenant-b')!)
48
+
49
+ // 4. Données différentes par tenant — preuve d'isolement.
50
+ await repoA.create({ email: `a-${Date.now()}@tenant-a.example.com`, name: 'Alice A' })
51
+ await repoB.create({ email: `b1-${Date.now()}@tenant-b.example.com`, name: 'Bob B1' })
52
+ await repoB.create({ email: `b2-${Date.now()}@tenant-b.example.com`, name: 'Bob B2' })
53
+
54
+ const countA = await repoA.count({})
55
+ const countB = await repoB.count({})
56
+ console.log(`✓ count tenant-a = ${countA}`)
57
+ console.log(`✓ count tenant-b = ${countB}`)
58
+
59
+ if (countA !== 1 || countB !== 2) {
60
+ throw new Error(`isolation assertion failed: A=${countA}, B=${countB} (expected 1, 2)`)
61
+ }
62
+ console.log('✓ DBs physiquement distinctes (count diffère)')
63
+
64
+ // 5. Cleanup — removeNamedConnection puis clearNamedConnections.
65
+ removeNamedConnection('tenant-a')
66
+ console.log(`✓ après remove tenant-a : ${listNamedConnections().join(', ') || '(vide)'}`)
67
+ clearNamedConnections()
68
+ console.log(`✓ après clearAll : ${listNamedConnections().length} connexions`)
69
+
70
+ console.log('✅ Smoke OK')
71
+
72
+ await dialectA.disconnect?.()
73
+ await dialectB.disconnect?.()
74
+ }
75
+
76
+ main().catch((err) => {
77
+ console.error('❌ Sample failed:', err)
78
+ process.exit(1)
79
+ })
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "03-isolated-connections",
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,23 @@
1
+ // Schéma User partagé entre les tenants — la séparation est au niveau
2
+ // DB physique, pas au niveau schéma.
3
+ // Author: Dr Hamid MADANI <drmdh@msn.com>
4
+
5
+ import type { EntitySchema } from '@mostajs/orm'
6
+
7
+ export const UserSchema: EntitySchema = {
8
+ name: 'User',
9
+ collection: 'users',
10
+ fields: {
11
+ email: { type: 'string', required: true, unique: true },
12
+ name: { type: 'string' },
13
+ },
14
+ relations: {},
15
+ indexes: [{ fields: { email: 'asc' }, unique: true }],
16
+ timestamps: true,
17
+ }
18
+
19
+ export interface UserRow {
20
+ id: string
21
+ email: string
22
+ name?: string
23
+ }
@@ -0,0 +1,2 @@
1
+ # Ce sample n'utilise PAS de dialect — le registre est purement en mémoire.
2
+ # Aucune variable d'environnement requise.
@@ -0,0 +1,10 @@
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
+ npx -y tsx app.ts
@@ -0,0 +1,56 @@
1
+ # 04-schema-registry
2
+
3
+ > Registre global de schémas : register / lookup / validate / clear, indépendant du dialect.
4
+
5
+ **Couvre** : `registerSchema`, `registerSchemas`, `getSchema`,
6
+ `getSchemaByCollection`, `getAllSchemas`, `getEntityNames`, `hasSchema`,
7
+ `validateSchemas`, `clearRegistry`.
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/04-schema-registry ~/my-registry-app
14
+ cd ~/my-registry-app
15
+ rm -rf ../tmp
16
+ ```
17
+
18
+ ## External resources
19
+
20
+ aucune.
21
+
22
+ ## Run
23
+
24
+ ```bash
25
+ ./04-schema-registry.sh
26
+ ```
27
+
28
+ ## Expected output
29
+
30
+ ```
31
+ ─── Schema registry — @mostajs/orm ───
32
+ ✓ 3 schémas enregistrés en batch : User, Project, Registration
33
+ ✓ getEntityNames() = [ 'User', 'Project', 'Registration' ]
34
+ ✓ hasSchema('User') = true
35
+ ✓ getSchema('User').collection = 'users'
36
+ ✓ getSchemaByCollection('projects').name = 'Project'
37
+ ✓ validateSchemas() = { valid: true, errors: [] }
38
+ ✓ clearRegistry() → 0 schémas restants
39
+ ✓ ré-registerSchema('Tag') → hasSchema('Tag') = true
40
+ ✅ Smoke OK
41
+ ```
42
+
43
+ ## What it shows
44
+
45
+ - `registerSchemas([…])` (batch) vs `registerSchema(s)` (single)
46
+ - 3 lookups : par nom, par collection, all
47
+ - `validateSchemas()` vérifie que les cibles de relations existent dans le registre
48
+ - Cycle complet : register → use → clear → re-register
49
+
50
+ ## Files
51
+
52
+ - `app.ts` — main code
53
+ - `schemas/` — 3 schémas (User, Project, Registration) avec relations
54
+ - `.env.example` — N/A (pas de DB pour ce sample)
55
+
56
+ **Author** : Dr Hamid MADANI <drmdh@msn.com>
@@ -0,0 +1,78 @@
1
+ // Schema registry — registre global indépendant du dialect.
2
+ //
3
+ // Démontre :
4
+ // - registerSchema(s) / registerSchemas([…])
5
+ // - getSchema, getSchemaByCollection, getAllSchemas, getEntityNames, hasSchema
6
+ // - validateSchemas (vérifie les cibles de relations)
7
+ // - clearRegistry + cycle de re-registration
8
+ //
9
+ // Pas besoin de connexion DB : le registre est purement en mémoire et
10
+ // peut être utilisé pour de l'introspection avant tout dialect.
11
+ //
12
+ // Author: Dr Hamid MADANI <drmdh@msn.com>
13
+
14
+ import {
15
+ registerSchema,
16
+ registerSchemas,
17
+ getSchema,
18
+ getSchemaByCollection,
19
+ getAllSchemas,
20
+ getEntityNames,
21
+ hasSchema,
22
+ validateSchemas,
23
+ clearRegistry,
24
+ } from '@mostajs/orm'
25
+ import { UserSchema, ProjectSchema, RegistrationSchema, TagSchema } from './schemas/index.js'
26
+
27
+ async function main(): Promise<void> {
28
+ console.log('─── Schema registry — @mostajs/orm ───')
29
+
30
+ // Bonne pratique : clear avant en cas de re-run dans la même process.
31
+ clearRegistry()
32
+
33
+ // 1. registerSchemas — batch.
34
+ registerSchemas([UserSchema, ProjectSchema, RegistrationSchema])
35
+ const names = getEntityNames()
36
+ console.log(`✓ 3 schémas enregistrés en batch : ${names.join(', ')}`)
37
+
38
+ if (names.length !== 3) throw new Error(`expected 3 schemas, got ${names.length}`)
39
+
40
+ // 2. getEntityNames — liste des noms enregistrés.
41
+ console.log('✓ getEntityNames() =', names)
42
+
43
+ // 3. hasSchema — check d'existence.
44
+ console.log(`✓ hasSchema('User') = ${hasSchema('User')}`)
45
+ if (!hasSchema('User')) throw new Error('User missing')
46
+
47
+ // 4. getSchema — lookup par nom (throw si absent).
48
+ console.log(`✓ getSchema('User').collection = '${getSchema('User').collection}'`)
49
+
50
+ // 5. getSchemaByCollection — lookup par table/collection name.
51
+ const byColl = getSchemaByCollection('projects')
52
+ console.log(`✓ getSchemaByCollection('projects').name = '${byColl?.name}'`)
53
+
54
+ // 6. getAllSchemas — récupère tous les schémas pour iteration.
55
+ const all = getAllSchemas()
56
+ if (all.length !== 3) throw new Error(`getAllSchemas count mismatch: ${all.length}`)
57
+
58
+ // 7. validateSchemas — vérifie que les `target` des relations existent.
59
+ const validation = validateSchemas()
60
+ console.log('✓ validateSchemas() =', validation)
61
+ if (!validation.valid) throw new Error(`validation failed: ${validation.errors.join(', ')}`)
62
+
63
+ // 8. clearRegistry — vide tout. Utile en tests, dans les hot-reload, etc.
64
+ clearRegistry()
65
+ console.log(`✓ clearRegistry() → ${getEntityNames().length} schémas restants`)
66
+ if (getEntityNames().length !== 0) throw new Error('clearRegistry failed')
67
+
68
+ // 9. registerSchema unitaire — alternative au batch.
69
+ registerSchema(TagSchema)
70
+ console.log(`✓ ré-registerSchema('Tag') → hasSchema('Tag') = ${hasSchema('Tag')}`)
71
+
72
+ console.log('✅ Smoke OK')
73
+ }
74
+
75
+ main().catch((err) => {
76
+ console.error('❌ Sample failed:', err)
77
+ process.exit(1)
78
+ })
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "04-schema-registry",
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
+ },
12
+ "devDependencies": {
13
+ "tsx": "^4.0.0",
14
+ "typescript": "^5.6.0",
15
+ "@types/node": "^22.0.0"
16
+ }
17
+ }
@@ -0,0 +1,35 @@
1
+ // 3 schémas avec relations croisées pour démontrer validateSchemas() :
2
+ // User ← Project (many-to-one author) ← Registration (many-to-one project).
3
+ // Author: Dr Hamid MADANI <drmdh@msn.com>
4
+
5
+ import type { EntitySchema } from '@mostajs/orm'
6
+
7
+ export const UserSchema: EntitySchema = {
8
+ name: 'User', collection: 'users',
9
+ fields: { email: { type: 'string', required: true, unique: true } },
10
+ relations: {}, indexes: [], timestamps: true,
11
+ }
12
+
13
+ export const ProjectSchema: EntitySchema = {
14
+ name: 'Project', collection: 'projects',
15
+ fields: { name: { type: 'string', required: true } },
16
+ relations: {
17
+ author: { type: 'many-to-one', target: 'User', onDelete: 'set-null' },
18
+ },
19
+ indexes: [], timestamps: true,
20
+ }
21
+
22
+ export const RegistrationSchema: EntitySchema = {
23
+ name: 'Registration', collection: 'registrations',
24
+ fields: { code: { type: 'string', required: true } },
25
+ relations: {
26
+ project: { type: 'many-to-one', target: 'Project', onDelete: 'cascade' },
27
+ },
28
+ indexes: [], timestamps: true,
29
+ }
30
+
31
+ export const TagSchema: EntitySchema = {
32
+ name: 'Tag', collection: 'tags',
33
+ fields: { label: { type: 'string', required: true, unique: true } },
34
+ relations: {}, indexes: [], timestamps: true,
35
+ }
@@ -0,0 +1,7 @@
1
+ # Default — SQLite local, zéro install externe.
2
+ DB_DIALECT=sqlite
3
+ SGBD_URI=./app.db
4
+
5
+ # Note : ce sample illustre les TYPES de field/index ; le dialect importe
6
+ # peu car la définition est portable. Sur Postgres/MySQL les types SQL
7
+ # précis (TEXT vs VARCHAR, JSONB vs JSON…) diffèrent automatiquement.
@@ -0,0 +1,12 @@
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
+ rm -f app.db
11
+
12
+ npx -y tsx app.ts
@@ -0,0 +1,60 @@
1
+ # 05-types-cles-entity-schema
2
+
3
+ > Tous les types-clés EntitySchema démontrés : chaque FieldType, chaque FieldDef option, IndexDef, discriminator, softDelete.
4
+
5
+ **Couvre** : `EntitySchema` exhaustif, `FieldDef` *(required, unique, sparse,
6
+ default, enum, lowercase, trim, arrayOf)*, `FieldType`
7
+ *(string, text, number, boolean, date, json, array)*, `EmbeddedSchemaDef`,
8
+ `IndexDef`, `IndexType` *(asc, desc, text)*, `discriminator`,
9
+ `discriminatorValue`, `softDelete`, `timestamps`.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ mkdir tmp && cd tmp && npm init -y && npm install @mostajs/orm-samples
15
+ cp -r node_modules/@mostajs/orm-samples/examples/05-types-cles-entity-schema ~/my-types-app
16
+ cd ~/my-types-app
17
+ rm -rf ../tmp
18
+ ```
19
+
20
+ ## External resources
21
+
22
+ aucune *(SQLite via better-sqlite3)*.
23
+
24
+ ## Run
25
+
26
+ ```bash
27
+ ./05-types-cles-entity-schema.sh
28
+ ```
29
+
30
+ ## Expected output
31
+
32
+ ```
33
+ ─── Types clés EntitySchema — @mostajs/orm ───
34
+ ✓ Schéma Article enregistré (softDelete=true, discriminator='_type')
35
+ ✓ FieldType démontrés : string, text, number, boolean, date, json, array
36
+ ✓ FieldDef options démontrées : required, unique, default, enum, lowercase, trim, arrayOf
37
+ ✓ IndexDef : 4 indexes dont 1 unique+sparse, 1 desc, 1 text, 1 composite
38
+ ✓ Article créé avec id=… title='Hello' status='draft' (enum default)
39
+ ✓ slug lowercase appliqué : 'hello-world' (input était 'Hello-World')
40
+ ✓ tags arrayOf string OK : [ 'one', 'two', 'three' ]
41
+ ✓ metadata JSON OK : { meta: 'sample' }
42
+ ✓ Soft-delete : count={ active: 0, total: 1 } après delete
43
+ ✅ Smoke OK
44
+ ```
45
+
46
+ ## What it shows
47
+
48
+ - Un seul schéma `Article` qui exerce **chaque field type, chaque option
49
+ FieldDef, chaque type d'index**
50
+ - `discriminator` (single-table inheritance Drupal-style) + `discriminatorValue`
51
+ - `softDelete: true` natif + index `sparse: true` cohérent
52
+ - Validation runtime des transformations : `lowercase`, `trim`, `enum default`
53
+
54
+ ## Files
55
+
56
+ - `app.ts` — main code avec assertions sur chaque option
57
+ - `schemas/article.schema.ts` — le schéma exhaustif
58
+ - `.env.example` — config SQLite
59
+
60
+ **Author** : Dr Hamid MADANI <drmdh@msn.com>