@stonyx/orm 0.2.1-beta.83 → 0.2.1-beta.85

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 (150) hide show
  1. package/dist/aggregates.d.ts +21 -0
  2. package/dist/aggregates.js +90 -0
  3. package/dist/attr.d.ts +2 -0
  4. package/dist/attr.js +22 -0
  5. package/dist/belongs-to.d.ts +11 -0
  6. package/dist/belongs-to.js +59 -0
  7. package/dist/cli.d.ts +22 -0
  8. package/dist/cli.js +148 -0
  9. package/dist/commands.d.ts +7 -0
  10. package/dist/commands.js +146 -0
  11. package/dist/db.d.ts +21 -0
  12. package/dist/db.js +174 -0
  13. package/dist/exports/db.d.ts +7 -0
  14. package/{src → dist}/exports/db.js +2 -4
  15. package/dist/has-many.d.ts +11 -0
  16. package/dist/has-many.js +58 -0
  17. package/dist/hooks.d.ts +47 -0
  18. package/dist/hooks.js +106 -0
  19. package/dist/index.d.ts +14 -0
  20. package/dist/index.js +34 -0
  21. package/dist/main.d.ts +46 -0
  22. package/dist/main.js +179 -0
  23. package/dist/manage-record.d.ts +13 -0
  24. package/dist/manage-record.js +114 -0
  25. package/dist/meta-request.d.ts +6 -0
  26. package/dist/meta-request.js +52 -0
  27. package/dist/migrate.d.ts +2 -0
  28. package/dist/migrate.js +57 -0
  29. package/dist/model-property.d.ts +9 -0
  30. package/dist/model-property.js +29 -0
  31. package/dist/model.d.ts +15 -0
  32. package/dist/model.js +18 -0
  33. package/dist/mysql/connection.d.ts +14 -0
  34. package/dist/mysql/connection.js +24 -0
  35. package/dist/mysql/migration-generator.d.ts +45 -0
  36. package/dist/mysql/migration-generator.js +245 -0
  37. package/dist/mysql/migration-runner.d.ts +12 -0
  38. package/dist/mysql/migration-runner.js +83 -0
  39. package/dist/mysql/mysql-db.d.ts +100 -0
  40. package/dist/mysql/mysql-db.js +415 -0
  41. package/dist/mysql/query-builder.d.ts +10 -0
  42. package/dist/mysql/query-builder.js +44 -0
  43. package/dist/mysql/schema-introspector.d.ts +19 -0
  44. package/dist/mysql/schema-introspector.js +286 -0
  45. package/dist/mysql/type-map.d.ts +21 -0
  46. package/dist/mysql/type-map.js +36 -0
  47. package/dist/orm-request.d.ts +38 -0
  48. package/dist/orm-request.js +455 -0
  49. package/dist/plural-registry.d.ts +4 -0
  50. package/{src → dist}/plural-registry.js +3 -6
  51. package/dist/postgres/connection.d.ts +15 -0
  52. package/dist/postgres/connection.js +30 -0
  53. package/dist/postgres/migration-generator.d.ts +45 -0
  54. package/dist/postgres/migration-generator.js +257 -0
  55. package/dist/postgres/migration-runner.d.ts +10 -0
  56. package/dist/postgres/migration-runner.js +82 -0
  57. package/dist/postgres/postgres-db.d.ts +119 -0
  58. package/dist/postgres/postgres-db.js +476 -0
  59. package/dist/postgres/query-builder.d.ts +27 -0
  60. package/dist/postgres/query-builder.js +98 -0
  61. package/dist/postgres/schema-introspector.d.ts +29 -0
  62. package/dist/postgres/schema-introspector.js +309 -0
  63. package/dist/postgres/type-map.d.ts +23 -0
  64. package/dist/postgres/type-map.js +53 -0
  65. package/dist/record.d.ts +75 -0
  66. package/dist/record.js +115 -0
  67. package/dist/relationships.d.ts +10 -0
  68. package/dist/relationships.js +39 -0
  69. package/dist/serializer.d.ts +17 -0
  70. package/dist/serializer.js +136 -0
  71. package/dist/setup-rest-server.d.ts +1 -0
  72. package/dist/setup-rest-server.js +54 -0
  73. package/dist/standalone-db.d.ts +58 -0
  74. package/dist/standalone-db.js +142 -0
  75. package/dist/store.d.ts +62 -0
  76. package/dist/store.js +271 -0
  77. package/dist/timescale/query-builder.d.ts +41 -0
  78. package/dist/timescale/query-builder.js +87 -0
  79. package/dist/timescale/timescale-db.d.ts +45 -0
  80. package/dist/timescale/timescale-db.js +84 -0
  81. package/dist/transforms.d.ts +2 -0
  82. package/dist/transforms.js +17 -0
  83. package/dist/types/orm-types.d.ts +142 -0
  84. package/dist/types/orm-types.js +1 -0
  85. package/dist/utils.d.ts +5 -0
  86. package/dist/utils.js +13 -0
  87. package/dist/view-resolver.d.ts +8 -0
  88. package/dist/view-resolver.js +169 -0
  89. package/dist/view.d.ts +11 -0
  90. package/dist/view.js +18 -0
  91. package/package.json +34 -11
  92. package/src/{aggregates.js → aggregates.ts} +27 -13
  93. package/src/{attr.js → attr.ts} +2 -2
  94. package/src/belongs-to.ts +90 -0
  95. package/src/{cli.js → cli.ts} +17 -11
  96. package/src/{commands.js → commands.ts} +179 -170
  97. package/src/{db.js → db.ts} +35 -26
  98. package/src/exports/db.ts +7 -0
  99. package/src/has-many.ts +92 -0
  100. package/src/{hooks.js → hooks.ts} +23 -27
  101. package/src/{index.js → index.ts} +4 -4
  102. package/src/{main.js → main.ts} +60 -34
  103. package/src/{manage-record.js → manage-record.ts} +42 -22
  104. package/src/{meta-request.js → meta-request.ts} +17 -14
  105. package/src/{migrate.js → migrate.ts} +9 -9
  106. package/src/{model-property.js → model-property.ts} +12 -6
  107. package/src/{model.js → model.ts} +5 -4
  108. package/src/mysql/{connection.js → connection.ts} +43 -28
  109. package/src/mysql/{migration-generator.js → migration-generator.ts} +332 -286
  110. package/src/mysql/{migration-runner.js → migration-runner.ts} +116 -110
  111. package/src/mysql/{mysql-db.js → mysql-db.ts} +537 -473
  112. package/src/mysql/{query-builder.js → query-builder.ts} +69 -64
  113. package/src/mysql/{schema-introspector.js → schema-introspector.ts} +355 -325
  114. package/src/mysql/{type-map.js → type-map.ts} +42 -37
  115. package/src/{orm-request.js → orm-request.ts} +169 -97
  116. package/src/plural-registry.ts +12 -0
  117. package/src/postgres/{connection.js → connection.ts} +14 -5
  118. package/src/postgres/{migration-generator.js → migration-generator.ts} +82 -38
  119. package/src/postgres/{migration-runner.js → migration-runner.ts} +11 -10
  120. package/src/postgres/{postgres-db.js → postgres-db.ts} +198 -114
  121. package/src/postgres/{query-builder.js → query-builder.ts} +27 -28
  122. package/src/postgres/{schema-introspector.js → schema-introspector.ts} +87 -58
  123. package/src/postgres/{type-map.js → type-map.ts} +10 -6
  124. package/src/{record.js → record.ts} +73 -34
  125. package/src/relationships.ts +53 -0
  126. package/src/{serializer.js → serializer.ts} +52 -36
  127. package/src/{setup-rest-server.js → setup-rest-server.ts} +18 -13
  128. package/src/{standalone-db.js → standalone-db.ts} +33 -24
  129. package/src/{store.js → store.ts} +90 -68
  130. package/src/timescale/{query-builder.js → query-builder.ts} +33 -38
  131. package/src/timescale/timescale-db.ts +119 -0
  132. package/src/transforms.ts +20 -0
  133. package/src/types/mysql2.d.ts +30 -0
  134. package/src/types/orm-types.ts +146 -0
  135. package/src/types/pg.d.ts +28 -0
  136. package/src/types/stonyx-cron.d.ts +5 -0
  137. package/src/types/stonyx-events.d.ts +4 -0
  138. package/src/types/stonyx-rest-server.d.ts +11 -0
  139. package/src/types/stonyx-utils.d.ts +33 -0
  140. package/src/types/stonyx.d.ts +21 -0
  141. package/src/utils.ts +16 -0
  142. package/src/{view-resolver.js → view-resolver.ts} +51 -24
  143. package/src/view.ts +22 -0
  144. package/src/belongs-to.js +0 -70
  145. package/src/has-many.js +0 -68
  146. package/src/relationships.js +0 -43
  147. package/src/timescale/timescale-db.js +0 -111
  148. package/src/transforms.js +0 -20
  149. package/src/utils.js +0 -12
  150. package/src/view.js +0 -21
@@ -0,0 +1,146 @@
1
+ import type { AggregateProperty } from '../aggregates.js';
2
+
3
+ export interface OrmDbConfig {
4
+ file: string;
5
+ schema: string;
6
+ mode: string;
7
+ directory: string;
8
+ autosave: string;
9
+ saveInterval: unknown;
10
+ }
11
+
12
+ export interface OrmMysqlConfig {
13
+ host: string;
14
+ port?: number;
15
+ user: string;
16
+ password: string;
17
+ database: string;
18
+ connectionLimit?: number;
19
+ migrationsDir?: string;
20
+ migrationsTable?: string;
21
+ [key: string]: unknown;
22
+ }
23
+
24
+ export interface OrmPostgresConfig {
25
+ host: string;
26
+ port: number;
27
+ user: string;
28
+ password: string;
29
+ database: string;
30
+ connectionLimit?: number;
31
+ migrationsDir?: string;
32
+ migrationsTable?: string;
33
+ [key: string]: unknown;
34
+ }
35
+
36
+ export interface OrmPaths {
37
+ model: string;
38
+ serializer: string;
39
+ transform: string;
40
+ view?: string;
41
+ access?: string;
42
+ [key: string]: string | undefined;
43
+ }
44
+
45
+ export interface OrmRestServerConfig {
46
+ enabled: string;
47
+ route: string;
48
+ metaRoute: boolean;
49
+ }
50
+
51
+ export interface OrmSection {
52
+ db: OrmDbConfig;
53
+ paths: OrmPaths;
54
+ restServer: OrmRestServerConfig;
55
+ mysql?: OrmMysqlConfig;
56
+ postgres?: OrmPostgresConfig;
57
+ timescale?: OrmPostgresConfig;
58
+ [key: string]: unknown;
59
+ }
60
+
61
+ export interface OrmConfig {
62
+ rootPath: string;
63
+ orm: OrmSection;
64
+ [key: string]: unknown;
65
+ }
66
+
67
+ export interface SourceRecord {
68
+ __model: { __name: string; [key: string]: unknown };
69
+ __data?: Record<string, unknown>;
70
+ __relationships?: Record<string, unknown>;
71
+ id: unknown;
72
+ [key: string]: unknown;
73
+ }
74
+
75
+ export interface OrmRecord {
76
+ id: string | number | unknown;
77
+ __model?: { __name: string };
78
+ __data: Record<string, unknown> & { id?: unknown; __pendingSqlId?: boolean };
79
+ __relationships: Record<string, unknown>;
80
+ toJSON?(options?: { fields?: Set<string>; baseUrl?: string }): unknown;
81
+ [key: string]: unknown;
82
+ }
83
+
84
+ export interface ForeignKeyDef {
85
+ references: string;
86
+ column: string;
87
+ }
88
+
89
+ export interface ModelSchema {
90
+ table: string;
91
+ idType: string;
92
+ columns: Record<string, string>;
93
+ foreignKeys: Record<string, ForeignKeyDef>;
94
+ relationships: {
95
+ belongsTo: Record<string, string | null>;
96
+ hasMany: Record<string, string | null>;
97
+ };
98
+ vectorColumns?: Record<string, number>;
99
+ memory: boolean;
100
+ }
101
+
102
+ export interface ViewSchema {
103
+ viewName: string;
104
+ source: string;
105
+ groupBy?: string;
106
+ columns: Record<string, string>;
107
+ foreignKeys: Record<string, ForeignKeyDef>;
108
+ aggregates: Record<string, AggregateProperty>;
109
+ relationships: {
110
+ belongsTo: Record<string, string | null>;
111
+ hasMany: Record<string, string | null>;
112
+ };
113
+ isView: boolean;
114
+ memory: boolean;
115
+ }
116
+
117
+ /**
118
+ * Typed relationship registry maps.
119
+ * Each key in Orm.relationships stores a different nested Map structure.
120
+ */
121
+ /** Relationship registry map types — source → target → recordId → value */
122
+ export type HasManyMap = Map<string, Map<string, Map<unknown, unknown[]>>>;
123
+ export type BelongsToMap = Map<string, Map<string, Map<unknown, unknown>>>;
124
+ export type GlobalMap = Map<string, unknown[][]>;
125
+ export type PendingMap = Map<string, Map<unknown, unknown[][]>>;
126
+ export type PendingBelongsToMap = Map<string, Map<unknown, unknown[]>>;
127
+
128
+ export interface RelationshipMaps {
129
+ hasMany: HasManyMap;
130
+ belongsTo: BelongsToMap;
131
+ global: GlobalMap;
132
+ pending: PendingMap;
133
+ pendingBelongsTo: PendingBelongsToMap;
134
+ }
135
+
136
+ export interface SnapshotEntry {
137
+ table?: string;
138
+ idType?: string;
139
+ columns?: Record<string, string>;
140
+ foreignKeys?: Record<string, ForeignKeyDef>;
141
+ vectorColumns?: Record<string, number>;
142
+ isView?: boolean;
143
+ viewName?: string;
144
+ source?: string;
145
+ viewQuery?: string;
146
+ }
@@ -0,0 +1,28 @@
1
+ declare module 'pg' {
2
+ interface PoolConfig {
3
+ host?: string;
4
+ user?: string;
5
+ password?: string;
6
+ database?: string;
7
+ port?: number;
8
+ [key: string]: unknown;
9
+ }
10
+
11
+ interface QueryResult {
12
+ rows: Record<string, unknown>[];
13
+ rowCount: number;
14
+ fields?: { name: string }[];
15
+ }
16
+
17
+ export class Pool {
18
+ constructor(config?: PoolConfig);
19
+ query(sql: string, params?: unknown[]): Promise<QueryResult>;
20
+ connect(): Promise<PoolClient>;
21
+ end(): Promise<void>;
22
+ }
23
+
24
+ export class PoolClient {
25
+ query(sql: string, params?: unknown[]): Promise<QueryResult>;
26
+ release(): void;
27
+ }
28
+ }
@@ -0,0 +1,5 @@
1
+ declare module '@stonyx/cron' {
2
+ export default class Cron {
3
+ register(name: string, fn: () => void | Promise<void>, interval: unknown): void;
4
+ }
5
+ }
@@ -0,0 +1,4 @@
1
+ declare module '@stonyx/events' {
2
+ export function setup(events: string[]): void;
3
+ export function emit(event: string, ...args: unknown[]): Promise<void>;
4
+ }
@@ -0,0 +1,11 @@
1
+ declare module '@stonyx/rest-server' {
2
+ export class Request {
3
+ constructor(...args: unknown[]);
4
+ }
5
+
6
+ export default class RestServer {
7
+ static instance: RestServer;
8
+ static close(): void;
9
+ mountRoute(RequestClass: unknown, options: { name: string; options?: unknown }): void;
10
+ }
11
+ }
@@ -0,0 +1,33 @@
1
+ declare module '@stonyx/utils/file' {
2
+ export function createFile(path: string, data: unknown, options?: { json?: boolean }): Promise<void>;
3
+ export function createDirectory(path: string): Promise<void>;
4
+ export function updateFile(path: string, data: unknown, options?: { json?: boolean }): Promise<void>;
5
+ export function readFile(path: string, options?: { json?: boolean; missingFileCallback?: () => Promise<unknown> }): Promise<unknown>;
6
+ export function fileExists(path: string): Promise<boolean>;
7
+ export function deleteDirectory(path: string): Promise<void>;
8
+ export function forEachFileImport(
9
+ path: string,
10
+ callback: (exported: unknown, meta: { name: string }) => unknown,
11
+ options?: { ignoreAccessFailure?: boolean; rawName?: boolean; recursive?: boolean; recursiveNaming?: boolean }
12
+ ): Promise<void>;
13
+ }
14
+
15
+ declare module '@stonyx/utils/string' {
16
+ export function pluralize(word: string): string;
17
+ export function kebabCaseToPascalCase(str: string): string;
18
+ export function camelCaseToKebabCase(str: string): string;
19
+ }
20
+
21
+ declare module '@stonyx/utils/object' {
22
+ export function get(obj: unknown, path: string): unknown;
23
+ export function getOrSet<T>(map: Map<unknown, T>, key: unknown, defaultValue: T): T;
24
+ export function makeArray<T>(value: T | T[]): T[];
25
+ }
26
+
27
+ declare module '@stonyx/utils/date' {
28
+ export function getTimestamp(value?: unknown): number;
29
+ }
30
+
31
+ declare module '@stonyx/utils/prompt' {
32
+ export function confirm(message: string): Promise<boolean>;
33
+ }
@@ -0,0 +1,21 @@
1
+ declare module 'stonyx/config' {
2
+ import type { OrmConfig } from './orm-types.js';
3
+ const config: OrmConfig;
4
+ export default config;
5
+ }
6
+
7
+ declare module 'stonyx/log' {
8
+ const log: Record<string, ((...args: unknown[]) => void) | undefined>;
9
+ export default log;
10
+ }
11
+
12
+ declare module 'stonyx' {
13
+ export function waitForModule(name: string): Promise<void>;
14
+ }
15
+
16
+ declare module 'stonyx/test-helpers' {
17
+ export function setupIntegrationTests(hooks: {
18
+ before(fn: () => void | Promise<void>): void;
19
+ after(fn: () => void | Promise<void>): void;
20
+ }): void;
21
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { pluralize as basePluralize } from '@stonyx/utils/string';
2
+
3
+ export function isDbError(error: unknown): error is { code: string; message: string } {
4
+ return typeof error === 'object' && error !== null && 'code' in error && typeof (error as Record<string, unknown>).code === 'string' && 'message' in error && typeof (error as Record<string, unknown>).message === 'string';
5
+ }
6
+
7
+ // Wrapper to handle dasherized model names (e.g., "access-link" → "access-links")
8
+ export function pluralize(word: string): string {
9
+ if (word.includes('-')) {
10
+ const parts = word.split('-');
11
+ const pluralizedLast = basePluralize(parts.pop()!);
12
+ return [...parts, pluralizedLast].join('-');
13
+ }
14
+
15
+ return basePluralize(word);
16
+ }
@@ -1,30 +1,41 @@
1
- import Orm, { createRecord, store } from '@stonyx/orm';
1
+ import Orm, { store } from '@stonyx/orm';
2
+ import { createRecord } from './manage-record.js';
2
3
  import { AggregateProperty } from './aggregates.js';
3
4
  import { get } from '@stonyx/utils/object';
5
+ import type { SourceRecord } from './types/orm-types.js';
6
+
7
+ interface ViewClass {
8
+ source?: string;
9
+ resolve?: Record<string, unknown>;
10
+ groupBy?: string;
11
+ new (viewName: string): Record<string, unknown>;
12
+ }
4
13
 
5
14
  export default class ViewResolver {
6
- constructor(viewName) {
15
+ viewName: string;
16
+
17
+ constructor(viewName: string) {
7
18
  this.viewName = viewName;
8
19
  }
9
20
 
10
- async resolveAll() {
21
+ async resolveAll(): Promise<unknown[]> {
11
22
  const orm = Orm.instance;
12
- const { modelClass: viewClass } = orm.getRecordClasses(this.viewName);
23
+ const { modelClass: viewClass } = orm.getRecordClasses(this.viewName) as { modelClass: ViewClass | undefined; serializerClass: unknown };
13
24
 
14
25
  if (!viewClass) return [];
15
26
 
16
27
  const source = viewClass.source;
17
28
  if (!source) return [];
18
29
 
19
- const sourceRecords = await store.findAll(source);
30
+ const sourceRecords = await store.findAll(source) as SourceRecord[];
20
31
  if (!sourceRecords || sourceRecords.length === 0) {
21
32
  return [];
22
33
  }
23
34
 
24
35
  const resolveMap = viewClass.resolve || {};
25
36
  const viewInstance = new viewClass(this.viewName);
26
- const aggregateFields = {};
27
- const regularFields = {};
37
+ const aggregateFields: Record<string, AggregateProperty> = {};
38
+ const regularFields: Record<string, unknown> = {};
28
39
 
29
40
  // Categorize fields on the view instance
30
41
  for (const [key, value] of Object.entries(viewInstance)) {
@@ -48,14 +59,21 @@ export default class ViewResolver {
48
59
  return this._resolvePerRecord(sourceRecords, aggregateFields, regularFields, resolveMap, viewClass);
49
60
  }
50
61
 
51
- _resolvePerRecord(sourceRecords, aggregateFields, regularFields, resolveMap, viewClass) {
52
- const results = [];
62
+ private _resolvePerRecord(
63
+ sourceRecords: SourceRecord[],
64
+ aggregateFields: Record<string, AggregateProperty>,
65
+ regularFields: Record<string, unknown>,
66
+ resolveMap: Record<string, unknown>,
67
+ viewClass: ViewClass
68
+ ): unknown[] {
69
+ const results: unknown[] = [];
53
70
 
54
71
  for (const sourceRecord of sourceRecords) {
55
- const rawData = { id: sourceRecord.id };
72
+ const rawData: Record<string, unknown> = { id: sourceRecord.id };
56
73
 
57
74
  // Compute aggregate fields from source record's relationships
58
75
  for (const [key, aggProp] of Object.entries(aggregateFields)) {
76
+ if (!aggProp.relationship) continue;
59
77
  const relatedRecords = sourceRecord.__relationships?.[aggProp.relationship]
60
78
  || sourceRecord[aggProp.relationship];
61
79
  const relArray = Array.isArray(relatedRecords) ? relatedRecords : [];
@@ -93,8 +111,8 @@ export default class ViewResolver {
93
111
 
94
112
  // Clear existing record from store to allow re-resolution
95
113
  const viewStore = store.get(this.viewName);
96
- if (viewStore?.has(rawData.id)) {
97
- viewStore.delete(rawData.id);
114
+ if (viewStore?.has(rawData.id as number | string)) {
115
+ viewStore.delete(rawData.id as number | string);
98
116
  }
99
117
 
100
118
  const record = createRecord(this.viewName, rawData, { isDbRecord: true });
@@ -104,21 +122,28 @@ export default class ViewResolver {
104
122
  return results;
105
123
  }
106
124
 
107
- _resolveGroupBy(sourceRecords, groupByField, aggregateFields, regularFields, resolveMap, viewClass) {
125
+ private _resolveGroupBy(
126
+ sourceRecords: SourceRecord[],
127
+ groupByField: string,
128
+ aggregateFields: Record<string, AggregateProperty>,
129
+ regularFields: Record<string, unknown>,
130
+ resolveMap: Record<string, unknown>,
131
+ viewClass: ViewClass
132
+ ): unknown[] {
108
133
  // Group source records by the groupBy field value
109
- const groups = new Map();
134
+ const groups = new Map<unknown, SourceRecord[]>();
110
135
  for (const record of sourceRecords) {
111
136
  const key = record.__data?.[groupByField] ?? record[groupByField];
112
137
  if (!groups.has(key)) {
113
138
  groups.set(key, []);
114
139
  }
115
- groups.get(key).push(record);
140
+ groups.get(key)!.push(record);
116
141
  }
117
142
 
118
- const results = [];
143
+ const results: unknown[] = [];
119
144
 
120
145
  for (const [groupKey, groupRecords] of groups) {
121
- const rawData = { id: groupKey };
146
+ const rawData: Record<string, unknown> = { id: groupKey };
122
147
 
123
148
  // Compute aggregate fields
124
149
  for (const [key, aggProp] of Object.entries(aggregateFields)) {
@@ -127,7 +152,8 @@ export default class ViewResolver {
127
152
  rawData[key] = aggProp.compute(groupRecords);
128
153
  } else {
129
154
  // Relationship aggregate — flatten related records across all group members
130
- const allRelated = [];
155
+ if (!aggProp.relationship) continue;
156
+ const allRelated: unknown[] = [];
131
157
  for (const record of groupRecords) {
132
158
  const relatedRecords = record.__relationships?.[aggProp.relationship]
133
159
  || record[aggProp.relationship];
@@ -135,7 +161,7 @@ export default class ViewResolver {
135
161
  allRelated.push(...relatedRecords);
136
162
  }
137
163
  }
138
- rawData[key] = aggProp.compute(allRelated);
164
+ rawData[key] = aggProp.compute(allRelated as { __data?: Record<string, unknown>; [key: string]: unknown }[]);
139
165
  }
140
166
  }
141
167
 
@@ -163,8 +189,8 @@ export default class ViewResolver {
163
189
 
164
190
  // Clear existing record from store to allow re-resolution
165
191
  const viewStore = store.get(this.viewName);
166
- if (viewStore?.has(rawData.id)) {
167
- viewStore.delete(rawData.id);
192
+ if (viewStore?.has(rawData.id as number | string)) {
193
+ viewStore.delete(rawData.id as number | string);
168
194
  }
169
195
 
170
196
  const record = createRecord(this.viewName, rawData, { isDbRecord: true });
@@ -174,10 +200,11 @@ export default class ViewResolver {
174
200
  return results;
175
201
  }
176
202
 
177
- async resolveOne(id) {
203
+ async resolveOne(id: unknown): Promise<unknown> {
178
204
  const all = await this.resolveAll();
179
- return all.find(record => {
180
- return record.id === id || record.id == id;
205
+ return all.find((record: unknown) => {
206
+ const r = record as SourceRecord;
207
+ return r.id === id || r.id == id;
181
208
  });
182
209
  }
183
210
  }
package/src/view.ts ADDED
@@ -0,0 +1,22 @@
1
+ import attr from './attr.js';
2
+
3
+ export default class View {
4
+ static memory: boolean = false;
5
+ static readOnly: boolean = true;
6
+ static pluralName: string | undefined = undefined;
7
+ static source: string | undefined = undefined;
8
+ static groupBy: string | undefined = undefined;
9
+ static resolve: ((record: unknown) => unknown) | undefined = undefined;
10
+
11
+ id = attr('number');
12
+ __name: string;
13
+
14
+ constructor(name: string) {
15
+ this.__name = name;
16
+
17
+ // Enforce readOnly — cannot be overridden to false
18
+ if ((this.constructor as typeof View).readOnly !== true) {
19
+ throw new Error(`View '${name}' cannot override readOnly to false`);
20
+ }
21
+ }
22
+ }
package/src/belongs-to.js DELETED
@@ -1,70 +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
- const fn = (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
- let output;
25
-
26
- if (typeof rawData === 'object') {
27
- output = createRecord(modelName, rawData, options);
28
- } else if (modelStore) {
29
- output = modelStore.get(rawData);
30
- }
31
-
32
- // If not found and is a string ID, register as pending
33
- if (!output && typeof rawData !== 'object') {
34
- const targetId = rawData;
35
-
36
- // Register pending belongsTo
37
- const modelPendingMap = getOrSet(pendingBelongsToQueue, modelName, new Map());
38
- const targetPendingArray = getOrSet(modelPendingMap, targetId, []);
39
-
40
- targetPendingArray.push({
41
- sourceRecord,
42
- sourceModelName,
43
- relationshipKey,
44
- relationshipId
45
- });
46
-
47
- relationship.set(relationshipId, null);
48
- return null;
49
- }
50
-
51
- relationship.set(relationshipId, output || {});
52
-
53
- // Populate hasMany side if the relationship is defined
54
- const otherSide = hasManyRelationships.get(modelName)?.get(sourceModelName)?.get(output?.id);
55
-
56
- if (otherSide) {
57
- otherSide.push(sourceRecord);
58
-
59
- // Remove pending queue if it was just fulfilled
60
- const pendingModelRelationships = pendingHasManyQueue.get(sourceModelName);
61
-
62
- if (pendingModelRelationships) pendingModelRelationships.delete(relationshipId);
63
- }
64
-
65
- return output;
66
- }
67
-
68
- Object.defineProperty(fn, '__relatedModelName', { value: modelName });
69
- return fn;
70
- }
package/src/has-many.js DELETED
@@ -1,68 +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
- const fn = (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
- if (!modelStore) {
31
- return queuePendingRelationship(pendingRelationshipQueue, pendingRelationships, modelName, elementData);
32
- }
33
-
34
- record = modelStore.get(elementData);
35
-
36
- if (!record) {
37
- return queuePendingRelationship(pendingRelationshipQueue, pendingRelationships, modelName, elementData);
38
- }
39
- } else {
40
- if (elementData !== Object(elementData)) {
41
- return queuePendingRelationship(pendingRelationshipQueue, pendingRelationships, modelName, elementData);
42
- }
43
-
44
- record = createRecord(modelName, elementData, options);
45
- }
46
-
47
- // Populate belongTo side if the relationship is defined
48
- const otherSide = relationships.get('belongsTo').get(modelName)?.get(sourceModelName)?.get(record.id);
49
-
50
- if (otherSide) Object.assign(otherSide, sourceRecord);
51
-
52
- return record;
53
- }).filter(value => value);
54
-
55
- relationship.set(relationshipId, output);
56
-
57
- // Assign global relationship
58
- if (options.global || sourceModelName === dbKey) getOrSet(globalRelationships, modelName, []).push(output);
59
-
60
- // Assign pending relationships
61
- for (const { pendingRelationship, id } of pendingRelationshipQueue) getOrSet(pendingRelationship, id, []).push(output);
62
-
63
- return output;
64
- }
65
-
66
- Object.defineProperty(fn, '__relatedModelName', { value: modelName });
67
- return fn;
68
- }
@@ -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'];