@stonyx/orm 0.2.1-beta.20 → 0.2.1-beta.21

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/.claude/index.md CHANGED
@@ -65,6 +65,7 @@ stonyx-orm/
65
65
  │ ├── migrate.js # JSON DB mode migration (file <-> directory)
66
66
  │ ├── commands.js # CLI commands (db:migrate-*, etc.)
67
67
  │ ├── utils.js # Pluralize wrapper for dasherized names
68
+ │ ├── plural-registry.js # Plural name registry (populated at init, supports Model.pluralName overrides)
68
69
  │ ├── exports/
69
70
  │ │ └── db.js # Convenience re-export of DB instance
70
71
  │ └── mysql/
@@ -150,6 +151,7 @@ The ORM supports two storage modes, configured via `db.mode`:
150
151
  - Models: `{PascalCase}Model` (e.g., `AnimalModel`)
151
152
  - Serializers: `{PascalCase}Serializer` (e.g., `AnimalSerializer`)
152
153
  - Transforms: Original filename (e.g., `animal.js`)
154
+ - Plural names: Auto-pluralized by default (e.g., `animal` → `animals`). Override with `static pluralName` on the model class (e.g., `static pluralName = 'people'`). All call sites use `getPluralName()` from the plural registry, **not** `pluralize()` directly.
153
155
 
154
156
  ---
155
157
 
@@ -31,6 +31,23 @@ export default class AnimalModel extends Model {
31
31
  - Use `hasMany(modelName)` for one-to-many
32
32
  - Getters work as computed properties
33
33
  - Relationships auto-establish bidirectionally
34
+ - Override auto-pluralization with `static pluralName` (see [Overriding Plural Names](#overriding-plural-names))
35
+
36
+ ### Overriding Plural Names
37
+
38
+ By default, model names are auto-pluralized (e.g., `animal` → `animals`) for REST routes, JSON:API URLs, and DB table names. When auto-pluralization produces the wrong result, override it with `static pluralName`:
39
+
40
+ ```javascript
41
+ import { Model, attr } from '@stonyx/orm';
42
+
43
+ export default class PersonModel extends Model {
44
+ static pluralName = 'people';
45
+
46
+ name = attr('string');
47
+ }
48
+ ```
49
+
50
+ The override is picked up automatically during ORM initialization — no additional registration is needed. All internal call sites (REST routes, JSON:API type references, MySQL table names, foreign key references) use the overridden value.
34
51
 
35
52
  ## 2. Serializers (Data Transformation)
36
53
 
package/README.md CHANGED
@@ -109,6 +109,22 @@ export default class OwnerModel extends Model {
109
109
  }
110
110
  ```
111
111
 
112
+ ### Overriding Plural Names
113
+
114
+ By default, model names are auto-pluralized for REST routes, JSON:API URLs, and DB table names (e.g., `animal` → `animals`). When auto-pluralization produces the wrong result, override it with `static pluralName`:
115
+
116
+ ```js
117
+ import { Model, attr } from '@stonyx/orm';
118
+
119
+ export default class PersonModel extends Model {
120
+ static pluralName = 'people';
121
+
122
+ name = attr('string');
123
+ }
124
+ ```
125
+
126
+ The override is picked up automatically during ORM initialization. All routes, JSON:API type references, and MySQL table names will use the overridden value.
127
+
112
128
  ## Serializers
113
129
 
114
130
  Based on the following sample payload structure which represents a poorly structure third-party data source:
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "stonyx-async",
5
5
  "stonyx-module"
6
6
  ],
7
- "version": "0.2.1-beta.20",
7
+ "version": "0.2.1-beta.21",
8
8
  "description": "",
9
9
  "main": "src/main.js",
10
10
  "type": "module",
package/src/main.js CHANGED
@@ -19,6 +19,7 @@ import config from 'stonyx/config';
19
19
  import log from 'stonyx/log';
20
20
  import { forEachFileImport } from '@stonyx/utils/file';
21
21
  import { kebabCaseToPascalCase, pluralize } from '@stonyx/utils/string';
22
+ import { registerPluralName } from './plural-registry.js';
22
23
  import setupRestServer from './setup-rest-server.js';
23
24
  import baseTransforms from './transforms.js';
24
25
  import Store from './store.js';
@@ -66,7 +67,10 @@ export default class Orm {
66
67
  // Transforms keep their original name, everything else gets converted to PascalCase with the type suffix
67
68
  const alias = type === 'Transform' ? name : `${kebabCaseToPascalCase(name)}${type}`;
68
69
 
69
- if (type === 'Model') Orm.store.set(name, new Map());
70
+ if (type === 'Model') {
71
+ Orm.store.set(name, new Map());
72
+ registerPluralName(name, exported);
73
+ }
70
74
 
71
75
  return this[pluralize(lowerCaseType)][alias] = exported;
72
76
  }, { ignoreAccessFailure: true, rawName: true, recursive: true, recursiveNaming: true });
package/src/model.js CHANGED
@@ -10,6 +10,7 @@ export default class Model {
10
10
  * Override in subclass: static memory = false;
11
11
  */
12
12
  static memory = true;
13
+ static pluralName = undefined;
13
14
 
14
15
  id = attr('number');
15
16
 
@@ -6,7 +6,7 @@ import { buildInsert, buildUpdate, buildDelete, buildSelect } from './query-buil
6
6
  import { createRecord, store } from '@stonyx/orm';
7
7
  import { confirm } from '@stonyx/utils/prompt';
8
8
  import { readFile } from '@stonyx/utils/file';
9
- import { pluralize } from '../utils.js';
9
+ import { getPluralName } from '../plural-registry.js';
10
10
  import config from 'stonyx/config';
11
11
  import log from 'stonyx/log';
12
12
  import path from 'path';
@@ -17,7 +17,7 @@ const defaultDeps = {
17
17
  introspectModels, getTopologicalOrder, schemasToSnapshot,
18
18
  loadLatestSnapshot, detectSchemaDrift,
19
19
  buildInsert, buildUpdate, buildDelete, buildSelect,
20
- createRecord, store, confirm, readFile, pluralize, config, log, path
20
+ createRecord, store, confirm, readFile, getPluralName, config, log, path
21
21
  };
22
22
 
23
23
  export default class MysqlDB {
@@ -1,7 +1,7 @@
1
1
  import Orm from '@stonyx/orm';
2
2
  import { getMysqlType } from './type-map.js';
3
3
  import { camelCaseToKebabCase } from '@stonyx/utils/string';
4
- import { pluralize } from '../utils.js';
4
+ import { getPluralName } from '../plural-registry.js';
5
5
  import { dbKey } from '../db.js';
6
6
 
7
7
  function getRelationshipInfo(property) {
@@ -51,15 +51,16 @@ export function introspectModels() {
51
51
 
52
52
  // Build foreign keys from belongsTo relationships
53
53
  for (const relName of Object.keys(relationships.belongsTo)) {
54
+ const modelName = camelCaseToKebabCase(relName);
54
55
  const fkColumn = `${relName}_id`;
55
56
  foreignKeys[fkColumn] = {
56
- references: pluralize(relName),
57
+ references: getPluralName(modelName),
57
58
  column: 'id',
58
59
  };
59
60
  }
60
61
 
61
62
  schemas[name] = {
62
- table: pluralize(name),
63
+ table: getPluralName(name),
63
64
  idType,
64
65
  columns,
65
66
  foreignKeys,
@@ -130,7 +131,7 @@ export function getTopologicalOrder(schemas) {
130
131
 
131
132
  // Visit dependencies (belongsTo targets) first
132
133
  for (const relName of Object.keys(schema.relationships.belongsTo)) {
133
- visit(relName);
134
+ visit(camelCaseToKebabCase(relName));
134
135
  }
135
136
 
136
137
  order.push(name);
@@ -1,7 +1,7 @@
1
1
  import { Request } from '@stonyx/rest-server';
2
2
  import Orm, { createRecord, updateRecord, store } from '@stonyx/orm';
3
3
  import { camelCaseToKebabCase } from '@stonyx/utils/string';
4
- import { pluralize } from './utils.js';
4
+ import { getPluralName } from './plural-registry.js';
5
5
  import { getBeforeHooks, getAfterHooks } from './hooks.js';
6
6
  import config from 'stonyx/config';
7
7
 
@@ -215,7 +215,7 @@ export default class OrmRequest extends Request {
215
215
 
216
216
  this.model = model;
217
217
  this.access = access;
218
- const pluralizedModel = pluralize(model);
218
+ const pluralizedModel = getPluralName(model);
219
219
 
220
220
  const modelRelationships = getModelRelationships(model);
221
221
 
@@ -0,0 +1,12 @@
1
+ import { pluralize } from './utils.js';
2
+
3
+ const registry = new Map();
4
+
5
+ export function registerPluralName(modelName, modelClass) {
6
+ const plural = modelClass.pluralName || pluralize(modelName);
7
+ registry.set(modelName, plural);
8
+ }
9
+
10
+ export function getPluralName(modelName) {
11
+ return registry.get(modelName) || pluralize(modelName);
12
+ }
package/src/record.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { store } from './index.js';
2
2
  import { getComputedProperties } from "./serializer.js";
3
3
  import { camelCaseToKebabCase } from '@stonyx/utils/string';
4
- import { pluralize } from './utils.js';
4
+ import { getPluralName } from './plural-registry.js';
5
5
  export default class Record {
6
6
  __data = {};
7
7
  __relationships = {};
@@ -57,7 +57,7 @@ export default class Record {
57
57
  const { fields, baseUrl } = options;
58
58
  const { __data:data } = this;
59
59
  const modelName = this.__model.__name;
60
- const pluralizedModelName = pluralize(modelName);
60
+ const pluralizedModelName = getPluralName(modelName);
61
61
  const recordId = data.id;
62
62
  const relationships = {};
63
63
  const attributes = {};
@@ -5,7 +5,7 @@ import MetaRequest from './meta-request.js';
5
5
  import RestServer from '@stonyx/rest-server';
6
6
  import { forEachFileImport } from '@stonyx/utils/file';
7
7
  import { dbKey } from './db.js';
8
- import { pluralize } from './utils.js';
8
+ import { getPluralName } from './plural-registry.js';
9
9
  import log from 'stonyx/log';
10
10
 
11
11
  export default async function(route, accessPath, metaRoute) {
@@ -43,7 +43,7 @@ export default async function(route, accessPath, metaRoute) {
43
43
 
44
44
  // Configure endpoints for models with access configuration
45
45
  for (const [model, access] of Object.entries(accessFiles)) {
46
- const pluralizedModel = pluralize(model);
46
+ const pluralizedModel = getPluralName(model);
47
47
  const modelName = name === 'index' ? pluralizedModel : `${name}/${pluralizedModel}`;
48
48
  RestServer.instance.mountRoute(OrmRequest, { name: modelName, options: { model, access } });
49
49
  }