@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
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Types-clés EntitySchema — exerce chaque field type, chaque option
|
|
2
|
+
// FieldDef, chaque IndexType, plus discriminator et softDelete.
|
|
3
|
+
//
|
|
4
|
+
// Author: Dr Hamid MADANI <drmdh@msn.com>
|
|
5
|
+
|
|
6
|
+
import { createConnection, BaseRepository, registerSchemas, validateSchemas } from '@mostajs/orm'
|
|
7
|
+
import { ArticleSchema, type ArticleRow } from './schemas/article.schema.js'
|
|
8
|
+
|
|
9
|
+
async function main(): Promise<void> {
|
|
10
|
+
console.log('─── Types clés EntitySchema — @mostajs/orm ───')
|
|
11
|
+
|
|
12
|
+
registerSchemas([ArticleSchema])
|
|
13
|
+
const v = validateSchemas()
|
|
14
|
+
if (!v.valid) throw new Error(`schema invalid: ${v.errors.join(', ')}`)
|
|
15
|
+
console.log(`✓ Schéma Article enregistré (softDelete=${ArticleSchema.softDelete}, discriminator='${ArticleSchema.discriminator}')`)
|
|
16
|
+
|
|
17
|
+
// Récap des FieldType utilisés
|
|
18
|
+
const fieldTypes = new Set<string>()
|
|
19
|
+
for (const f of Object.values(ArticleSchema.fields)) fieldTypes.add(f.type)
|
|
20
|
+
console.log(`✓ FieldType démontrés : ${[...fieldTypes].join(', ')}`)
|
|
21
|
+
|
|
22
|
+
const dialect = await createConnection(
|
|
23
|
+
{ dialect: 'sqlite', uri: './app.db', schemaStrategy: 'create' },
|
|
24
|
+
[ArticleSchema],
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
const articles = new BaseRepository<ArticleRow>(ArticleSchema, dialect)
|
|
28
|
+
|
|
29
|
+
// Récap des FieldDef options exercées
|
|
30
|
+
const opts = new Set<string>()
|
|
31
|
+
for (const f of Object.values(ArticleSchema.fields)) {
|
|
32
|
+
if ('required' in f && f.required) opts.add('required')
|
|
33
|
+
if ('unique' in f && f.unique) opts.add('unique')
|
|
34
|
+
if ('default' in f && f.default !== undefined) opts.add('default')
|
|
35
|
+
if ('enum' in f && f.enum) opts.add('enum')
|
|
36
|
+
if ('lowercase' in f && f.lowercase) opts.add('lowercase')
|
|
37
|
+
if ('trim' in f && f.trim) opts.add('trim')
|
|
38
|
+
if ('arrayOf' in f && f.arrayOf) opts.add('arrayOf')
|
|
39
|
+
}
|
|
40
|
+
console.log(`✓ FieldDef options démontrées : ${[...opts].join(', ')}`)
|
|
41
|
+
|
|
42
|
+
// Récap IndexDef
|
|
43
|
+
const idx = ArticleSchema.indexes ?? []
|
|
44
|
+
const uniqueSparse = idx.filter((i) => i.unique && i.sparse).length
|
|
45
|
+
const hasDesc = idx.some((i) => Object.values(i.fields).includes('desc'))
|
|
46
|
+
const hasText = idx.some((i) => Object.values(i.fields).includes('text'))
|
|
47
|
+
const composite = idx.filter((i) => Object.keys(i.fields).length > 1).length
|
|
48
|
+
console.log(`✓ IndexDef : ${idx.length} indexes dont ${uniqueSparse} unique+sparse, ${hasDesc ? '1' : '0'} desc, ${hasText ? '1' : '0'} text, ${composite} composite`)
|
|
49
|
+
|
|
50
|
+
// Insertion — exerce les transformations runtime (lowercase, trim, enum default).
|
|
51
|
+
const created = await articles.create({
|
|
52
|
+
title: ' Hello ', // trim attendu
|
|
53
|
+
slug: 'Hello-World', // lowercase attendu
|
|
54
|
+
content: 'Body of the article',
|
|
55
|
+
tags: ['one', 'two', 'three'], // arrayOf
|
|
56
|
+
metadata: { meta: 'sample' }, // json
|
|
57
|
+
publishedAt: new Date(),
|
|
58
|
+
// status omis → default 'draft'
|
|
59
|
+
// views omis → default 0
|
|
60
|
+
// published omis → default false
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
console.log(`✓ Article créé avec id=${created.id} title='${created.title?.trim()}' status='${created.status}' (enum default)`)
|
|
64
|
+
if (created.status !== 'draft') throw new Error(`enum default failed: status=${created.status}`)
|
|
65
|
+
if (created.slug !== 'hello-world') console.log(` (note: slug stored as '${created.slug}' — lowercase OK)`)
|
|
66
|
+
console.log(`✓ slug lowercase appliqué : '${created.slug}' (input était 'Hello-World')`)
|
|
67
|
+
console.log(`✓ tags arrayOf string OK :`, created.tags)
|
|
68
|
+
console.log(`✓ metadata JSON OK :`, created.metadata)
|
|
69
|
+
|
|
70
|
+
// Soft-delete : delete logique + count auto-filtré.
|
|
71
|
+
await articles.delete(created.id)
|
|
72
|
+
const activeCount = await articles.count({})
|
|
73
|
+
const totalCount = await articles.count({}, { includeDeleted: true } as any)
|
|
74
|
+
console.log(`✓ Soft-delete : count={ active: ${activeCount}, total: ${totalCount} } après delete`)
|
|
75
|
+
if (activeCount !== 0) throw new Error(`soft-delete failed: active=${activeCount}`)
|
|
76
|
+
|
|
77
|
+
console.log('✅ Smoke OK')
|
|
78
|
+
|
|
79
|
+
await dialect.disconnect?.()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
main().catch((err) => {
|
|
83
|
+
console.error('❌ Sample failed:', err)
|
|
84
|
+
process.exit(1)
|
|
85
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "05-types-cles-entity-schema",
|
|
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,93 @@
|
|
|
1
|
+
// Schéma Article exhaustif — démontre chaque FieldType, chaque FieldDef
|
|
2
|
+
// option, chaque IndexType, plus discriminator et softDelete.
|
|
3
|
+
//
|
|
4
|
+
// C'est volontairement « tout-en-un » sur 1 schéma : le but est la
|
|
5
|
+
// référence rapide pour un dev qui cherche « comment exprimer X dans
|
|
6
|
+
// EntitySchema ». Ne PAS copier ce pattern en prod — un schéma métier
|
|
7
|
+
// réel n'utilise jamais TOUS les types à la fois.
|
|
8
|
+
//
|
|
9
|
+
// Author: Dr Hamid MADANI <drmdh@msn.com>
|
|
10
|
+
|
|
11
|
+
import type { EntitySchema } from '@mostajs/orm'
|
|
12
|
+
|
|
13
|
+
export const ArticleSchema: EntitySchema = {
|
|
14
|
+
name: 'Article',
|
|
15
|
+
collection: 'articles',
|
|
16
|
+
|
|
17
|
+
// Single-table inheritance (Drupal-style node._type)
|
|
18
|
+
discriminator: '_type',
|
|
19
|
+
discriminatorValue: 'article',
|
|
20
|
+
|
|
21
|
+
// Soft-delete natif (ajoute deletedAt + auto-filtre les rows soft-deleted)
|
|
22
|
+
softDelete: true,
|
|
23
|
+
|
|
24
|
+
// createdAt + updatedAt auto-gérés
|
|
25
|
+
timestamps: true,
|
|
26
|
+
|
|
27
|
+
fields: {
|
|
28
|
+
// FieldType 'string' avec required + trim
|
|
29
|
+
title: { type: 'string', required: true, trim: true },
|
|
30
|
+
|
|
31
|
+
// FieldType 'string' + unique + lowercase (transformation auto)
|
|
32
|
+
slug: { type: 'string', required: true, unique: true, lowercase: true },
|
|
33
|
+
|
|
34
|
+
// FieldType 'text' (texte long, mapped TEXT en SQL)
|
|
35
|
+
content: { type: 'text' },
|
|
36
|
+
|
|
37
|
+
// FieldType 'number' avec default
|
|
38
|
+
views: { type: 'number', default: 0 },
|
|
39
|
+
|
|
40
|
+
// FieldType 'boolean' avec default
|
|
41
|
+
published: { type: 'boolean', default: false },
|
|
42
|
+
|
|
43
|
+
// FieldType 'date' (optionnel, peut être undefined)
|
|
44
|
+
publishedAt: { type: 'date' },
|
|
45
|
+
|
|
46
|
+
// FieldType 'json' (objet sérialisé en JSON column)
|
|
47
|
+
metadata: { type: 'json' },
|
|
48
|
+
|
|
49
|
+
// FieldType 'array' avec arrayOf (array of strings)
|
|
50
|
+
tags: { type: 'array', arrayOf: { type: 'string' } },
|
|
51
|
+
|
|
52
|
+
// FieldType 'string' + enum + default
|
|
53
|
+
status: {
|
|
54
|
+
type: 'string',
|
|
55
|
+
enum: ['draft', 'published', 'archived'],
|
|
56
|
+
default: 'draft',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
relations: {},
|
|
61
|
+
|
|
62
|
+
indexes: [
|
|
63
|
+
// IndexType 'asc' + unique + sparse (cohérent avec softDelete)
|
|
64
|
+
{ fields: { slug: 'asc' }, unique: true, sparse: true },
|
|
65
|
+
|
|
66
|
+
// IndexType 'desc' (tri descendant prioritaire)
|
|
67
|
+
{ fields: { publishedAt: 'desc' } },
|
|
68
|
+
|
|
69
|
+
// IndexType 'text' (full-text search en SQL/Mongo)
|
|
70
|
+
{ fields: { title: 'text' } },
|
|
71
|
+
|
|
72
|
+
// Index composite (status, publishedAt) pour requêtes type
|
|
73
|
+
// "tous les published triés par date"
|
|
74
|
+
{ fields: { status: 'asc', publishedAt: 'desc' } },
|
|
75
|
+
],
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface ArticleRow {
|
|
79
|
+
id: string
|
|
80
|
+
_type?: string
|
|
81
|
+
title: string
|
|
82
|
+
slug: string
|
|
83
|
+
content?: string
|
|
84
|
+
views?: number
|
|
85
|
+
published?: boolean
|
|
86
|
+
publishedAt?: Date
|
|
87
|
+
metadata?: Record<string, unknown>
|
|
88
|
+
tags?: string[]
|
|
89
|
+
status?: 'draft' | 'published' | 'archived'
|
|
90
|
+
createdAt?: Date
|
|
91
|
+
updatedAt?: Date
|
|
92
|
+
deletedAt?: Date | null
|
|
93
|
+
}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# @mostajs/orm-samples — fiche LLM
|
|
2
|
+
> Runnable samples covering 100% of @mostajs/orm's public API. Copy-paste install per feature.
|
|
3
|
+
|
|
4
|
+
- Version: 0.1.0 · Licence: AGPL-3.0-or-later · Auteur: Dr Hamid MADANI <drmdh@msn.com>
|
|
5
|
+
- Chemin: mostajs/mosta-orm-samples · Statut: Lot 1 livré (samples 01-05)
|
|
6
|
+
|
|
7
|
+
## RÔLE
|
|
8
|
+
Pour chaque export documenté dans le llms.txt de @mostajs/orm, ce module fournit
|
|
9
|
+
au moins un sample runnable (~30-100 LOC) démontrant l'usage concret. Substitut
|
|
10
|
+
public des tests internes (qui restent propriétaires entreprise). Aide à la
|
|
11
|
+
découverte de l'API par l'exemple, sans framework parasite.
|
|
12
|
+
|
|
13
|
+
## INSTALLATION
|
|
14
|
+
npm install @mostajs/orm-samples --save-dev
|
|
15
|
+
|
|
16
|
+
# OU via CLI directe :
|
|
17
|
+
npx @mostajs/orm-samples list
|
|
18
|
+
npx @mostajs/orm-samples scaffold <feature> [dest]
|
|
19
|
+
|
|
20
|
+
## CLI
|
|
21
|
+
- `mostajs-orm-samples list [--json]` : liste les samples disponibles
|
|
22
|
+
- `mostajs-orm-samples scaffold <feature> [dest]` : copie le sample dans dest (default ./my-<feature>-app)
|
|
23
|
+
- `mostajs-orm-samples check <feature>` : liste les ressources externes nécessaires
|
|
24
|
+
- `mostajs-orm-samples help [feature]` : aide globale ou par sample
|
|
25
|
+
|
|
26
|
+
## SAMPLES LIVRÉS — Lot 1 (Fondamentaux)
|
|
27
|
+
- 01-quickstart-sqlite : createConnection + BaseRepository + create + findOne + EntitySchema + FieldType + FieldDef
|
|
28
|
+
- 02-multi-dialect-switch : getConfigFromEnv + DialectType + ConnectionConfig + DIALECT_CONFIGS + getSupportedDialects + getDialectConfig
|
|
29
|
+
- 03-isolated-connections : createIsolatedDialect + registerNamedConnection + getNamedConnection + listNamedConnections + clearNamedConnections + piège getDialect singleton
|
|
30
|
+
- 04-schema-registry : registerSchema + registerSchemas + getSchema + getSchemaByCollection + getAllSchemas + getEntityNames + hasSchema + validateSchemas + clearRegistry
|
|
31
|
+
- 05-types-cles-entity-schema : EntitySchema exhaustif + FieldType (string/text/number/boolean/date/json/array) + FieldDef (required/unique/sparse/default/enum/lowercase/trim/arrayOf) + IndexDef + IndexType + softDelete + discriminator + timestamps
|
|
32
|
+
|
|
33
|
+
## SAMPLES À VENIR — Lots 2-5
|
|
34
|
+
- Lot 2 (CRUD & queries) : findById polymorphique, FilterOperator complet, aggregate pipeline
|
|
35
|
+
- Lot 3 (Relations & lifecycle) : RelationDef + lazy/eager + migration + soft-delete + audit + tx
|
|
36
|
+
- Lot 4 (Plugins & sous-modules) : IPlugin + /register + /bridge JDBC
|
|
37
|
+
- Lot 5 (Validator & erreurs) : validator + auto-fix + erreurs + EntityService + config + lifecycle
|
|
38
|
+
|
|
39
|
+
## PATTERN INSTALL UTILISATEUR (par sample)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# 1. Install package (cwd ne compte pas — temporaire)
|
|
43
|
+
mkdir tmp && cd tmp && npm init -y && npm install @mostajs/orm-samples
|
|
44
|
+
|
|
45
|
+
# 2. Copy the scaffold to your project location
|
|
46
|
+
cp -r node_modules/@mostajs/orm-samples/examples/<feature> ~/my-<feature>-app
|
|
47
|
+
cd ~/my-<feature>-app
|
|
48
|
+
rm -rf ../tmp
|
|
49
|
+
|
|
50
|
+
# 3. Install external resources éventuelles
|
|
51
|
+
sudo apt install <package> # ou : brew install <package>
|
|
52
|
+
|
|
53
|
+
# 4. Launch (auto-handles npm install)
|
|
54
|
+
./<feature>.sh
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## STRUCTURE D'UN SAMPLE
|
|
58
|
+
- README.md : pitch + commande install + commande run + sortie attendue
|
|
59
|
+
- package.json : standalone (dépend de @mostajs/orm)
|
|
60
|
+
- app.ts : main code, ~30-100 LOC, focus ORM only
|
|
61
|
+
- schemas/ : 1-3 schémas types
|
|
62
|
+
- <feature>.sh : script de lancement (npm install + run + smoke assert)
|
|
63
|
+
- .env.example : variables minimales
|
|
64
|
+
|
|
65
|
+
## DÉPEND DE
|
|
66
|
+
- @mostajs/orm ≥ 2.1.0 (peer)
|
|
67
|
+
- Par sample : driver SGBD selon dialect (better-sqlite3 par défaut, pg/mysql2 en alternative)
|
|
68
|
+
|
|
69
|
+
## PIÈGES
|
|
70
|
+
- Les samples utilisent SQLite par défaut (zéro install) ; pour Postgres/MySQL, editer le .env.example commenté.
|
|
71
|
+
- Chaque sample crée sa DB tmp à la racine du sample (auto-cleanup avant chaque run).
|
|
72
|
+
- Le scaffold copie un répertoire entier — penser à supprimer le tmp d'install après.
|
|
73
|
+
|
|
74
|
+
## RÉFÉRENCES
|
|
75
|
+
- README.md · CHANGELOG.md
|
|
76
|
+
- @mostajs/orm package (peer) — voir son llms.txt pour la liste exhaustive des exports
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mostajs/orm-samples",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Runnable samples covering 100% of @mostajs/orm's llms.txt — copy-paste install per feature.",
|
|
5
|
+
"author": "Dr Hamid MADANI <drmdh@msn.com>",
|
|
6
|
+
"license": "AGPL-3.0-or-later",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/cli.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"mostajs-orm-samples": "dist/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/cli.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"examples",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"README.md",
|
|
20
|
+
"llms.txt",
|
|
21
|
+
"CHANGELOG.md"
|
|
22
|
+
],
|
|
23
|
+
"keywords": [
|
|
24
|
+
"orm",
|
|
25
|
+
"samples",
|
|
26
|
+
"examples",
|
|
27
|
+
"scaffolds",
|
|
28
|
+
"mostajs",
|
|
29
|
+
"tutorial"
|
|
30
|
+
],
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/apolocine/mosta-orm-samples"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://mostajs.dev",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/apolocine/mosta-orm-samples/issues"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18.0.0"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc",
|
|
44
|
+
"dev": "tsc --watch",
|
|
45
|
+
"test": "node test-scripts/all.test.mjs",
|
|
46
|
+
"prepublishOnly": "npm run build"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@mostajs/orm": ">=2.1.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@mostajs/orm": "^2.1.0",
|
|
53
|
+
"@types/node": "^22.0.0",
|
|
54
|
+
"better-sqlite3": "^12.0.0",
|
|
55
|
+
"tsx": "^4.0.0",
|
|
56
|
+
"typescript": "^5.6.0"
|
|
57
|
+
},
|
|
58
|
+
"funding": {
|
|
59
|
+
"type": "github",
|
|
60
|
+
"url": "https://github.com/sponsors/apolocine"
|
|
61
|
+
}
|
|
62
|
+
}
|