@cedarjs/record 0.0.4

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Cedar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # RedwoodRecord
2
+
3
+ RedwoodRecord is an ORM ([Object-Relational Mapping](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping)) built on top of Prisma. It may be extended in the future to wrap other database access packages.
4
+
5
+ RedwoodRecord is heavily inspired by [ActiveRecord](https://guides.rubyonrails.org/active_record_basics.html) which ships with [Ruby on Rails](https://rubyonrails.org). It presents a natural interface to the underlying data in your database, without worry about the particulars of SQL syntax.
6
+
7
+ ## Usage
8
+
9
+ Usage documentation is available at https://redwoodjs.com/docs/redwoodrecord
10
+
11
+ ## Package Structure
12
+
13
+ RedwoodRecord is composed of 5 classes total:
14
+
15
+ 1. **Core** - provides core database access for a single model, enabling CRUD actions
16
+ 2. **Reflection** - parses the Prisma data schema and determines what relations exist to other models
17
+ 3. **RelationProxy** - provides access to related models reveales by the Reflection class
18
+ 4. **ValidationMixin** - adds validation support, adding error messages
19
+ 5. **RedwoodRecord** - combines the functionality of the other four classes into the standard base class that all models should extend from
20
+
21
+ There is also an `errors.js` file which contains all error messages that RedwoodRecord could throw.
22
+
23
+ ### Tasks
24
+
25
+ RedwoodRecord depends on reading the Prisma schema file to determine relations to other tables. In order to avoid the `async` wait when parsing the schema with Prisma's built-in function, we have a task which parses the schema file and then saves out a JSON version to the cache `.redwood` directory. This task also creates an `index.js` file in your `api/src/models` directory that imports the models themselves and also adds some configuration to support relations without a circular dependency. The models are then re-exported.
26
+
27
+ This task is run with:
28
+
29
+ ```
30
+ yarn rw record init
31
+ ```
32
+
33
+ This task needs to be run whenever you create a new model, or change your database schema in a way that would add/remove a relation to another model.
34
+
35
+ > We plan to make the task run automatically, watching for changes to your schema.prisma or models directory. But for now you'll need to run it manually!
@@ -0,0 +1,75 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var errors_exports = {};
19
+ __export(errors_exports, {
20
+ RedwoodRecordError: () => RedwoodRecordError,
21
+ RedwoodRecordMissingAttributeError: () => RedwoodRecordMissingAttributeError,
22
+ RedwoodRecordMissingRequiredModelError: () => RedwoodRecordMissingRequiredModelError,
23
+ RedwoodRecordNotFoundError: () => RedwoodRecordNotFoundError,
24
+ RedwoodRecordNullAttributeError: () => RedwoodRecordNullAttributeError,
25
+ RedwoodRecordUncaughtError: () => RedwoodRecordUncaughtError
26
+ });
27
+ module.exports = __toCommonJS(errors_exports);
28
+ var import_api = require("@cedarjs/api");
29
+ class RedwoodRecordError extends import_api.RedwoodError {
30
+ constructor() {
31
+ super();
32
+ this.name = "RedwoodRecordError";
33
+ }
34
+ }
35
+ class RedwoodRecordUncaughtError extends import_api.RedwoodError {
36
+ constructor(message) {
37
+ super(message);
38
+ this.name = "RedwoodRecordUncaughtError";
39
+ }
40
+ }
41
+ class RedwoodRecordNotFoundError extends import_api.RedwoodError {
42
+ constructor(name) {
43
+ super(`${name} record not found`);
44
+ this.name = "RedwoodRecordNotFoundError";
45
+ }
46
+ }
47
+ class RedwoodRecordNullAttributeError extends import_api.RedwoodError {
48
+ constructor(name) {
49
+ super(`${name} must not be null`);
50
+ this.name = "RedwoodRecordNullAttributeError";
51
+ }
52
+ }
53
+ class RedwoodRecordMissingAttributeError extends import_api.RedwoodError {
54
+ constructor(name) {
55
+ super(`${name} is missing`);
56
+ this.name = "RedwoodRecordMissingAttributeError";
57
+ }
58
+ }
59
+ class RedwoodRecordMissingRequiredModelError extends import_api.RedwoodError {
60
+ constructor(modelName, requiredModelName) {
61
+ super(
62
+ `Tried to build a relationship for ${requiredModelName} model but is not listed as a \`requiredModel\` in ${modelName}`
63
+ );
64
+ this.name = "RedwoodRecordMissingRequiredModelError";
65
+ }
66
+ }
67
+ // Annotate the CommonJS export names for ESM import in node:
68
+ 0 && (module.exports = {
69
+ RedwoodRecordError,
70
+ RedwoodRecordMissingAttributeError,
71
+ RedwoodRecordMissingRequiredModelError,
72
+ RedwoodRecordNotFoundError,
73
+ RedwoodRecordNullAttributeError,
74
+ RedwoodRecordUncaughtError
75
+ });
@@ -0,0 +1,54 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var index_exports = {};
30
+ __export(index_exports, {
31
+ Core: () => import_Core.default,
32
+ RedwoodRecord: () => import_RedwoodRecord.default,
33
+ Reflection: () => import_Reflection.default,
34
+ RelationProxy: () => import_RelationProxy.default,
35
+ ValidationMixin: () => import_ValidationMixin.default
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+ __reExport(index_exports, require("./errors"), module.exports);
39
+ var import_Core = __toESM(require("./redwoodrecord/Core"), 1);
40
+ var import_Reflection = __toESM(require("./redwoodrecord/Reflection"), 1);
41
+ var import_RelationProxy = __toESM(require("./redwoodrecord/RelationProxy"), 1);
42
+ var import_ValidationMixin = __toESM(require("./redwoodrecord/ValidationMixin"), 1);
43
+ var import_RedwoodRecord = __toESM(require("./redwoodrecord/RedwoodRecord"), 1);
44
+ __reExport(index_exports, require("./tasks/parse"), module.exports);
45
+ // Annotate the CommonJS export names for ESM import in node:
46
+ 0 && (module.exports = {
47
+ Core,
48
+ RedwoodRecord,
49
+ Reflection,
50
+ RelationProxy,
51
+ ValidationMixin,
52
+ ...require("./errors"),
53
+ ...require("./tasks/parse")
54
+ });
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,265 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var Core_exports = {};
29
+ __export(Core_exports, {
30
+ default: () => Core
31
+ });
32
+ module.exports = __toCommonJS(Core_exports);
33
+ var import_camelcase = __toESM(require("camelcase"), 1);
34
+ var Errors = __toESM(require("../errors"), 1);
35
+ class Core {
36
+ ////////////////////////////
37
+ // Public class properties
38
+ ////////////////////////////
39
+ // Set in child class to override DB accessor name. This is the name of the
40
+ // property you would call on an instance of Prisma Client in order the query
41
+ // a model in your schema. i.e. For the call `db.user` the accessorName is
42
+ // "user". Not setting this property will use the default camelCase version of
43
+ // the class name itself as the accessor.
44
+ //
45
+ // static accessorName = 'users'
46
+ static accessorName;
47
+ // Set in child class to override primary key field name for this model.
48
+ //
49
+ // static primaryKey = 'userId'
50
+ static primaryKey = "id";
51
+ // Parsed schema.prisma for use in subclasses
52
+ static schema = null;
53
+ // Any other model that may be required by this model
54
+ static requiredModels = [];
55
+ /////////////////////////
56
+ // Public class methods
57
+ /////////////////////////
58
+ // Access the raw Prisma Client for doing low level query manipulation
59
+ static db = null;
60
+ // Returns the Prisma DB accessor instance (ex. db.user)
61
+ static get accessor() {
62
+ return this.db[this.accessorName || (0, import_camelcase.default)(this.name)];
63
+ }
64
+ // Alias for where({})
65
+ static all(args) {
66
+ return this.where({}, args);
67
+ }
68
+ static build(attributes) {
69
+ const record = new this();
70
+ record.attributes = attributes;
71
+ return record;
72
+ }
73
+ // Create a new record. Instantiates a new instance and then calls .save() on it
74
+ static async create(attributes, options = {}) {
75
+ const record = this.build(attributes);
76
+ return await record.save(options);
77
+ }
78
+ // Find a single record by ID.
79
+ static async find(id, options = {}) {
80
+ const record = await this.findBy(
81
+ {
82
+ [this.primaryKey]: id,
83
+ ...options.where || {}
84
+ },
85
+ options
86
+ );
87
+ if (record === null) {
88
+ throw new Errors.RedwoodRecordNotFoundError(this.name);
89
+ }
90
+ return record;
91
+ }
92
+ // Returns the first record matching the given `where`, otherwise first in the
93
+ // whole table (whatever the DB determines is the first record)
94
+ static async findBy(attributes, options = {}) {
95
+ const record = await this.accessor.findFirst({
96
+ where: attributes,
97
+ ...options
98
+ });
99
+ return record ? await this.build(record) : null;
100
+ }
101
+ // Alias for findBy
102
+ static async first(...args) {
103
+ return this.findBy(...args);
104
+ }
105
+ // Find all records
106
+ static async where(attributes, options = {}) {
107
+ const records = await this.accessor.findMany({
108
+ where: attributes,
109
+ ...options
110
+ });
111
+ return Promise.all(
112
+ records.map(async (record) => {
113
+ return await this.build(record);
114
+ })
115
+ );
116
+ }
117
+ ///////////////////////////////
118
+ // Private instance properties
119
+ ///////////////////////////////
120
+ // Stores instance attributes object internally
121
+ #attributes = {};
122
+ ////////////////////////////
123
+ // Public instance methods
124
+ ////////////////////////////
125
+ constructor() {
126
+ }
127
+ get attributes() {
128
+ return this.#attributes;
129
+ }
130
+ set attributes(attrs) {
131
+ if (attrs) {
132
+ this.#attributes = attrs;
133
+ this._createPropertiesForAttributes();
134
+ }
135
+ }
136
+ async destroy(options = {}) {
137
+ const { throw: shouldThrow, ...rest } = options;
138
+ try {
139
+ await this.constructor.accessor.delete({
140
+ where: { [this.constructor.primaryKey]: this.attributes.id },
141
+ ...rest
142
+ });
143
+ return this;
144
+ } catch (e) {
145
+ this._deleteErrorHandler(e, shouldThrow);
146
+ return false;
147
+ }
148
+ }
149
+ // Saves the attributes to the database
150
+ async save(options = {}) {
151
+ const saveAttributes = JSON.parse(JSON.stringify(this.attributes));
152
+ try {
153
+ let newAttributes;
154
+ if (this.attributes[this.constructor.primaryKey]) {
155
+ delete saveAttributes[this.constructor.primaryKey];
156
+ newAttributes = await this.constructor.accessor.update({
157
+ where: {
158
+ [this.constructor.primaryKey]: this.attributes[this.constructor.primaryKey]
159
+ },
160
+ data: saveAttributes
161
+ });
162
+ } else {
163
+ newAttributes = await this.constructor.accessor.create({
164
+ data: saveAttributes
165
+ });
166
+ }
167
+ this.attributes = newAttributes;
168
+ } catch (e) {
169
+ this._saveErrorHandler(e, options.throw);
170
+ return false;
171
+ }
172
+ return this;
173
+ }
174
+ async update(attributes = {}, options = {}) {
175
+ this.#attributes = Object.assign(this.#attributes, attributes);
176
+ return await this.save(options);
177
+ }
178
+ ////////////////////////////
179
+ // Private instance methods
180
+ ////////////////////////////
181
+ // Turns a plain object's properties into getters/setters on the instance:
182
+ //
183
+ // const user = new User({ name: 'Rob' })
184
+ // user.name // => 'Rob'
185
+ _createPropertiesForAttributes() {
186
+ for (const [name, value] of Object.entries(this.attributes)) {
187
+ if (this.hasOwnProperty(name)) {
188
+ continue;
189
+ }
190
+ if (value && typeof value === "object" && (Object.keys(value).includes("create") || Object.keys(value).includes("connect"))) {
191
+ continue;
192
+ }
193
+ this._createPropertyForAttribute(name);
194
+ }
195
+ }
196
+ // Create property for a single attribute
197
+ _createPropertyForAttribute(name) {
198
+ Object.defineProperty(this, name, {
199
+ get() {
200
+ return this._attributeGetter(name);
201
+ },
202
+ set(value) {
203
+ this._attributeSetter(name, value);
204
+ },
205
+ enumerable: true
206
+ });
207
+ }
208
+ _attributeGetter(name) {
209
+ return this.#attributes[name];
210
+ }
211
+ _attributeSetter(name, value) {
212
+ return this.#attributes[name] = value;
213
+ }
214
+ _onSaveError(_name, _message) {
215
+ }
216
+ _deleteErrorHandler(error, shouldThrow) {
217
+ if (error.message.match(/Record to delete does not exist/)) {
218
+ this._onSaveError(
219
+ "base",
220
+ `${this.constructor.name} record to destroy not found`
221
+ );
222
+ if (shouldThrow) {
223
+ throw new Errors.RedwoodRecordNotFoundError();
224
+ }
225
+ } else {
226
+ this._onSaveError(
227
+ "base",
228
+ `${this.constructor.name} record threw uncaught error: ${error.message}`
229
+ );
230
+ if (shouldThrow) {
231
+ throw new Errors.RedwoodRecordUncaughtError(error.message);
232
+ }
233
+ }
234
+ }
235
+ // Handles errors from saving a record (either update or create), converting
236
+ // to this.#errors messages, or throwing RedwoodRecord errors
237
+ _saveErrorHandler(error, shouldThrow) {
238
+ if (error.message.match(/Record to update not found/)) {
239
+ this._onSaveError(
240
+ "base",
241
+ `${this.constructor.name} record to update not found`
242
+ );
243
+ if (shouldThrow) {
244
+ throw new Errors.RedwoodRecordNotFoundError(this.constructor.name);
245
+ }
246
+ } else if (error.message.match(/must not be null/)) {
247
+ const [_all, name] = error.message.match(/Argument (\w+)/);
248
+ this._onSaveError(name, "must not be null");
249
+ if (shouldThrow) {
250
+ throw new Errors.RedwoodRecordNullAttributeError(name);
251
+ }
252
+ } else if (error.message.match(/is missing/)) {
253
+ const [_all, name] = error.message.match(/Argument (\w+)/);
254
+ this._onSaveError("base", `${name} is missing`);
255
+ if (shouldThrow) {
256
+ throw new Errors.RedwoodRecordMissingAttributeError(name);
257
+ }
258
+ } else {
259
+ this._onSaveError("base", error.message);
260
+ if (shouldThrow) {
261
+ throw new Errors.RedwoodRecordUncaughtError(error.message);
262
+ }
263
+ }
264
+ }
265
+ }
@@ -0,0 +1,65 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var RedwoodRecord_exports = {};
29
+ __export(RedwoodRecord_exports, {
30
+ default: () => RedwoodRecord
31
+ });
32
+ module.exports = __toCommonJS(RedwoodRecord_exports);
33
+ var import_Core = __toESM(require("./Core"), 1);
34
+ var import_Reflection = __toESM(require("./Reflection"), 1);
35
+ var import_RelationProxy = __toESM(require("./RelationProxy"), 1);
36
+ var import_ValidationMixin = __toESM(require("./ValidationMixin"), 1);
37
+ class RedwoodRecord extends (0, import_ValidationMixin.default)(import_Core.default) {
38
+ static get reflect() {
39
+ return new import_Reflection.default(this);
40
+ }
41
+ // Call original build, but add related attributes
42
+ static build(attributes) {
43
+ const record = super.build(attributes);
44
+ import_RelationProxy.default.addRelations(record, this.constructor.schema);
45
+ return record;
46
+ }
47
+ // Don't even try to save if data isn't valid
48
+ async save(options = {}) {
49
+ if (this.validate({ throw: options.throw })) {
50
+ return await super.save(options);
51
+ } else {
52
+ return false;
53
+ }
54
+ }
55
+ // Call original method, but add error keys for validation
56
+ _createPropertyForAttribute(name) {
57
+ super._createPropertyForAttribute(name);
58
+ this._errors[name] = [];
59
+ }
60
+ // Add validation error on save error
61
+ _onSaveError(...args) {
62
+ super._onSaveError(...args);
63
+ this.addError(...args);
64
+ }
65
+ }
@@ -0,0 +1,100 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var Reflection_exports = {};
19
+ __export(Reflection_exports, {
20
+ default: () => Reflection
21
+ });
22
+ module.exports = __toCommonJS(Reflection_exports);
23
+ class Reflection {
24
+ #hasMany = null;
25
+ #belongsTo = null;
26
+ #attributes = null;
27
+ constructor(model) {
28
+ this.model = model;
29
+ }
30
+ get attributes() {
31
+ if (!this.#attributes) {
32
+ this.#parseAttributes();
33
+ }
34
+ return this.#attributes;
35
+ }
36
+ get belongsTo() {
37
+ if (!this.#belongsTo) {
38
+ this.#parseBelongsTo();
39
+ }
40
+ return this.#belongsTo;
41
+ }
42
+ get hasMany() {
43
+ if (!this.#hasMany) {
44
+ this.#parseHasMany();
45
+ }
46
+ return this.#hasMany;
47
+ }
48
+ // Finds the schema for a single model
49
+ #schemaForModel(name = this.model.name) {
50
+ return this.model.schema.models.find((model) => model.name === name);
51
+ }
52
+ #parseHasMany() {
53
+ const selfSchema = this.#schemaForModel();
54
+ this.#hasMany = {};
55
+ selfSchema?.fields?.forEach((field) => {
56
+ if (field.isList) {
57
+ const otherSchema = this.#schemaForModel(field.type);
58
+ const belongsTo = otherSchema.fields.find(
59
+ (field2) => field2.type === this.model.name
60
+ );
61
+ this.#hasMany[field.name] = {
62
+ modelName: field.type,
63
+ referenceName: belongsTo.name,
64
+ // a null foreign key denotes an implicit many-to-many relationship
65
+ foreignKey: belongsTo.relationFromFields[0] || null,
66
+ primaryKey: belongsTo.relationToFields[0]
67
+ };
68
+ }
69
+ });
70
+ }
71
+ #parseBelongsTo() {
72
+ const selfSchema = this.#schemaForModel();
73
+ this.#belongsTo = {};
74
+ selfSchema?.fields?.forEach((field) => {
75
+ if (field.relationFromFields?.length) {
76
+ this.#belongsTo[field.name] = {
77
+ modelName: field.type,
78
+ foreignKey: field.relationFromFields[0],
79
+ primaryKey: field.relationToFields[0]
80
+ };
81
+ }
82
+ });
83
+ }
84
+ #parseAttributes() {
85
+ const selfSchema = this.#schemaForModel();
86
+ this.#attributes = {};
87
+ if (!this.#hasMany) {
88
+ this.#parseHasMany();
89
+ }
90
+ if (!this.belongsTo) {
91
+ this.#parseBelongsTo();
92
+ }
93
+ selfSchema?.fields?.forEach((field) => {
94
+ const { name, ...props } = field;
95
+ if (!Object.keys(this.#hasMany).includes(name) && !Object.keys(this.#belongsTo).includes(name)) {
96
+ this.#attributes[name] = props;
97
+ }
98
+ });
99
+ }
100
+ }