@zudojs/database 1.2.0 → 1.2.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.
@@ -303,19 +303,24 @@ export async function getOrSet(cache, key, loader, options) {
303
303
  const pending = inflight.get(key);
304
304
  if (pending)
305
305
  return pending;
306
+ // The cleanup lives outside the promise: the body runs synchronously up to
307
+ // its first `await`, so a loader that throws synchronously would otherwise
308
+ // run the cleanup before the entry is registered and leave the rejected
309
+ // promise cached for the lifetime of the cache.
306
310
  const promise = (async () => {
307
- try {
308
- const value = await loader();
309
- if (value !== undefined)
310
- cache.set(key, value, options);
311
- return value;
312
- }
313
- finally {
314
- inflight.delete(key);
315
- }
311
+ const value = await loader();
312
+ if (value !== undefined)
313
+ cache.set(key, value, options);
314
+ return value;
316
315
  })();
317
316
  inflight.set(key, promise);
318
- return promise;
317
+ try {
318
+ return await promise;
319
+ }
320
+ finally {
321
+ if (inflight.get(key) === promise)
322
+ inflight.delete(key);
323
+ }
319
324
  }
320
325
  /**
321
326
  * Invalidates all entries whose keys start with a prefix.
@@ -84,6 +84,23 @@ export function validateInclude(include) {
84
84
  validateInclude(nested);
85
85
  }
86
86
  }
87
+ /**
88
+ * Validates a single include level: its shape, relation name and select
89
+ * fields, leaving nested includes to the caller.
90
+ *
91
+ * `buildInclude` uses this so the depth bound applies per level — a
92
+ * recursive validation would walk the whole caller-supplied subtree before
93
+ * the depth guard could refuse it.
94
+ */
95
+ function validateIncludeLevel(include) {
96
+ if (!include || typeof include !== "object") {
97
+ throw new TypeError("A relation include is required.");
98
+ }
99
+ validateRelationName(include.relation);
100
+ for (const field of include.select ?? []) {
101
+ validateFieldName(field);
102
+ }
103
+ }
87
104
  /**
88
105
  * Translates relation includes into a Prisma `include` object.
89
106
  *
@@ -105,10 +122,13 @@ function buildInclude(includes, options, parent, depth, maxDepth, path) {
105
122
  if (depth > maxDepth) {
106
123
  throw new RangeError(`Relation include depth exceeds the maximum of ${maxDepth}.`);
107
124
  }
108
- const result = {};
125
+ // A null-prototype accumulator: relation names such as `toString` or
126
+ // `__proto__` must behave as ordinary keys. It is spread into a plain
127
+ // object before it is returned.
128
+ const result = Object.create(null);
109
129
  for (const include of includes) {
110
- validateInclude(include);
111
- if (include.relation in result) {
130
+ validateIncludeLevel(include);
131
+ if (Object.hasOwn(result, include.relation)) {
112
132
  throw new TypeError(`Relation "${include.relation}" is included more than once.`);
113
133
  }
114
134
  let definition;
@@ -123,11 +143,11 @@ function buildInclude(includes, options, parent, depth, maxDepth, path) {
123
143
  }
124
144
  const entry = {};
125
145
  if (include.select && include.select.length > 0) {
126
- const select = {};
146
+ const select = Object.create(null);
127
147
  for (const field of include.select) {
128
148
  select[field] = true;
129
149
  }
130
- entry["select"] = select;
150
+ entry["select"] = { ...select };
131
151
  }
132
152
  if (include.include && include.include.length > 0) {
133
153
  const nested = buildInclude(include.include, options, definition ? definition.child : undefined, depth + 1, maxDepth, definition ? [...path, definition] : path);
@@ -147,7 +167,7 @@ function buildInclude(includes, options, parent, depth, maxDepth, path) {
147
167
  }
148
168
  result[include.relation] = Object.keys(entry).length === 0 ? true : entry;
149
169
  }
150
- return result;
170
+ return { ...result };
151
171
  }
152
172
  /**
153
173
  * Creates a nested relation include.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/database",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Database abstraction layer with clients, repositories, transactions, and query building for Zudojs applications.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -41,9 +41,9 @@
41
41
  "!dist/.tsbuildinfo"
42
42
  ],
43
43
  "dependencies": {
44
- "@zudojs/errors": "1.1.0",
45
- "@zudojs/logger": "1.2.0",
46
- "@zudojs/types": "1.1.0"
44
+ "@zudojs/errors": "1.2.0",
45
+ "@zudojs/logger": "1.3.0",
46
+ "@zudojs/types": "1.1.1"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@prisma/client": ">=7.0.0 <8"