@stonyx/orm 0.2.1-beta.9 → 0.2.1-beta.91
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 +64 -6
- package/config/environment.js +37 -1
- package/dist/aggregates.d.ts +21 -0
- package/dist/aggregates.js +93 -0
- package/dist/attr.d.ts +2 -0
- package/dist/attr.js +22 -0
- package/dist/belongs-to.d.ts +11 -0
- package/dist/belongs-to.js +59 -0
- package/dist/cli.d.ts +22 -0
- package/dist/cli.js +148 -0
- package/dist/commands.d.ts +7 -0
- package/dist/commands.js +146 -0
- package/dist/db.d.ts +21 -0
- package/dist/db.js +180 -0
- package/dist/exports/db.d.ts +7 -0
- package/{src → dist}/exports/db.js +2 -4
- package/dist/has-many.d.ts +11 -0
- package/dist/has-many.js +58 -0
- package/dist/hooks.d.ts +75 -0
- package/dist/hooks.js +110 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +34 -0
- package/dist/main.d.ts +46 -0
- package/dist/main.js +181 -0
- package/dist/manage-record.d.ts +13 -0
- package/dist/manage-record.js +123 -0
- package/dist/meta-request.d.ts +6 -0
- package/dist/meta-request.js +52 -0
- package/dist/migrate.d.ts +2 -0
- package/dist/migrate.js +57 -0
- package/dist/model-property.d.ts +9 -0
- package/dist/model-property.js +29 -0
- package/dist/model.d.ts +15 -0
- package/dist/model.js +18 -0
- package/dist/mysql/connection.d.ts +14 -0
- package/dist/mysql/connection.js +24 -0
- package/dist/mysql/migration-generator.d.ts +45 -0
- package/dist/mysql/migration-generator.js +254 -0
- package/dist/mysql/migration-runner.d.ts +12 -0
- package/dist/mysql/migration-runner.js +88 -0
- package/dist/mysql/mysql-db.d.ts +100 -0
- package/dist/mysql/mysql-db.js +425 -0
- package/dist/mysql/query-builder.d.ts +10 -0
- package/dist/mysql/query-builder.js +44 -0
- package/dist/mysql/schema-introspector.d.ts +19 -0
- package/dist/mysql/schema-introspector.js +257 -0
- package/dist/mysql/type-map.d.ts +21 -0
- package/dist/mysql/type-map.js +36 -0
- package/dist/orm-request.d.ts +38 -0
- package/dist/orm-request.js +475 -0
- package/dist/plural-registry.d.ts +4 -0
- package/dist/plural-registry.js +9 -0
- package/dist/postgres/connection.d.ts +15 -0
- package/dist/postgres/connection.js +32 -0
- package/dist/postgres/migration-generator.d.ts +45 -0
- package/dist/postgres/migration-generator.js +261 -0
- package/dist/postgres/migration-runner.d.ts +10 -0
- package/dist/postgres/migration-runner.js +87 -0
- package/dist/postgres/postgres-db.d.ts +119 -0
- package/dist/postgres/postgres-db.js +477 -0
- package/dist/postgres/query-builder.d.ts +27 -0
- package/dist/postgres/query-builder.js +98 -0
- package/dist/postgres/schema-introspector.d.ts +28 -0
- package/dist/postgres/schema-introspector.js +280 -0
- package/dist/postgres/type-map.d.ts +23 -0
- package/dist/postgres/type-map.js +56 -0
- package/dist/record.d.ts +75 -0
- package/dist/record.js +129 -0
- package/dist/relationships.d.ts +10 -0
- package/dist/relationships.js +41 -0
- package/dist/schema-helpers.d.ts +20 -0
- package/dist/schema-helpers.js +48 -0
- package/dist/serializer.d.ts +17 -0
- package/dist/serializer.js +136 -0
- package/dist/setup-rest-server.d.ts +1 -0
- package/dist/setup-rest-server.js +52 -0
- package/dist/standalone-db.d.ts +58 -0
- package/dist/standalone-db.js +142 -0
- package/dist/store.d.ts +62 -0
- package/dist/store.js +286 -0
- package/dist/timescale/query-builder.d.ts +43 -0
- package/dist/timescale/query-builder.js +115 -0
- package/dist/timescale/timescale-db.d.ts +45 -0
- package/dist/timescale/timescale-db.js +84 -0
- package/dist/transforms.d.ts +2 -0
- package/dist/transforms.js +17 -0
- package/dist/types/orm-types.d.ts +142 -0
- package/dist/types/orm-types.js +1 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +17 -0
- package/dist/view-resolver.d.ts +8 -0
- package/dist/view-resolver.js +171 -0
- package/dist/view.d.ts +11 -0
- package/dist/view.js +18 -0
- package/package.json +57 -15
- package/src/aggregates.ts +109 -0
- package/src/{attr.js → attr.ts} +2 -2
- package/src/belongs-to.ts +90 -0
- package/src/cli.ts +183 -0
- package/src/{commands.js → commands.ts} +179 -170
- package/src/{db.js → db.ts} +55 -29
- package/src/exports/db.ts +7 -0
- package/src/has-many.ts +92 -0
- package/src/hooks.ts +151 -0
- package/src/{index.js → index.ts} +11 -2
- package/src/main.ts +229 -0
- package/src/manage-record.ts +161 -0
- package/src/{meta-request.js → meta-request.ts} +17 -14
- package/src/{migrate.js → migrate.ts} +9 -9
- package/src/model-property.ts +35 -0
- package/src/model.ts +21 -0
- package/src/mysql/{connection.js → connection.ts} +43 -28
- package/src/mysql/migration-generator.ts +337 -0
- package/src/mysql/{migration-runner.js → migration-runner.ts} +121 -110
- package/src/mysql/mysql-db.ts +543 -0
- package/src/mysql/{query-builder.js → query-builder.ts} +69 -64
- package/src/mysql/schema-introspector.ts +310 -0
- package/src/mysql/{type-map.js → type-map.ts} +42 -37
- package/src/{orm-request.js → orm-request.ts} +187 -108
- package/src/plural-registry.ts +12 -0
- package/src/postgres/connection.ts +48 -0
- package/src/postgres/migration-generator.ts +348 -0
- package/src/postgres/migration-runner.ts +115 -0
- package/src/postgres/postgres-db.ts +616 -0
- package/src/postgres/query-builder.ts +148 -0
- package/src/postgres/schema-introspector.ts +343 -0
- package/src/postgres/type-map.ts +61 -0
- package/src/record.ts +186 -0
- package/src/relationships.ts +54 -0
- package/src/schema-helpers.ts +59 -0
- package/src/serializer.ts +161 -0
- package/src/{setup-rest-server.js → setup-rest-server.ts} +18 -16
- package/src/standalone-db.ts +185 -0
- package/src/store.ts +373 -0
- package/src/timescale/query-builder.ts +174 -0
- package/src/timescale/timescale-db.ts +119 -0
- package/src/transforms.ts +20 -0
- package/src/types/mysql2.d.ts +49 -0
- package/src/types/orm-types.ts +146 -0
- package/src/types/pg.d.ts +32 -0
- package/src/types/stonyx-cron.d.ts +5 -0
- package/src/types/stonyx-events.d.ts +4 -0
- package/src/types/stonyx-rest-server.d.ts +16 -0
- package/src/types/stonyx-utils.d.ts +33 -0
- package/src/types/stonyx.d.ts +21 -0
- package/src/utils.ts +22 -0
- package/src/view-resolver.ts +211 -0
- package/src/view.ts +22 -0
- package/.claude/code-style-rules.md +0 -44
- package/.claude/hooks.md +0 -250
- package/.claude/index.md +0 -279
- package/.claude/usage-patterns.md +0 -217
- package/.github/workflows/ci.yml +0 -16
- package/.github/workflows/publish.yml +0 -51
- package/improvements.md +0 -139
- package/project-structure.md +0 -343
- package/src/belongs-to.js +0 -63
- package/src/has-many.js +0 -61
- package/src/hooks.js +0 -124
- package/src/main.js +0 -148
- package/src/manage-record.js +0 -118
- package/src/model-property.js +0 -29
- package/src/model.js +0 -9
- package/src/mysql/migration-generator.js +0 -188
- package/src/mysql/mysql-db.js +0 -320
- package/src/mysql/schema-introspector.js +0 -158
- package/src/record.js +0 -127
- package/src/relationships.js +0 -43
- package/src/serializer.js +0 -138
- package/src/store.js +0 -211
- package/src/transforms.js +0 -20
- package/src/utils.js +0 -12
- package/test-events-setup.js +0 -41
- package/test-hooks-manual.js +0 -54
- package/test-hooks-with-logging.js +0 -52
package/.claude/index.md
DELETED
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
# Stonyx-ORM Guide for Claude
|
|
2
|
-
|
|
3
|
-
## Detailed Guides
|
|
4
|
-
|
|
5
|
-
- [Usage Patterns](usage-patterns.md) — Model definitions, serializers, transforms, CRUD, DB schema, persistence, access control, REST API, and include parameters
|
|
6
|
-
- [Middleware Hooks System](hooks.md) — Before/after hooks for CRUD operations, halting, context object, change detection, and testing
|
|
7
|
-
- [Code Style Rules](code-style-rules.md) — Strict prettier/eslint rules to apply across all Stonyx projects
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Project Overview
|
|
12
|
-
|
|
13
|
-
**stonyx-orm** is a lightweight Object-Relational Mapping (ORM) library designed specifically for the Stonyx framework. It provides structured data modeling, relationship management, serialization, and persistence to JSON files, with optional REST API integration.
|
|
14
|
-
|
|
15
|
-
## Core Problem It Solves
|
|
16
|
-
|
|
17
|
-
1. **Data Modeling**: Clean, type-safe model definitions with attributes and relationships
|
|
18
|
-
2. **Data Serialization**: Transforms messy third-party data into structured model instances
|
|
19
|
-
3. **Relationship Management**: Automatic bidirectional relationships (hasMany, belongsTo)
|
|
20
|
-
4. **Data Persistence**: File-based JSON storage with auto-save
|
|
21
|
-
5. **REST API Generation**: Auto-generated RESTful endpoints with access control
|
|
22
|
-
6. **Data Transformation**: Custom type conversion and formatting
|
|
23
|
-
7. **Middleware Hooks**: Before/after hooks for all CRUD operations with halting capability
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## Architecture Overview
|
|
28
|
-
|
|
29
|
-
### Key Components
|
|
30
|
-
|
|
31
|
-
1. **Orm** ([src/main.js](src/main.js)) - Singleton that initializes and manages the entire system
|
|
32
|
-
2. **Store** ([src/store.js](src/store.js)) - In-memory storage (nested Maps: `Map<modelName, Map<recordId, record>>`)
|
|
33
|
-
3. **Model** ([src/model.js](src/model.js)) - Base class for all models
|
|
34
|
-
4. **Record** ([src/record.js](src/record.js)) - Individual model instances
|
|
35
|
-
5. **Serializer** ([src/serializer.js](src/serializer.js)) - Maps raw data to model format
|
|
36
|
-
6. **DB** ([src/db.js](src/db.js)) - JSON file persistence layer
|
|
37
|
-
7. **Relationships** ([src/has-many.js](src/has-many.js), [src/belongs-to.js](src/belongs-to.js)) - Relationship handlers
|
|
38
|
-
8. **Include Logic** (inline in [src/orm-request.js](src/orm-request.js)) - Parses include query params, traverses relationships, collects and deduplicates included records
|
|
39
|
-
9. **Hooks** ([src/hooks.js](src/hooks.js)) - Middleware-based hook registry for CRUD lifecycle
|
|
40
|
-
10. **MySQL Driver** ([src/mysql/mysql-db.js](src/mysql/mysql-db.js)) - MySQL persistence, migrations, schema introspection. Loads records in topological order. `_rowToRawData()` converts TINYINT(1) → boolean, remaps FK columns, strips timestamps.
|
|
41
|
-
|
|
42
|
-
### Project Structure
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
stonyx-orm/
|
|
46
|
-
├── src/
|
|
47
|
-
│ ├── index.js # Main exports (includes hook functions)
|
|
48
|
-
│ ├── main.js # Orm class
|
|
49
|
-
│ ├── model.js # Base Model
|
|
50
|
-
│ ├── record.js # Record instances
|
|
51
|
-
│ ├── serializer.js # Base Serializer
|
|
52
|
-
│ ├── store.js # In-memory storage
|
|
53
|
-
│ ├── db.js # JSON persistence
|
|
54
|
-
│ ├── attr.js # Attribute helper (Proxy-based)
|
|
55
|
-
│ ├── has-many.js # One-to-many relationships
|
|
56
|
-
│ ├── belongs-to.js # Many-to-one relationships
|
|
57
|
-
│ ├── relationships.js # Relationship registry
|
|
58
|
-
│ ├── manage-record.js # createRecord/updateRecord
|
|
59
|
-
│ ├── model-property.js # Transform handler
|
|
60
|
-
│ ├── transforms.js # Built-in transforms
|
|
61
|
-
│ ├── hooks.js # Middleware hook registry
|
|
62
|
-
│ ├── setup-rest-server.js # REST integration
|
|
63
|
-
│ ├── orm-request.js # CRUD request handler with hooks + includes
|
|
64
|
-
│ ├── meta-request.js # Meta endpoint (dev only)
|
|
65
|
-
│ ├── migrate.js # JSON DB mode migration (file <-> directory)
|
|
66
|
-
│ ├── commands.js # CLI commands (db:migrate-*, etc.)
|
|
67
|
-
│ ├── utils.js # Pluralize wrapper for dasherized names
|
|
68
|
-
│ ├── exports/
|
|
69
|
-
│ │ └── db.js # Convenience re-export of DB instance
|
|
70
|
-
│ └── mysql/
|
|
71
|
-
│ ├── mysql-db.js # MySQL driver (CRUD persistence, record loading)
|
|
72
|
-
│ ├── connection.js # mysql2 connection pool
|
|
73
|
-
│ ├── query-builder.js # SQL builders (INSERT/UPDATE/DELETE/SELECT) with identifier validation
|
|
74
|
-
│ ├── schema-introspector.js # Model-to-MySQL schema introspection
|
|
75
|
-
│ ├── migration-generator.js # Schema diff and .sql migration generation
|
|
76
|
-
│ ├── migration-runner.js # Migration apply/rollback with transactions
|
|
77
|
-
│ └── type-map.js # ORM attr types -> MySQL column types (supports custom transform mysqlType)
|
|
78
|
-
├── config/
|
|
79
|
-
│ └── environment.js # Default configuration
|
|
80
|
-
├── test/
|
|
81
|
-
│ ├── integration/ # Integration tests
|
|
82
|
-
│ ├── unit/ # Unit tests
|
|
83
|
-
│ └── sample/ # Test fixtures
|
|
84
|
-
│ ├── models/ # Example models
|
|
85
|
-
│ ├── serializers/ # Example serializers
|
|
86
|
-
│ ├── transforms/ # Custom transforms
|
|
87
|
-
│ ├── access/ # Access control
|
|
88
|
-
│ ├── db-schema.js # DB schema
|
|
89
|
-
│ └── payload.js # Test data
|
|
90
|
-
└── package.json
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## Configuration
|
|
96
|
-
|
|
97
|
-
Located in [config/environment.js](config/environment.js), overridable via environment variables:
|
|
98
|
-
|
|
99
|
-
```javascript
|
|
100
|
-
config.orm = {
|
|
101
|
-
paths: {
|
|
102
|
-
model: './models',
|
|
103
|
-
serializer: './serializers',
|
|
104
|
-
transform: './transforms',
|
|
105
|
-
access: './access'
|
|
106
|
-
},
|
|
107
|
-
db: {
|
|
108
|
-
autosave: 'false',
|
|
109
|
-
file: 'db.json',
|
|
110
|
-
mode: 'file', // 'file' (single db.json) or 'directory' (one file per collection)
|
|
111
|
-
directory: 'db', // directory name for collection files when mode is 'directory'
|
|
112
|
-
saveInterval: 3600,
|
|
113
|
-
schema: './config/db-schema.js'
|
|
114
|
-
},
|
|
115
|
-
restServer: {
|
|
116
|
-
enabled: 'true',
|
|
117
|
-
route: '/'
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## Storage Modes
|
|
125
|
-
|
|
126
|
-
The ORM supports two storage modes, configured via `db.mode`:
|
|
127
|
-
|
|
128
|
-
- **`'file'`** (default): All data is stored in a single `db.json` file.
|
|
129
|
-
- **`'directory'`**: Each collection is stored as a separate file in the configured directory — `{directory}/{collection}.json` (e.g., `db/animals.json`, `db/owners.json`). The main `db.json` is kept as a skeleton with empty arrays.
|
|
130
|
-
|
|
131
|
-
**Migration CLI commands:**
|
|
132
|
-
- `stonyx-db-file-to-directory` — Splits a single `db.json` into per-collection files in the directory.
|
|
133
|
-
- `stonyx-db-directory-to-file` — Merges per-collection files back into a single `db.json`.
|
|
134
|
-
|
|
135
|
-
**Mode validation:** On startup, the ORM warns if the configured mode doesn't match the actual file state (e.g., mode is `'file'` but a `db/` directory exists, or mode is `'directory'` but no directory is found).
|
|
136
|
-
|
|
137
|
-
---
|
|
138
|
-
|
|
139
|
-
## Design Patterns
|
|
140
|
-
|
|
141
|
-
1. **Singleton**: Orm, Store, DB classes
|
|
142
|
-
2. **Proxy**: `attr()` uses Proxies for type-safe access
|
|
143
|
-
3. **Registry**: Relationships in nested Maps
|
|
144
|
-
4. **Factory**: `createRecord()` function
|
|
145
|
-
5. **Observer**: Auto-save via Cron
|
|
146
|
-
6. **Middleware**: Hook system with halting capability
|
|
147
|
-
7. **Convention over Configuration**: Auto-discovery by naming
|
|
148
|
-
|
|
149
|
-
**Naming Conventions:**
|
|
150
|
-
- Models: `{PascalCase}Model` (e.g., `AnimalModel`)
|
|
151
|
-
- Serializers: `{PascalCase}Serializer` (e.g., `AnimalSerializer`)
|
|
152
|
-
- Transforms: Original filename (e.g., `animal.js`)
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
## Testing
|
|
157
|
-
|
|
158
|
-
**Test Runner**: QUnit via `stonyx test` (auto-bootstraps and runs `test/**/*-test.js`)
|
|
159
|
-
|
|
160
|
-
**Test Structure:**
|
|
161
|
-
- **Integration**: [test/integration/orm-test.js](test/integration/orm-test.js) - Full pipeline test
|
|
162
|
-
- **Unit**: [test/unit/transforms/](test/unit/transforms/) - Transform tests
|
|
163
|
-
- **Sample**: [test/sample/](test/sample/) - Test fixtures
|
|
164
|
-
|
|
165
|
-
**Key Test Data:**
|
|
166
|
-
- [test/sample/payload.js](test/sample/payload.js) - Raw vs serialized data
|
|
167
|
-
- Demonstrates transformation from messy external data to clean models
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## Critical Files for Common Tasks
|
|
172
|
-
|
|
173
|
-
**Understanding Core Behavior:**
|
|
174
|
-
- [src/main.js](src/main.js) - Initialization flow
|
|
175
|
-
- [src/store.js](src/store.js) - Record storage/retrieval
|
|
176
|
-
- [src/manage-record.js](src/manage-record.js) - CRUD operations
|
|
177
|
-
|
|
178
|
-
**Understanding Relationships:**
|
|
179
|
-
- [src/relationships.js](src/relationships.js) - Registry system
|
|
180
|
-
- [src/has-many.js](src/has-many.js) - One-to-many logic
|
|
181
|
-
- [src/belongs-to.js](src/belongs-to.js) - Many-to-one logic
|
|
182
|
-
|
|
183
|
-
**Understanding Data Flow:**
|
|
184
|
-
- [src/serializer.js](src/serializer.js) - Raw → Model mapping
|
|
185
|
-
- [src/model-property.js](src/model-property.js) - Transform application
|
|
186
|
-
- [src/transforms.js](src/transforms.js) - Built-in transforms
|
|
187
|
-
|
|
188
|
-
**Understanding REST API:**
|
|
189
|
-
- [src/setup-rest-server.js](src/setup-rest-server.js) - Endpoint registration
|
|
190
|
-
- [src/orm-request.js](src/orm-request.js) - Request handling with hooks
|
|
191
|
-
|
|
192
|
-
**Understanding Hooks:**
|
|
193
|
-
- [src/hooks.js](src/hooks.js) - Hook registry (beforeHooks, afterHooks Maps)
|
|
194
|
-
- [src/orm-request.js](src/orm-request.js) - `_withHooks()` wrapper
|
|
195
|
-
|
|
196
|
-
---
|
|
197
|
-
|
|
198
|
-
## Key Insights
|
|
199
|
-
|
|
200
|
-
**Strengths:**
|
|
201
|
-
- Zero-config REST API generation
|
|
202
|
-
- Clean declarative model definitions
|
|
203
|
-
- Automatic relationship management
|
|
204
|
-
- File-based (no database setup needed)
|
|
205
|
-
- Flexible serialization for messy data
|
|
206
|
-
- Middleware hooks with halting capability
|
|
207
|
-
|
|
208
|
-
**Use Cases:**
|
|
209
|
-
- Rapid prototyping
|
|
210
|
-
- Small to medium applications
|
|
211
|
-
- Third-party API consumption with normalization
|
|
212
|
-
- Development/testing environments
|
|
213
|
-
- Applications needing quick REST APIs
|
|
214
|
-
|
|
215
|
-
**Dependencies:**
|
|
216
|
-
- `stonyx` - Main framework (peer)
|
|
217
|
-
- `@stonyx/utils` - File/string utilities
|
|
218
|
-
- `@stonyx/events` - Pub/sub event system (event names initialized on startup; hooks use separate middleware-based registry)
|
|
219
|
-
- `@stonyx/cron` - Scheduled tasks (used by DB for auto-save)
|
|
220
|
-
- `@stonyx/rest-server` - REST API
|
|
221
|
-
- `mysql2` - Optional peer dependency for MySQL mode
|
|
222
|
-
|
|
223
|
-
---
|
|
224
|
-
|
|
225
|
-
## Quick Reference
|
|
226
|
-
|
|
227
|
-
**Import the ORM:**
|
|
228
|
-
```javascript
|
|
229
|
-
import {
|
|
230
|
-
Orm, Model, Serializer, attr, hasMany, belongsTo,
|
|
231
|
-
createRecord, updateRecord, store,
|
|
232
|
-
beforeHook, afterHook, clearHook, clearAllHooks
|
|
233
|
-
} from '@stonyx/orm';
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
**Initialize:**
|
|
237
|
-
```javascript
|
|
238
|
-
const orm = new Orm({ dbType: 'json' });
|
|
239
|
-
await orm.init();
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
**Access Database:**
|
|
243
|
-
```javascript
|
|
244
|
-
await Orm.db.save();
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
**Common Operations:**
|
|
248
|
-
```javascript
|
|
249
|
-
// Create
|
|
250
|
-
const record = createRecord('modelName', data);
|
|
251
|
-
|
|
252
|
-
// Read
|
|
253
|
-
const record = store.get('modelName', id);
|
|
254
|
-
const all = store.get('modelName');
|
|
255
|
-
|
|
256
|
-
// Update
|
|
257
|
-
updateRecord(record, newData);
|
|
258
|
-
|
|
259
|
-
// Delete
|
|
260
|
-
store.remove('modelName', id);
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
**Register Hooks:**
|
|
264
|
-
```javascript
|
|
265
|
-
// Before hook (can halt)
|
|
266
|
-
const unsubscribe = beforeHook('create', 'animal', (ctx) => {
|
|
267
|
-
if (invalid) return 400;
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
// After hook
|
|
271
|
-
afterHook('update', 'animal', (ctx) => {
|
|
272
|
-
console.log('Updated:', ctx.record.id);
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// Cleanup
|
|
276
|
-
unsubscribe(); // Remove specific hook
|
|
277
|
-
clearHook('create', 'animal'); // Clear all hooks for operation
|
|
278
|
-
clearAllHooks(); // Clear everything
|
|
279
|
-
```
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
# Usage Patterns
|
|
2
|
-
|
|
3
|
-
## 1. Model Definition
|
|
4
|
-
|
|
5
|
-
Models extend `Model` and use decorators for attributes and relationships:
|
|
6
|
-
|
|
7
|
-
```javascript
|
|
8
|
-
// test/sample/models/animal.js
|
|
9
|
-
import { Model, attr, belongsTo, hasMany } from '@stonyx/orm';
|
|
10
|
-
|
|
11
|
-
export default class AnimalModel extends Model {
|
|
12
|
-
// Attributes with type transforms
|
|
13
|
-
type = attr('animal'); // Custom transform
|
|
14
|
-
age = attr('number'); // Built-in transform
|
|
15
|
-
size = attr('string');
|
|
16
|
-
|
|
17
|
-
// Relationships
|
|
18
|
-
owner = belongsTo('owner'); // Many-to-one
|
|
19
|
-
traits = hasMany('trait'); // One-to-many
|
|
20
|
-
|
|
21
|
-
// Computed properties
|
|
22
|
-
get tag() {
|
|
23
|
-
return `${this.owner.id}'s ${this.size} animal`;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**Key Points:**
|
|
29
|
-
- Use `attr(type)` for simple attributes
|
|
30
|
-
- Use `belongsTo(modelName)` for many-to-one
|
|
31
|
-
- Use `hasMany(modelName)` for one-to-many
|
|
32
|
-
- Getters work as computed properties
|
|
33
|
-
- Relationships auto-establish bidirectionally
|
|
34
|
-
|
|
35
|
-
## 2. Serializers (Data Transformation)
|
|
36
|
-
|
|
37
|
-
Serializers map raw data paths to model properties:
|
|
38
|
-
|
|
39
|
-
```javascript
|
|
40
|
-
// test/sample/serializers/animal.js
|
|
41
|
-
import { Serializer } from '@stonyx/orm';
|
|
42
|
-
|
|
43
|
-
export default class AnimalSerializer extends Serializer {
|
|
44
|
-
map = {
|
|
45
|
-
// Nested path mapping
|
|
46
|
-
age: 'details.age',
|
|
47
|
-
size: 'details.c',
|
|
48
|
-
owner: 'details.location.owner',
|
|
49
|
-
|
|
50
|
-
// Custom transformation function
|
|
51
|
-
traits: ['details', ({ x:color }) => {
|
|
52
|
-
const traits = [{ id: 1, type: 'habitat', value: 'farm' }];
|
|
53
|
-
if (color) traits.push({ id: 2, type: 'color', value: color });
|
|
54
|
-
return traits;
|
|
55
|
-
}]
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
**Key Points:**
|
|
61
|
-
- `map` object defines field mappings
|
|
62
|
-
- Supports nested paths (`'details.age'`)
|
|
63
|
-
- Custom functions for complex transformations
|
|
64
|
-
- Handlers receive raw data subset
|
|
65
|
-
|
|
66
|
-
## 3. Custom Transforms
|
|
67
|
-
|
|
68
|
-
Transforms convert data types:
|
|
69
|
-
|
|
70
|
-
```javascript
|
|
71
|
-
// test/sample/transforms/animal.js
|
|
72
|
-
const codeEnumMap = { 'dog': 1, 'cat': 2, 'bird': 3 };
|
|
73
|
-
|
|
74
|
-
export default function(value) {
|
|
75
|
-
return codeEnumMap[value] || 0;
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
**Built-in Transforms:**
|
|
80
|
-
- Type: `boolean`, `number`, `float`, `string`, `date`, `timestamp`
|
|
81
|
-
- Math: `round`, `ceil`, `floor`
|
|
82
|
-
- String: `trim`, `uppercase`
|
|
83
|
-
- Utility: `passthrough`
|
|
84
|
-
|
|
85
|
-
## 4. CRUD Operations
|
|
86
|
-
|
|
87
|
-
```javascript
|
|
88
|
-
import { createRecord, updateRecord, store } from '@stonyx/orm';
|
|
89
|
-
|
|
90
|
-
// Create
|
|
91
|
-
createRecord('owner', { id: 'bob', age: 30 });
|
|
92
|
-
|
|
93
|
-
// Read
|
|
94
|
-
const owner = store.get('owner', 'bob');
|
|
95
|
-
const allOwners = store.get('owner');
|
|
96
|
-
|
|
97
|
-
// Update
|
|
98
|
-
updateRecord(owner, { age: 31 });
|
|
99
|
-
// Or direct: owner.age = 31;
|
|
100
|
-
|
|
101
|
-
// Delete
|
|
102
|
-
store.remove('owner', 'bob');
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## 5. Database Schema
|
|
106
|
-
|
|
107
|
-
The DB schema is a Model defining top-level collections:
|
|
108
|
-
|
|
109
|
-
```javascript
|
|
110
|
-
// test/sample/db-schema.js
|
|
111
|
-
import { Model, hasMany } from '@stonyx/orm';
|
|
112
|
-
|
|
113
|
-
export default class DBModel extends Model {
|
|
114
|
-
owners = hasMany('owner');
|
|
115
|
-
animals = hasMany('animal');
|
|
116
|
-
traits = hasMany('trait');
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## 6. Persistence
|
|
121
|
-
|
|
122
|
-
```javascript
|
|
123
|
-
import Orm from '@stonyx/orm';
|
|
124
|
-
|
|
125
|
-
// Save to file
|
|
126
|
-
await Orm.db.save();
|
|
127
|
-
|
|
128
|
-
// Data auto-serializes to JSON file
|
|
129
|
-
// Reload using createRecord with serialize:false, transform:false
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## 7. Access Control
|
|
133
|
-
|
|
134
|
-
```javascript
|
|
135
|
-
// test/sample/access/global-access.js
|
|
136
|
-
export default class GlobalAccess {
|
|
137
|
-
models = ['owner', 'animal']; // or '*' for all
|
|
138
|
-
|
|
139
|
-
access(request) {
|
|
140
|
-
// Deny specific access
|
|
141
|
-
if (request.url.endsWith('/owner/angela')) return false;
|
|
142
|
-
|
|
143
|
-
// Filter collections
|
|
144
|
-
if (request.url.endsWith('/owner')) {
|
|
145
|
-
return record => record.id !== 'angela';
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Grant CRUD permissions
|
|
149
|
-
return ['read', 'create', 'update', 'delete'];
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
## 8. REST API (Auto-generated)
|
|
155
|
-
|
|
156
|
-
```javascript
|
|
157
|
-
// Endpoints auto-generated for models:
|
|
158
|
-
// GET /owners - List all
|
|
159
|
-
// GET /owners/:id - Get one
|
|
160
|
-
// POST /animals - Create
|
|
161
|
-
// PATCH /animals/:id - Update (attributes and/or relationships)
|
|
162
|
-
// DELETE /animals/:id - Delete
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
**PATCH supports both attributes and relationships:**
|
|
166
|
-
```javascript
|
|
167
|
-
// Update attributes only
|
|
168
|
-
PATCH /animals/1
|
|
169
|
-
{ data: { type: 'animal', attributes: { age: 5 } } }
|
|
170
|
-
|
|
171
|
-
// Update relationship only
|
|
172
|
-
PATCH /animals/1
|
|
173
|
-
{ data: { type: 'animal', relationships: { owner: { data: { type: 'owner', id: 'gina' } } } } }
|
|
174
|
-
|
|
175
|
-
// Update both
|
|
176
|
-
PATCH /animals/1
|
|
177
|
-
{ data: { type: 'animal', attributes: { age: 5 }, relationships: { owner: { data: { type: 'owner', id: 'gina' } } } } }
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## 9. Include Parameter (Sideloading)
|
|
181
|
-
|
|
182
|
-
GET endpoints support sideloading related records with **nested relationship traversal**:
|
|
183
|
-
|
|
184
|
-
```javascript
|
|
185
|
-
// Single-level includes
|
|
186
|
-
GET /animals/1?include=owner,traits
|
|
187
|
-
|
|
188
|
-
// Nested includes (NEW!)
|
|
189
|
-
GET /animals/1?include=owner.pets,owner.company
|
|
190
|
-
|
|
191
|
-
// Deep nesting (3+ levels)
|
|
192
|
-
GET /scenes/e001-s001?include=slides.dialogue.character
|
|
193
|
-
|
|
194
|
-
// Response structure (unchanged)
|
|
195
|
-
{
|
|
196
|
-
data: { type: 'animal', id: 1, attributes: {...}, relationships: {...} },
|
|
197
|
-
included: [
|
|
198
|
-
{ type: 'owner', id: 'angela', ... },
|
|
199
|
-
{ type: 'animal', id: 7, ... }, // owner's other pets
|
|
200
|
-
{ type: 'animal', id: 11, ... }, // owner's other pets
|
|
201
|
-
{ type: 'company', id: 'acme', ... } // owner's company (if requested)
|
|
202
|
-
]
|
|
203
|
-
}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
**How Nested Includes Work:**
|
|
207
|
-
1. Query param parsed into path segments: `owner.pets` -> `[['owner'], ['owner', 'pets'], ['traits']]`
|
|
208
|
-
2. `traverseIncludePath()` recursively traverses relationships depth-first
|
|
209
|
-
3. Deduplication still by type+id (no duplicates in included array)
|
|
210
|
-
4. Gracefully handles null/missing relationships at any depth
|
|
211
|
-
5. Each included record gets full `toJSON()` representation
|
|
212
|
-
|
|
213
|
-
**Key Functions:**
|
|
214
|
-
- `parseInclude()` - Splits comma-separated includes and parses nested paths
|
|
215
|
-
- `traverseIncludePath()` - Recursively traverses relationship paths
|
|
216
|
-
- `collectIncludedRecords()` - Orchestrates traversal and deduplication
|
|
217
|
-
- All implemented in [src/orm-request.js](src/orm-request.js)
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches: [dev, main]
|
|
6
|
-
|
|
7
|
-
concurrency:
|
|
8
|
-
group: ci-${{ github.head_ref || github.ref }}
|
|
9
|
-
cancel-in-progress: true
|
|
10
|
-
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
|
|
14
|
-
jobs:
|
|
15
|
-
test:
|
|
16
|
-
uses: abofs/stonyx-workflows/.github/workflows/ci.yml@main
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
name: Publish to NPM
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
repository_dispatch:
|
|
5
|
-
types: [cascade-publish]
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
inputs:
|
|
8
|
-
version-type:
|
|
9
|
-
description: 'Version type'
|
|
10
|
-
required: true
|
|
11
|
-
type: choice
|
|
12
|
-
options:
|
|
13
|
-
- patch
|
|
14
|
-
- minor
|
|
15
|
-
- major
|
|
16
|
-
custom-version:
|
|
17
|
-
description: 'Custom version (optional, overrides version-type)'
|
|
18
|
-
required: false
|
|
19
|
-
type: string
|
|
20
|
-
pull_request:
|
|
21
|
-
types: [opened, synchronize, reopened]
|
|
22
|
-
branches: [main]
|
|
23
|
-
push:
|
|
24
|
-
branches: [main]
|
|
25
|
-
|
|
26
|
-
concurrency:
|
|
27
|
-
group: ${{ github.event_name == 'repository_dispatch' && 'cascade-update' || format('publish-{0}', github.ref) }}
|
|
28
|
-
cancel-in-progress: false
|
|
29
|
-
|
|
30
|
-
permissions:
|
|
31
|
-
contents: write
|
|
32
|
-
id-token: write
|
|
33
|
-
pull-requests: write
|
|
34
|
-
|
|
35
|
-
jobs:
|
|
36
|
-
publish:
|
|
37
|
-
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
|
38
|
-
uses: abofs/stonyx-workflows/.github/workflows/npm-publish.yml@main
|
|
39
|
-
with:
|
|
40
|
-
version-type: ${{ github.event.inputs.version-type }}
|
|
41
|
-
custom-version: ${{ github.event.inputs.custom-version }}
|
|
42
|
-
cascade-source: ${{ github.event.client_payload.source_package || '' }}
|
|
43
|
-
secrets: inherit
|
|
44
|
-
|
|
45
|
-
cascade:
|
|
46
|
-
needs: publish
|
|
47
|
-
uses: abofs/stonyx-workflows/.github/workflows/cascade.yml@main
|
|
48
|
-
with:
|
|
49
|
-
package-name: ${{ needs.publish.outputs.package-name }}
|
|
50
|
-
published-version: ${{ needs.publish.outputs.published-version }}
|
|
51
|
-
secrets: inherit
|