@stonyx/orm 0.2.5-alpha.0 → 0.3.1

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 (166) hide show
  1. package/README.md +482 -15
  2. package/config/environment.js +63 -6
  3. package/dist/aggregates.d.ts +21 -0
  4. package/dist/aggregates.js +93 -0
  5. package/dist/attr.d.ts +2 -0
  6. package/dist/attr.js +22 -0
  7. package/dist/belongs-to.d.ts +11 -0
  8. package/dist/belongs-to.js +59 -0
  9. package/dist/cli.d.ts +22 -0
  10. package/dist/cli.js +148 -0
  11. package/dist/commands.d.ts +7 -0
  12. package/dist/commands.js +146 -0
  13. package/dist/db.d.ts +21 -0
  14. package/dist/db.js +180 -0
  15. package/dist/exports/db.d.ts +7 -0
  16. package/{src → dist}/exports/db.js +2 -4
  17. package/dist/has-many.d.ts +11 -0
  18. package/dist/has-many.js +58 -0
  19. package/dist/hooks.d.ts +75 -0
  20. package/dist/hooks.js +110 -0
  21. package/dist/index.d.ts +14 -0
  22. package/dist/index.js +34 -0
  23. package/dist/main.d.ts +46 -0
  24. package/dist/main.js +181 -0
  25. package/dist/manage-record.d.ts +13 -0
  26. package/dist/manage-record.js +123 -0
  27. package/dist/meta-request.d.ts +6 -0
  28. package/dist/meta-request.js +52 -0
  29. package/dist/migrate.d.ts +2 -0
  30. package/dist/migrate.js +57 -0
  31. package/dist/model-property.d.ts +9 -0
  32. package/dist/model-property.js +29 -0
  33. package/dist/model.d.ts +15 -0
  34. package/dist/model.js +18 -0
  35. package/dist/mysql/connection.d.ts +14 -0
  36. package/dist/mysql/connection.js +24 -0
  37. package/dist/mysql/migration-generator.d.ts +45 -0
  38. package/dist/mysql/migration-generator.js +254 -0
  39. package/dist/mysql/migration-runner.d.ts +12 -0
  40. package/dist/mysql/migration-runner.js +88 -0
  41. package/dist/mysql/mysql-db.d.ts +100 -0
  42. package/dist/mysql/mysql-db.js +425 -0
  43. package/dist/mysql/query-builder.d.ts +10 -0
  44. package/dist/mysql/query-builder.js +44 -0
  45. package/dist/mysql/schema-introspector.d.ts +19 -0
  46. package/dist/mysql/schema-introspector.js +257 -0
  47. package/dist/mysql/type-map.d.ts +21 -0
  48. package/dist/mysql/type-map.js +36 -0
  49. package/dist/orm-request.d.ts +38 -0
  50. package/dist/orm-request.js +475 -0
  51. package/dist/plural-registry.d.ts +4 -0
  52. package/dist/plural-registry.js +9 -0
  53. package/dist/postgres/connection.d.ts +15 -0
  54. package/dist/postgres/connection.js +32 -0
  55. package/dist/postgres/migration-generator.d.ts +45 -0
  56. package/dist/postgres/migration-generator.js +280 -0
  57. package/dist/postgres/migration-runner.d.ts +10 -0
  58. package/dist/postgres/migration-runner.js +87 -0
  59. package/dist/postgres/postgres-db.d.ts +119 -0
  60. package/dist/postgres/postgres-db.js +477 -0
  61. package/dist/postgres/query-builder.d.ts +27 -0
  62. package/dist/postgres/query-builder.js +98 -0
  63. package/dist/postgres/schema-introspector.d.ts +29 -0
  64. package/dist/postgres/schema-introspector.js +296 -0
  65. package/dist/postgres/type-map.d.ts +23 -0
  66. package/dist/postgres/type-map.js +56 -0
  67. package/dist/record.d.ts +75 -0
  68. package/dist/record.js +129 -0
  69. package/dist/relationships.d.ts +10 -0
  70. package/dist/relationships.js +41 -0
  71. package/dist/schema-helpers.d.ts +20 -0
  72. package/dist/schema-helpers.js +48 -0
  73. package/dist/serializer.d.ts +17 -0
  74. package/dist/serializer.js +136 -0
  75. package/dist/setup-rest-server.d.ts +1 -0
  76. package/dist/setup-rest-server.js +52 -0
  77. package/dist/standalone-db.d.ts +58 -0
  78. package/dist/standalone-db.js +142 -0
  79. package/dist/store.d.ts +62 -0
  80. package/dist/store.js +286 -0
  81. package/dist/timescale/query-builder.d.ts +43 -0
  82. package/dist/timescale/query-builder.js +115 -0
  83. package/dist/timescale/timescale-db.d.ts +45 -0
  84. package/dist/timescale/timescale-db.js +84 -0
  85. package/dist/transforms.d.ts +2 -0
  86. package/dist/transforms.js +17 -0
  87. package/dist/types/orm-types.d.ts +153 -0
  88. package/dist/types/orm-types.js +1 -0
  89. package/dist/utils.d.ts +7 -0
  90. package/dist/utils.js +17 -0
  91. package/dist/view-resolver.d.ts +8 -0
  92. package/dist/view-resolver.js +171 -0
  93. package/dist/view.d.ts +11 -0
  94. package/dist/view.js +18 -0
  95. package/package.json +64 -11
  96. package/src/aggregates.ts +109 -0
  97. package/src/{attr.js → attr.ts} +2 -2
  98. package/src/belongs-to.ts +90 -0
  99. package/src/cli.ts +183 -0
  100. package/src/commands.ts +179 -0
  101. package/src/db.ts +232 -0
  102. package/src/exports/db.ts +7 -0
  103. package/src/has-many.ts +92 -0
  104. package/src/hooks.ts +151 -0
  105. package/src/{index.js → index.ts} +12 -2
  106. package/src/main.ts +229 -0
  107. package/src/manage-record.ts +161 -0
  108. package/src/{meta-request.js → meta-request.ts} +17 -14
  109. package/src/migrate.ts +72 -0
  110. package/src/model-property.ts +35 -0
  111. package/src/model.ts +21 -0
  112. package/src/mysql/connection.ts +43 -0
  113. package/src/mysql/migration-generator.ts +337 -0
  114. package/src/mysql/migration-runner.ts +121 -0
  115. package/src/mysql/mysql-db.ts +543 -0
  116. package/src/mysql/query-builder.ts +69 -0
  117. package/src/mysql/schema-introspector.ts +310 -0
  118. package/src/mysql/type-map.ts +42 -0
  119. package/src/orm-request.ts +582 -0
  120. package/src/plural-registry.ts +12 -0
  121. package/src/postgres/connection.ts +48 -0
  122. package/src/postgres/migration-generator.ts +370 -0
  123. package/src/postgres/migration-runner.ts +115 -0
  124. package/src/postgres/postgres-db.ts +616 -0
  125. package/src/postgres/query-builder.ts +148 -0
  126. package/src/postgres/schema-introspector.ts +360 -0
  127. package/src/postgres/type-map.ts +61 -0
  128. package/src/record.ts +186 -0
  129. package/src/relationships.ts +54 -0
  130. package/src/schema-helpers.ts +59 -0
  131. package/src/serializer.ts +161 -0
  132. package/src/setup-rest-server.ts +62 -0
  133. package/src/standalone-db.ts +185 -0
  134. package/src/store.ts +373 -0
  135. package/src/timescale/query-builder.ts +174 -0
  136. package/src/timescale/timescale-db.ts +119 -0
  137. package/src/transforms.ts +20 -0
  138. package/src/types/mysql2.d.ts +49 -0
  139. package/src/types/orm-types.ts +158 -0
  140. package/src/types/pg.d.ts +32 -0
  141. package/src/types/stonyx-cron.d.ts +5 -0
  142. package/src/types/stonyx-events.d.ts +4 -0
  143. package/src/types/stonyx-rest-server.d.ts +16 -0
  144. package/src/types/stonyx-utils.d.ts +33 -0
  145. package/src/types/stonyx.d.ts +21 -0
  146. package/src/utils.ts +22 -0
  147. package/src/view-resolver.ts +211 -0
  148. package/src/view.ts +22 -0
  149. package/.claude/project-structure.md +0 -578
  150. package/.github/workflows/ci.yml +0 -36
  151. package/.github/workflows/publish.yml +0 -143
  152. package/src/belongs-to.js +0 -63
  153. package/src/db.js +0 -80
  154. package/src/has-many.js +0 -61
  155. package/src/main.js +0 -119
  156. package/src/manage-record.js +0 -103
  157. package/src/model-property.js +0 -29
  158. package/src/model.js +0 -9
  159. package/src/orm-request.js +0 -249
  160. package/src/record.js +0 -100
  161. package/src/relationships.js +0 -43
  162. package/src/serializer.js +0 -138
  163. package/src/setup-rest-server.js +0 -57
  164. package/src/store.js +0 -211
  165. package/src/transforms.js +0 -20
  166. package/stonyx-bootstrap.cjs +0 -30
@@ -1,143 +0,0 @@
1
- name: Publish to NPM
2
-
3
- on:
4
- # Manual trigger (kept for flexibility)
5
- workflow_dispatch:
6
- inputs:
7
- version-type:
8
- description: 'Version type'
9
- required: true
10
- type: choice
11
- options:
12
- - alpha
13
- - patch
14
- - minor
15
- - major
16
- custom-version:
17
- description: 'Custom version (optional, overrides version-type)'
18
- required: false
19
- type: string
20
-
21
- # Auto-publish alpha on PR
22
- pull_request:
23
- types: [opened, synchronize, reopened]
24
- branches: [main, dev]
25
-
26
- # Auto-publish stable on merge to main
27
- push:
28
- branches: [main]
29
-
30
- permissions:
31
- contents: write
32
- id-token: write # Required for npm provenance
33
- pull-requests: write # For PR comments
34
-
35
- jobs:
36
- publish:
37
- runs-on: ubuntu-latest
38
-
39
- steps:
40
- - name: Checkout code
41
- uses: actions/checkout@v3
42
- with:
43
- fetch-depth: 0
44
- # For PR events, check out the PR branch
45
- ref: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref }}
46
-
47
- - name: Setup pnpm
48
- uses: pnpm/action-setup@v4
49
- with:
50
- version: 9
51
-
52
- - name: Set up Node.js
53
- uses: actions/setup-node@v3
54
- with:
55
- node-version: 24.13.0
56
- cache: 'pnpm'
57
- registry-url: 'https://registry.npmjs.org'
58
-
59
- - name: Install dependencies
60
- run: pnpm install --frozen-lockfile
61
-
62
- - name: Run tests
63
- run: pnpm test
64
-
65
- - name: Configure git
66
- run: |
67
- git config user.name "github-actions[bot]"
68
- git config user.email "github-actions[bot]@users.noreply.github.com"
69
-
70
- # Determine version type based on trigger
71
- - name: Determine version bump type
72
- id: version-type
73
- run: |
74
- if [ "${{ github.event_name }}" = "pull_request" ]; then
75
- echo "type=alpha" >> $GITHUB_OUTPUT
76
- elif [ "${{ github.event_name }}" = "push" ]; then
77
- echo "type=patch" >> $GITHUB_OUTPUT
78
- elif [ "${{ github.event.inputs.custom-version }}" != "" ]; then
79
- echo "type=custom" >> $GITHUB_OUTPUT
80
- else
81
- echo "type=${{ github.event.inputs.version-type }}" >> $GITHUB_OUTPUT
82
- fi
83
-
84
- # Version bumping
85
- - name: Bump version (custom)
86
- if: steps.version-type.outputs.type == 'custom'
87
- run: pnpm version ${{ github.event.inputs.custom-version }} --no-git-tag-version
88
-
89
- - name: Bump version (alpha)
90
- if: steps.version-type.outputs.type == 'alpha'
91
- run: pnpm version prerelease --preid=alpha --no-git-tag-version
92
-
93
- - name: Bump version (patch/minor/major)
94
- if: steps.version-type.outputs.type == 'patch' || steps.version-type.outputs.type == 'minor' || steps.version-type.outputs.type == 'major'
95
- run: pnpm version ${{ steps.version-type.outputs.type }} --no-git-tag-version
96
-
97
- - name: Get package version
98
- id: package-version
99
- run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
100
-
101
- # Publishing
102
- - name: Publish to NPM (alpha)
103
- if: contains(steps.package-version.outputs.version, 'alpha')
104
- run: pnpm publish --tag alpha --access public --no-git-checks
105
-
106
- - name: Publish to NPM (stable)
107
- if: "!contains(steps.package-version.outputs.version, 'alpha')"
108
- run: pnpm publish --access public
109
-
110
- # Only commit and tag for stable releases (push to main or manual stable)
111
- - name: Commit version bump and create tag
112
- if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && !contains(steps.package-version.outputs.version, 'alpha'))
113
- run: |
114
- git add package.json
115
- git commit -m "chore: release v${{ steps.package-version.outputs.version }}"
116
- git tag v${{ steps.package-version.outputs.version }}
117
- git push origin main --tags
118
-
119
- - name: Create GitHub Release
120
- if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && !contains(steps.package-version.outputs.version, 'alpha'))
121
- uses: actions/create-release@v1
122
- env:
123
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
124
- with:
125
- tag_name: v${{ steps.package-version.outputs.version }}
126
- release_name: v${{ steps.package-version.outputs.version }}
127
- draft: false
128
- prerelease: false
129
-
130
- # Add PR comment with alpha version info
131
- - name: Comment on PR with alpha version
132
- if: github.event_name == 'pull_request'
133
- uses: actions/github-script@v6
134
- with:
135
- script: |
136
- const version = '${{ steps.package-version.outputs.version }}';
137
- const packageName = require('./package.json').name;
138
- github.rest.issues.createComment({
139
- issue_number: context.issue.number,
140
- owner: context.repo.owner,
141
- repo: context.repo.repo,
142
- body: `## 🚀 Alpha Version Published\n\n**Version:** \`${version}\`\n\n**Install:**\n\`\`\`bash\npnpm add ${packageName}@${version}\n# or\npnpm add ${packageName}@alpha # latest alpha\n\`\`\`\n\nThis alpha version is now available for testing!`
143
- });
package/src/belongs-to.js DELETED
@@ -1,63 +0,0 @@
1
- import { createRecord, relationships, store } from '@stonyx/orm';
2
- import { getRelationships } from './relationships.js';
3
-
4
- function getOrSet(map, key, defaultValue) {
5
- if (!map.has(key)) map.set(key, defaultValue);
6
- return map.get(key);
7
- }
8
-
9
- export default function belongsTo(modelName) {
10
- const hasManyRelationships = relationships.get('hasMany');
11
- const pendingHasManyQueue = relationships.get('pending');
12
- const pendingBelongsToQueue = relationships.get('pendingBelongsTo');
13
-
14
- return (sourceRecord, rawData, options) => {
15
- if (!rawData) return null;
16
-
17
- const { __name: sourceModelName } = sourceRecord.__model;
18
- const relationshipId = sourceRecord.id;
19
- const relationshipKey = options._relationshipKey;
20
- const relationship = getRelationships('belongsTo', sourceModelName, modelName, relationshipId);
21
- const modelStore = store.get(modelName);
22
-
23
- // Try to get existing record
24
- const output = typeof rawData === 'object'
25
- ? createRecord(modelName, rawData, options)
26
- : modelStore.get(rawData);
27
-
28
- // If not found and is a string ID, register as pending
29
- if (!output && typeof rawData !== 'object') {
30
- const targetId = rawData;
31
-
32
- // Register pending belongsTo
33
- const modelPendingMap = getOrSet(pendingBelongsToQueue, modelName, new Map());
34
- const targetPendingArray = getOrSet(modelPendingMap, targetId, []);
35
-
36
- targetPendingArray.push({
37
- sourceRecord,
38
- sourceModelName,
39
- relationshipKey,
40
- relationshipId
41
- });
42
-
43
- relationship.set(relationshipId, null);
44
- return null;
45
- }
46
-
47
- relationship.set(relationshipId, output || {});
48
-
49
- // Populate hasMany side if the relationship is defined
50
- const otherSide = hasManyRelationships.get(modelName)?.get(sourceModelName)?.get(output?.id);
51
-
52
- if (otherSide) {
53
- otherSide.push(sourceRecord);
54
-
55
- // Remove pending queue if it was just fulfilled
56
- const pendingModelRelationships = pendingHasManyQueue.get(sourceModelName);
57
-
58
- if (pendingModelRelationships) pendingModelRelationships.delete(relationshipId);
59
- }
60
-
61
- return output;
62
- }
63
- }
package/src/db.js DELETED
@@ -1,80 +0,0 @@
1
- /*
2
- * Copyright 2025 Stone Costa
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
-
17
- import Cron from '@stonyx/cron';
18
- import config from 'stonyx/config';
19
- import log from 'stonyx/log';
20
- import Orm, { createRecord, store } from '@stonyx/orm';
21
- import { createFile, updateFile, readFile } from '@stonyx/utils/file';
22
-
23
- export const dbKey = '__db';
24
-
25
- export default class DB {
26
- constructor() {
27
- if (DB.instance) return DB.instance;
28
-
29
- DB.instance = this;
30
- }
31
-
32
- async getSchema() {
33
- const { rootPath } = config;
34
- const { file, schema } = config.orm.db;
35
-
36
- if (!file) throw new Error('Configuration Error: ORM DB file path must be defined.');
37
-
38
- return (await import(`${rootPath}/${schema}`)).default;
39
- }
40
-
41
- async init() {
42
- const { autosave, saveInterval } = config.orm.db;
43
-
44
- store.set(dbKey, new Map());
45
- Orm.instance.models[`${dbKey}Model`] = await this.getSchema();
46
-
47
- this.record = await this.getRecord();
48
-
49
- if (autosave !== 'true') return;
50
-
51
- new Cron().register('save', this.save.bind(this), saveInterval);
52
- }
53
-
54
- async create() {
55
- const { rootPath } = config;
56
- const { file } = config.orm.db;
57
-
58
- createFile(`${rootPath}/${file}`, {}, { json: true });
59
-
60
- return {};
61
- }
62
-
63
- async save() {
64
- const { file } = config.orm.db;
65
- const jsonData = this.record.format();
66
- delete jsonData.id; // Don't save id
67
-
68
- await updateFile(`${config.rootPath}/${file}`, jsonData, { json: true });
69
-
70
- log.db(`DB has been successfully saved to ${file}`);
71
- }
72
-
73
- async getRecord() {
74
- const { file } = config.orm.db;
75
-
76
- const data = await readFile(file, { json: true, missingFileCallback: this.create.bind(this) });
77
-
78
- return createRecord(dbKey, data, { isDbRecord: true, serialize: false, transform: false });
79
- }
80
- }
package/src/has-many.js DELETED
@@ -1,61 +0,0 @@
1
- import { createRecord, relationships, store } from '@stonyx/orm';
2
- import { getRelationships } from './relationships.js';
3
- import { getOrSet, makeArray } from '@stonyx/utils/object';
4
- import { dbKey } from './db.js';
5
-
6
- function queuePendingRelationship(pendingRelationshipQueue, pendingRelationships, modelName, id) {
7
- pendingRelationshipQueue.push({
8
- pendingRelationship: getOrSet(pendingRelationships, modelName, new Map()),
9
- id
10
- });
11
-
12
- return null;
13
- }
14
-
15
- export default function hasMany(modelName) {
16
- const globalRelationships = relationships.get('global');
17
- const pendingRelationships = relationships.get('pending');
18
-
19
- return (sourceRecord, rawData, options) => {
20
- const { __name: sourceModelName } = sourceRecord.__model;
21
- const relationshipId = sourceRecord.id;
22
- const relationship = getRelationships('hasMany', sourceModelName, modelName, relationshipId);
23
- const modelStore = store.get(modelName);
24
- const pendingRelationshipQueue = [];
25
-
26
- const output = !rawData ? [] : makeArray(rawData).map(elementData => {
27
- let record;
28
-
29
- if (typeof elementData !== 'object') {
30
- record = modelStore.get(elementData);
31
-
32
- if (!record) {
33
- return queuePendingRelationship(pendingRelationshipQueue, pendingRelationships, modelName, elementData);
34
- }
35
- } else {
36
- if (elementData !== Object(elementData)) {
37
- return queuePendingRelationship(pendingRelationshipQueue, pendingRelationships, modelName, elementData);
38
- }
39
-
40
- record = createRecord(modelName, elementData, options);
41
- }
42
-
43
- // Populate belongTo side if the relationship is defined
44
- const otherSide = relationships.get('belongsTo').get(modelName)?.get(sourceModelName)?.get(record.id);
45
-
46
- if (otherSide) Object.assign(otherSide, sourceRecord);
47
-
48
- return record;
49
- }).filter(value => value);
50
-
51
- relationship.set(relationshipId, output);
52
-
53
- // Assign global relationship
54
- if (options.global || sourceModelName === dbKey) getOrSet(globalRelationships, modelName, []).push(output);
55
-
56
- // Assign pending relationships
57
- for (const { pendingRelationship, id } of pendingRelationshipQueue) getOrSet(pendingRelationship, id, []).push(output);
58
-
59
- return output;
60
- }
61
- }
package/src/main.js DELETED
@@ -1,119 +0,0 @@
1
- /*
2
- * Copyright 2025 Stone Costa
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
-
17
- import DB from './db.js';
18
- import config from 'stonyx/config';
19
- import log from 'stonyx/log';
20
- import { forEachFileImport } from '@stonyx/utils/file';
21
- import { kebabCaseToPascalCase, pluralize } from '@stonyx/utils/string';
22
- import setupRestServer from './setup-rest-server.js';
23
- import baseTransforms from './transforms.js';
24
- import Store from './store.js';
25
- import Serializer from './serializer.js';
26
-
27
- const defaultOptions = {
28
- dbType: 'json'
29
- }
30
-
31
- export default class Orm {
32
- static initialized = false;
33
- static relationships = new Map();
34
- static store = new Store();
35
-
36
- models = {};
37
- serializers = {};
38
- transforms = { ...baseTransforms };
39
- warnings = new Set();
40
-
41
- constructor(options={}) {
42
- if (Orm.instance) return Orm.instance;
43
-
44
- const { relationships } = Orm;
45
-
46
- // Declare relationship maps
47
- for (const key of ['hasMany', 'belongsTo', 'global', 'pending', 'pendingBelongsTo']) {
48
- relationships.set(key, new Map());
49
- }
50
-
51
- this.options = { ...defaultOptions, ...options };
52
-
53
- Orm.instance = this;
54
- }
55
-
56
- async init() {
57
- const { paths, restServer } = config.orm;
58
- const promises = ['Model', 'Serializer', 'Transform'].map(type => {
59
- const lowerCaseType = type.toLowerCase();
60
- const path = paths[lowerCaseType];
61
-
62
- if (!path) throw new Error(`Configuration Error: ORM path for "${type}" must be defined.`);
63
-
64
- return forEachFileImport(path, (exported, { name }) => {
65
- // Transforms keep their original name, everything else gets converted to PascalCase with the type suffix
66
- const alias = type === 'Transform' ? name : `${kebabCaseToPascalCase(name)}${type}`;
67
-
68
- if (type === 'Model') Orm.store.set(name, new Map());
69
-
70
- return this[pluralize(lowerCaseType)][alias] = exported;
71
- }, { ignoreAccessFailure: true, rawName: true, recursive: true, recursiveNaming: true });
72
- });
73
-
74
- // Wait for imports before db & rest server setup
75
- await Promise.all(promises);
76
-
77
- if (this.options.dbType !== 'none') {
78
- const db = new DB();
79
- this.db = db;
80
-
81
- promises.push(db.init());
82
- }
83
-
84
- if (restServer.enabled === 'true') {
85
- promises.push(setupRestServer(restServer.route, paths.access, restServer.metaRoute));
86
- }
87
-
88
- Orm.ready = await Promise.all(promises);
89
- Orm.initialized = true;
90
- }
91
-
92
- static get db() {
93
- if (!Orm.initialized) throw new Error('ORM has not been initialized yet');
94
-
95
- return Orm.instance.db;
96
- }
97
-
98
- getRecordClasses(modelName) {
99
- const modelClassPrefix = kebabCaseToPascalCase(modelName);
100
-
101
- return {
102
- modelClass: this.models[`${modelClassPrefix}Model`],
103
- serializerClass: this.serializers[`${modelClassPrefix}Serializer`] || Serializer
104
- };
105
- }
106
-
107
- // Queue warnings to avoid the same error from being logged in the same iteration
108
- warn(message) {
109
- this.warnings.add(message);
110
-
111
- setTimeout(() => {
112
- this.warnings.forEach(warning => log.warn(warning));
113
- this.warnings.clear();
114
- }, 0);
115
- }
116
- }
117
-
118
- export const store = Orm.store;
119
- export const relationships = Orm.relationships;
@@ -1,103 +0,0 @@
1
- import Orm, { store, relationships } from '@stonyx/orm';
2
- import Record from './record.js';
3
-
4
- const defaultOptions = {
5
- isDbRecord: false,
6
- serialize: true,
7
- transform: true
8
- };
9
-
10
- export function createRecord(modelName, rawData={}, userOptions={}) {
11
- const orm = Orm.instance;
12
- const { initialized } = Orm;
13
- const options = { ...defaultOptions, ...userOptions };
14
-
15
- if (!initialized && !options.isDbRecord) throw new Error('ORM is not ready');
16
-
17
- const modelStore = store.get(modelName);
18
- const globalRelationships = relationships.get('global');
19
- const pendingRelationships = relationships.get('pending');
20
-
21
- assignRecordId(modelName, rawData);
22
- if (modelStore.has(rawData.id)) return modelStore.get(rawData.id);
23
-
24
- const { modelClass, serializerClass } = orm.getRecordClasses(modelName);
25
-
26
- if (!modelClass) throw new Error(`A model named '${modelName}' does not exist`);
27
-
28
- const model = new modelClass(modelName);
29
- const serializer = new serializerClass(model);
30
- const record = new Record(model, serializer);
31
-
32
- record.serialize(rawData, options);
33
- modelStore.set(record.id, record);
34
-
35
- // populate global hasMany relationships
36
- const globalHasMany = globalRelationships.get(modelName);
37
- if (globalHasMany) for (const relationship of globalHasMany) relationship.push(record);
38
-
39
- // populate pending hasMany relationships and clear the queue
40
- const pendingHasMany = pendingRelationships.get(modelName)?.get(record.id);
41
- if (pendingHasMany) {
42
- for (const relationship of pendingHasMany) relationship.push(record);
43
- pendingHasMany.splice(0);
44
- }
45
-
46
- // Fulfill pending belongsTo relationships
47
- const pendingBelongsToQueue = relationships.get('pendingBelongsTo');
48
- const pendingBelongsTo = pendingBelongsToQueue.get(modelName)?.get(record.id);
49
-
50
- if (pendingBelongsTo) {
51
- const belongsToReg = relationships.get('belongsTo');
52
- const hasManyReg = relationships.get('hasMany');
53
-
54
- for (const { sourceRecord, sourceModelName, relationshipKey, relationshipId } of pendingBelongsTo) {
55
- // Update the belongsTo relationship on the source record
56
- sourceRecord.__relationships[relationshipKey] = record;
57
- sourceRecord[relationshipKey] = record; // Also update the direct property
58
-
59
- // Update the belongsTo relationship registry
60
- const sourceModelReg = belongsToReg.get(sourceModelName);
61
- if (sourceModelReg) {
62
- const targetModelReg = sourceModelReg.get(modelName);
63
- if (targetModelReg) {
64
- targetModelReg.set(relationshipId, record);
65
- }
66
- }
67
-
68
- // Wire inverse hasMany if it exists
69
- const inverseHasMany = hasManyReg.get(modelName)?.get(sourceModelName)?.get(record.id);
70
-
71
- if (inverseHasMany && !inverseHasMany.includes(sourceRecord)) {
72
- inverseHasMany.push(sourceRecord);
73
- }
74
- }
75
-
76
- // Clear the pending queue
77
- pendingBelongsTo.length = 0;
78
- }
79
-
80
- return record;
81
- }
82
-
83
- export function updateRecord(record, rawData, userOptions={}) {
84
- if (!rawData) throw new Error('rawData must be passed in to updateRecord call');
85
-
86
- const options = { ...defaultOptions, ...userOptions, update:true };
87
-
88
- record.serialize(rawData, options);
89
- }
90
-
91
- /**
92
- * gets the next available id based on last record entry.
93
- *
94
- * Note/TODO: Records going into a db should get their id from the db instead
95
- * Atm, i think the best way to do that would be as an id override that happens after the
96
- * record is created
97
- */
98
- function assignRecordId(modelName, rawData) {
99
- if (rawData.id) return;
100
-
101
- const modelStore = Array.from(store.get(modelName).values());
102
- rawData.id = modelStore.length ? modelStore.at(-1).id + 1 : 1;
103
- }
@@ -1,29 +0,0 @@
1
- import Orm from '@stonyx/orm';
2
-
3
- function validType(type) {
4
- return Object.keys(Orm.instance.transforms).includes(type);
5
- }
6
-
7
- export default class ModelProperty {
8
- constructor(type='passthrough', defaultValue) {
9
- if (!validType(type)) throw new Error(`Invalid model property type: ${type}`);
10
-
11
- this.type = type;
12
- this.value = defaultValue;
13
- }
14
-
15
- get value() {
16
- return this._value;
17
- }
18
-
19
- set value(newValue) {
20
- if (this.ignoreFirstTransform) {
21
- delete this.ignoreFirstTransform;
22
- return this._value = newValue;
23
- }
24
-
25
- if (newValue === undefined || newValue === null) return;
26
-
27
- this._value = Orm.instance.transforms[this.type](newValue);
28
- }
29
- }
package/src/model.js DELETED
@@ -1,9 +0,0 @@
1
- import { attr } from '@stonyx/orm';
2
-
3
- export default class Model {
4
- id = attr('number');
5
-
6
- constructor(name) {
7
- this.__name = name;
8
- }
9
- }