@stonyx/orm 0.2.1-alpha.35 → 0.2.1-alpha.37
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/dist/aggregates.d.ts +21 -0
- package/dist/aggregates.js +90 -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 +174 -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 +47 -0
- package/dist/hooks.js +106 -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 +179 -0
- package/dist/manage-record.d.ts +13 -0
- package/dist/manage-record.js +117 -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 +245 -0
- package/dist/mysql/migration-runner.d.ts +12 -0
- package/dist/mysql/migration-runner.js +83 -0
- package/dist/mysql/mysql-db.d.ts +100 -0
- package/dist/mysql/mysql-db.js +415 -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 +286 -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 +455 -0
- package/dist/plural-registry.d.ts +4 -0
- package/{src → dist}/plural-registry.js +3 -6
- package/dist/postgres/connection.d.ts +15 -0
- package/dist/postgres/connection.js +30 -0
- package/dist/postgres/migration-generator.d.ts +45 -0
- package/dist/postgres/migration-generator.js +257 -0
- package/dist/postgres/migration-runner.d.ts +10 -0
- package/dist/postgres/migration-runner.js +82 -0
- package/dist/postgres/postgres-db.d.ts +119 -0
- package/dist/postgres/postgres-db.js +476 -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 +29 -0
- package/dist/postgres/schema-introspector.js +309 -0
- package/dist/postgres/type-map.d.ts +23 -0
- package/dist/postgres/type-map.js +53 -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 +39 -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 +54 -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 +271 -0
- package/dist/timescale/query-builder.d.ts +41 -0
- package/dist/timescale/query-builder.js +87 -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 +5 -0
- package/dist/utils.js +13 -0
- package/dist/view-resolver.d.ts +8 -0
- package/dist/view-resolver.js +169 -0
- package/dist/view.d.ts +11 -0
- package/dist/view.js +18 -0
- package/package.json +34 -11
- package/src/{aggregates.js → aggregates.ts} +27 -13
- package/src/{attr.js → attr.ts} +2 -2
- package/src/belongs-to.ts +90 -0
- package/src/{cli.js → cli.ts} +17 -11
- package/src/{commands.js → commands.ts} +179 -170
- package/src/{db.js → db.ts} +35 -26
- package/src/exports/db.ts +7 -0
- package/src/has-many.ts +92 -0
- package/src/{hooks.js → hooks.ts} +23 -27
- package/src/{index.js → index.ts} +4 -4
- package/src/{main.js → main.ts} +60 -34
- package/src/{manage-record.js → manage-record.ts} +47 -22
- package/src/{meta-request.js → meta-request.ts} +17 -14
- package/src/{migrate.js → migrate.ts} +9 -9
- package/src/{model-property.js → model-property.ts} +12 -6
- package/src/{model.js → model.ts} +5 -4
- package/src/mysql/{connection.js → connection.ts} +43 -28
- package/src/mysql/{migration-generator.js → migration-generator.ts} +332 -286
- package/src/mysql/{migration-runner.js → migration-runner.ts} +116 -110
- package/src/mysql/{mysql-db.js → mysql-db.ts} +537 -473
- package/src/mysql/{query-builder.js → query-builder.ts} +69 -64
- package/src/mysql/{schema-introspector.js → schema-introspector.ts} +355 -325
- package/src/mysql/{type-map.js → type-map.ts} +42 -37
- package/src/{orm-request.js → orm-request.ts} +169 -97
- package/src/plural-registry.ts +12 -0
- package/src/postgres/{connection.js → connection.ts} +14 -5
- package/src/postgres/{migration-generator.js → migration-generator.ts} +82 -38
- package/src/postgres/{migration-runner.js → migration-runner.ts} +11 -10
- package/src/postgres/{postgres-db.js → postgres-db.ts} +198 -114
- package/src/postgres/{query-builder.js → query-builder.ts} +27 -28
- package/src/postgres/{schema-introspector.js → schema-introspector.ts} +87 -58
- package/src/postgres/{type-map.js → type-map.ts} +10 -6
- package/src/record.ts +186 -0
- package/src/relationships.ts +53 -0
- package/src/{serializer.js → serializer.ts} +52 -36
- package/src/{setup-rest-server.js → setup-rest-server.ts} +18 -13
- package/src/{standalone-db.js → standalone-db.ts} +33 -24
- package/src/{store.js → store.ts} +90 -68
- package/src/timescale/{query-builder.js → query-builder.ts} +33 -38
- package/src/timescale/timescale-db.ts +119 -0
- package/src/transforms.ts +20 -0
- package/src/types/mysql2.d.ts +30 -0
- package/src/types/orm-types.ts +146 -0
- package/src/types/pg.d.ts +28 -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 +11 -0
- package/src/types/stonyx-utils.d.ts +33 -0
- package/src/types/stonyx.d.ts +21 -0
- package/src/utils.ts +16 -0
- package/src/{view-resolver.js → view-resolver.ts} +51 -24
- package/src/view.ts +22 -0
- package/src/belongs-to.js +0 -70
- package/src/has-many.js +0 -68
- package/src/record.js +0 -132
- package/src/relationships.js +0 -43
- package/src/timescale/timescale-db.js +0 -111
- package/src/transforms.js +0 -20
- package/src/utils.js +0 -12
- package/src/view.js +0 -21
package/src/record.js
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { store } from './index.js';
|
|
2
|
-
import { getComputedProperties } from "./serializer.js";
|
|
3
|
-
import { camelCaseToKebabCase } from '@stonyx/utils/string';
|
|
4
|
-
import { getPluralName } from './plural-registry.js';
|
|
5
|
-
export default class Record {
|
|
6
|
-
/** @private */
|
|
7
|
-
__data = {};
|
|
8
|
-
/** @private */
|
|
9
|
-
__relationships = {};
|
|
10
|
-
/** @private */
|
|
11
|
-
__serialized = false;
|
|
12
|
-
|
|
13
|
-
constructor(model, serializer) {
|
|
14
|
-
/** @private */
|
|
15
|
-
this.__model = model;
|
|
16
|
-
/** @private */
|
|
17
|
-
this.__serializer = serializer;
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
serialize(rawData, options={}) {
|
|
22
|
-
const { __data:data } = this;
|
|
23
|
-
|
|
24
|
-
if (this.__serialized && !options.update) {
|
|
25
|
-
const relatedIds = {};
|
|
26
|
-
|
|
27
|
-
for (const [ key, childRecord ] of Object.entries(this.__relationships)) {
|
|
28
|
-
relatedIds[key] = Array.isArray(childRecord)
|
|
29
|
-
? childRecord.map(r => r.id)
|
|
30
|
-
: childRecord?.id ?? null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return { ...data, ...relatedIds };
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const normalizedData = this.__serializer.normalize(rawData);
|
|
37
|
-
this.__serializer.setProperties(normalizedData, this, options);
|
|
38
|
-
|
|
39
|
-
return data;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Similar to serialize, but preserves top level relationship records
|
|
43
|
-
format() {
|
|
44
|
-
if (!this.__serialized) throw new Error('Record must be serialized before being converted to JSON');
|
|
45
|
-
|
|
46
|
-
const { __data:data } = this;
|
|
47
|
-
const records = {};
|
|
48
|
-
|
|
49
|
-
for (const [ key, childRecord ] of Object.entries(this.__relationships)) {
|
|
50
|
-
records[key] = Array.isArray(childRecord)
|
|
51
|
-
? childRecord.map(r => r.serialize())
|
|
52
|
-
: childRecord?.serialize() ?? null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return { ...data, ...records };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Formats record for JSON API output
|
|
59
|
-
toJSON(options = {}) {
|
|
60
|
-
if (!this.__serialized) throw new Error('Record must be serialized before being converted to JSON');
|
|
61
|
-
|
|
62
|
-
const { fields, baseUrl } = options;
|
|
63
|
-
const { __data:data } = this;
|
|
64
|
-
const modelName = this.__model.__name;
|
|
65
|
-
const pluralizedModelName = getPluralName(modelName);
|
|
66
|
-
const recordId = data.id;
|
|
67
|
-
const relationships = {};
|
|
68
|
-
const attributes = {};
|
|
69
|
-
|
|
70
|
-
for (const [key, value] of Object.entries(data)) {
|
|
71
|
-
if (key === 'id') continue;
|
|
72
|
-
if (fields && !fields.has(key)) continue;
|
|
73
|
-
attributes[key] = value;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
for (const [key, getter] of getComputedProperties(this.__model)) {
|
|
77
|
-
if (fields && !fields.has(key)) continue;
|
|
78
|
-
attributes[key] = getter.call(this);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
for (const [key, childRecord] of Object.entries(this.__relationships)) {
|
|
82
|
-
if (fields && !fields.has(key)) continue;
|
|
83
|
-
|
|
84
|
-
const relationshipData = Array.isArray(childRecord)
|
|
85
|
-
? childRecord.map(r => ({ type: r.__model.__name, id: r.id }))
|
|
86
|
-
: childRecord ? { type: childRecord.__model.__name, id: childRecord.id } : null;
|
|
87
|
-
|
|
88
|
-
// Dasherize the key for URL paths (e.g., accessLinks -> access-links)
|
|
89
|
-
const dasherizedKey = camelCaseToKebabCase(key);
|
|
90
|
-
|
|
91
|
-
relationships[dasherizedKey] = { data: relationshipData };
|
|
92
|
-
|
|
93
|
-
// Add links to relationship if baseUrl provided
|
|
94
|
-
if (baseUrl) {
|
|
95
|
-
relationships[dasherizedKey].links = {
|
|
96
|
-
self: `${baseUrl}/${pluralizedModelName}/${recordId}/relationships/${dasherizedKey}`,
|
|
97
|
-
related: `${baseUrl}/${pluralizedModelName}/${recordId}/${dasherizedKey}`
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const result = {
|
|
103
|
-
attributes,
|
|
104
|
-
relationships,
|
|
105
|
-
id: recordId,
|
|
106
|
-
type: modelName,
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// Add resource links if baseUrl provided
|
|
110
|
-
if (baseUrl) {
|
|
111
|
-
result.links = {
|
|
112
|
-
self: `${baseUrl}/${pluralizedModelName}/${recordId}`
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return result;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
unload(options={}) {
|
|
120
|
-
store.unloadRecord(this.__model.__name, this.id, options);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
clean() {
|
|
124
|
-
try {
|
|
125
|
-
for (const key of Object.keys(this)) {
|
|
126
|
-
delete this[key];
|
|
127
|
-
}
|
|
128
|
-
} catch {
|
|
129
|
-
// Ignore errors during cleanup, as some keys may not be deletable
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
package/src/relationships.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { relationships } from "@stonyx/orm";
|
|
2
|
-
|
|
3
|
-
export default class Relationships {
|
|
4
|
-
constructor() {
|
|
5
|
-
if (Relationships.instance) return Relationships.instance;
|
|
6
|
-
Relationships.instance = this;
|
|
7
|
-
|
|
8
|
-
this.data = new Map();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
get(key) {
|
|
12
|
-
return this.data.get(key);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
set(key, value) {
|
|
16
|
-
this.data.set(key, value);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// TODO: Refactor mapping to remove a level of iteration
|
|
21
|
-
export function getRelationships(type, sourceModel, targetModel, relationshipId) {
|
|
22
|
-
const allRelationships = relationships.get(type);
|
|
23
|
-
|
|
24
|
-
// create relationship map for this type of it doesn't already exist
|
|
25
|
-
if (!allRelationships.has(sourceModel)) allRelationships.set(sourceModel, new Map());
|
|
26
|
-
|
|
27
|
-
const modelRelationship = allRelationships.get(sourceModel);
|
|
28
|
-
|
|
29
|
-
if (!modelRelationship.has(targetModel)) modelRelationship.set(targetModel, new Map());
|
|
30
|
-
|
|
31
|
-
const relationship = modelRelationship.get(targetModel);
|
|
32
|
-
|
|
33
|
-
// TODO: Determine whether already having id should be handled differently
|
|
34
|
-
//if (relationship.has(relationshipId)) return;
|
|
35
|
-
|
|
36
|
-
return relationship;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function getHasManyRelationships(sourceModel, targetModel) {
|
|
40
|
-
return relationships.get('hasMany').get(sourceModel)?.get(targetModel);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export const TYPES = ['global', 'hasMany', 'belongsTo', 'pending'];
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import PostgresDB from '../postgres/postgres-db.js';
|
|
2
|
-
import { buildCreateHypertable, buildTimeBucket, buildContinuousAggregate, buildCompressionPolicy, buildEnableCompression } from './query-builder.js';
|
|
3
|
-
|
|
4
|
-
export default class TimescaleDB extends PostgresDB {
|
|
5
|
-
static extensions = ['timescaledb'];
|
|
6
|
-
static configKey = 'timescale';
|
|
7
|
-
|
|
8
|
-
constructor(deps = {}) {
|
|
9
|
-
super({
|
|
10
|
-
...deps,
|
|
11
|
-
buildCreateHypertable,
|
|
12
|
-
buildTimeBucket,
|
|
13
|
-
buildContinuousAggregate,
|
|
14
|
-
buildCompressionPolicy,
|
|
15
|
-
buildEnableCompression,
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Convert a table to a TimescaleDB hypertable.
|
|
21
|
-
* Should be called after the table is created (e.g. after initial migration).
|
|
22
|
-
* @param {string} modelName
|
|
23
|
-
* @param {string} timeColumn - The time-partitioning column
|
|
24
|
-
* @param {Object} [options]
|
|
25
|
-
* @param {string} [options.chunkInterval='7 days']
|
|
26
|
-
*/
|
|
27
|
-
async createHypertable(modelName, timeColumn, options = {}) {
|
|
28
|
-
const schemas = this.deps.introspectModels();
|
|
29
|
-
const schema = schemas[modelName];
|
|
30
|
-
if (!schema) throw new Error(`Model '${modelName}' not found`);
|
|
31
|
-
|
|
32
|
-
const { sql } = this.deps.buildCreateHypertable(schema.table, timeColumn, options);
|
|
33
|
-
await this.pool.query(sql);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Query time-bucketed aggregations on a hypertable.
|
|
38
|
-
* @param {string} modelName
|
|
39
|
-
* @param {string} timeColumn - Timestamp column to bucket
|
|
40
|
-
* @param {string} bucketSize - Bucket interval (e.g. '1 hour', '5 minutes')
|
|
41
|
-
* @param {Object} [options]
|
|
42
|
-
* @param {string[]} [options.aggregates] - Aggregate expressions
|
|
43
|
-
* @param {Object} [options.where] - WHERE conditions
|
|
44
|
-
* @param {number} [options.limit]
|
|
45
|
-
* @returns {Promise<Object[]>} Rows with bucket + aggregate columns
|
|
46
|
-
*/
|
|
47
|
-
async timeBucket(modelName, timeColumn, bucketSize, options = {}) {
|
|
48
|
-
const schemas = this.deps.introspectModels();
|
|
49
|
-
const schema = schemas[modelName];
|
|
50
|
-
if (!schema) return [];
|
|
51
|
-
|
|
52
|
-
const { sql, values } = this.deps.buildTimeBucket(schema.table, timeColumn, bucketSize, options);
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
const result = await this.pool.query(sql, values);
|
|
56
|
-
return result.rows;
|
|
57
|
-
} catch (error) {
|
|
58
|
-
if (error.code === '42P01') return [];
|
|
59
|
-
throw error;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Create a continuous aggregate view on a hypertable.
|
|
65
|
-
* @param {string} viewName - Name for the materialized view
|
|
66
|
-
* @param {string} modelName - Source hypertable model
|
|
67
|
-
* @param {string} timeColumn - Timestamp column
|
|
68
|
-
* @param {string} bucketSize - Bucket interval
|
|
69
|
-
* @param {string[]} aggregates - Aggregate expressions
|
|
70
|
-
* @param {Object} [options]
|
|
71
|
-
* @param {boolean} [options.withNoData=false]
|
|
72
|
-
*/
|
|
73
|
-
async createContinuousAggregate(viewName, modelName, timeColumn, bucketSize, aggregates, options = {}) {
|
|
74
|
-
const schemas = this.deps.introspectModels();
|
|
75
|
-
const schema = schemas[modelName];
|
|
76
|
-
if (!schema) throw new Error(`Model '${modelName}' not found`);
|
|
77
|
-
|
|
78
|
-
const { sql } = this.deps.buildContinuousAggregate(viewName, schema.table, timeColumn, bucketSize, aggregates, options);
|
|
79
|
-
await this.pool.query(sql);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Enable compression on a hypertable.
|
|
84
|
-
* @param {string} modelName
|
|
85
|
-
* @param {Object} [options]
|
|
86
|
-
* @param {string} [options.segmentBy] - Column to segment by
|
|
87
|
-
* @param {string} [options.orderBy] - Column to order by
|
|
88
|
-
*/
|
|
89
|
-
async enableCompression(modelName, options = {}) {
|
|
90
|
-
const schemas = this.deps.introspectModels();
|
|
91
|
-
const schema = schemas[modelName];
|
|
92
|
-
if (!schema) throw new Error(`Model '${modelName}' not found`);
|
|
93
|
-
|
|
94
|
-
const { sql } = this.deps.buildEnableCompression(schema.table, options.segmentBy, options.orderBy);
|
|
95
|
-
await this.pool.query(sql);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Add a compression policy to a hypertable.
|
|
100
|
-
* @param {string} modelName
|
|
101
|
-
* @param {string} compressAfter - Interval after which to compress (e.g. '7 days')
|
|
102
|
-
*/
|
|
103
|
-
async addCompressionPolicy(modelName, compressAfter) {
|
|
104
|
-
const schemas = this.deps.introspectModels();
|
|
105
|
-
const schema = schemas[modelName];
|
|
106
|
-
if (!schema) throw new Error(`Model '${modelName}' not found`);
|
|
107
|
-
|
|
108
|
-
const { sql } = this.deps.buildCompressionPolicy(schema.table, compressAfter);
|
|
109
|
-
await this.pool.query(sql);
|
|
110
|
-
}
|
|
111
|
-
}
|
package/src/transforms.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { getTimestamp } from "@stonyx/utils/date";
|
|
2
|
-
|
|
3
|
-
const transforms = {
|
|
4
|
-
boolean: value => typeof value === 'string' ? value.trim().toLowerCase() === 'true' : !!value,
|
|
5
|
-
date: value => value ? new Date(value) : null,
|
|
6
|
-
float: value => parseFloat(value),
|
|
7
|
-
number: value => parseInt(value),
|
|
8
|
-
passthrough: value => value,
|
|
9
|
-
string: value => String(value),
|
|
10
|
-
timestamp: value => getTimestamp(value),
|
|
11
|
-
trim: value => value?.trim(),
|
|
12
|
-
uppercase: value => value?.toUpperCase(),
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
// Math Proxies
|
|
16
|
-
['ceil', 'floor', 'round'].forEach(method => {
|
|
17
|
-
transforms[method] = value => Math[method](value);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
export default transforms;
|
package/src/utils.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { pluralize as basePluralize } from '@stonyx/utils/string';
|
|
2
|
-
|
|
3
|
-
// Wrapper to handle dasherized model names (e.g., "access-link" → "access-links")
|
|
4
|
-
export function pluralize(word) {
|
|
5
|
-
if (word.includes('-')) {
|
|
6
|
-
const parts = word.split('-');
|
|
7
|
-
const pluralizedLast = basePluralize(parts.pop());
|
|
8
|
-
return [...parts, pluralizedLast].join('-');
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return basePluralize(word);
|
|
12
|
-
}
|
package/src/view.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { attr } from '@stonyx/orm';
|
|
2
|
-
|
|
3
|
-
export default class View {
|
|
4
|
-
static memory = false;
|
|
5
|
-
static readOnly = true;
|
|
6
|
-
static pluralName = undefined;
|
|
7
|
-
static source = undefined;
|
|
8
|
-
static groupBy = undefined;
|
|
9
|
-
static resolve = undefined;
|
|
10
|
-
|
|
11
|
-
id = attr('number');
|
|
12
|
-
|
|
13
|
-
constructor(name) {
|
|
14
|
-
this.__name = name;
|
|
15
|
-
|
|
16
|
-
// Enforce readOnly — cannot be overridden to false
|
|
17
|
-
if (this.constructor.readOnly !== true) {
|
|
18
|
-
throw new Error(`View '${name}' cannot override readOnly to false`);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|