@cerbos/orm-prisma 3.3.0 → 4.1.0

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 (74) hide show
  1. package/README.md +243 -10
  2. package/lib/index.d.ts +102 -2
  3. package/lib/index.d.ts.map +1 -1
  4. package/lib/index.js +1754 -155
  5. package/lib/index.js.map +1 -1
  6. package/package.json +24 -15
  7. package/src/adversarial.test.ts +1281 -0
  8. package/src/corpus.ts +414 -0
  9. package/src/generated/prisma-adversarial/browser.ts +54 -0
  10. package/src/generated/prisma-adversarial/client.ts +76 -0
  11. package/src/generated/{prisma → prisma-adversarial}/commonInputTypes.ts +131 -27
  12. package/src/generated/prisma-adversarial/enums.ts +15 -0
  13. package/src/generated/prisma-adversarial/internal/class.ts +264 -0
  14. package/src/generated/prisma-adversarial/internal/prismaNamespace.ts +1332 -0
  15. package/src/generated/{prisma → prisma-adversarial}/internal/prismaNamespaceBrowser.ts +45 -47
  16. package/src/generated/prisma-adversarial/models/AdversarialCategory.ts +1401 -0
  17. package/src/generated/prisma-adversarial/models/AdversarialInner.ts +1369 -0
  18. package/src/generated/prisma-adversarial/models/AdversarialLabel.ts +1272 -0
  19. package/src/generated/prisma-adversarial/models/AdversarialParent.ts +1474 -0
  20. package/src/generated/prisma-adversarial/models/AdversarialResource.ts +1789 -0
  21. package/src/generated/prisma-adversarial/models/AdversarialSubCategory.ts +1401 -0
  22. package/src/generated/prisma-adversarial/models/AdversarialTag.ts +1307 -0
  23. package/src/generated/prisma-adversarial/models.ts +18 -0
  24. package/src/generated/{prisma → prisma-adversarial-pg}/browser.ts +14 -19
  25. package/src/generated/{prisma → prisma-adversarial-pg}/client.ts +16 -21
  26. package/src/generated/prisma-adversarial-pg/commonInputTypes.ts +356 -0
  27. package/src/generated/prisma-adversarial-pg/internal/class.ts +264 -0
  28. package/src/generated/prisma-adversarial-pg/internal/prismaNamespace.ts +1371 -0
  29. package/src/generated/prisma-adversarial-pg/internal/prismaNamespaceBrowser.ts +177 -0
  30. package/src/generated/prisma-adversarial-pg/models/AdversarialCategory.ts +1404 -0
  31. package/src/generated/prisma-adversarial-pg/models/AdversarialInner.ts +1371 -0
  32. package/src/generated/prisma-adversarial-pg/models/AdversarialLabel.ts +1275 -0
  33. package/src/generated/prisma-adversarial-pg/models/AdversarialParent.ts +1476 -0
  34. package/src/generated/prisma-adversarial-pg/models/AdversarialResource.ts +1791 -0
  35. package/src/generated/prisma-adversarial-pg/models/AdversarialSubCategory.ts +1404 -0
  36. package/src/generated/prisma-adversarial-pg/models/AdversarialTag.ts +1310 -0
  37. package/src/generated/prisma-adversarial-pg/models.ts +18 -0
  38. package/src/generated/prisma-adversarial-pg-v6/index.d.ts +11830 -0
  39. package/src/generated/prisma-adversarial-v6/client.d.ts +1 -0
  40. package/src/generated/prisma-adversarial-v6/default.d.ts +1 -0
  41. package/src/generated/prisma-adversarial-v6/edge.d.ts +1 -0
  42. package/src/generated/prisma-adversarial-v6/index.d.ts +11769 -0
  43. package/src/generated/prisma-adversarial-v6/runtime/index-browser.d.ts +370 -0
  44. package/src/generated/prisma-adversarial-v6/runtime/library.d.ts +3982 -0
  45. package/src/generated/prisma-adversarial-v6/wasm.d.ts +1 -0
  46. package/src/index.ts +2515 -219
  47. package/src/test-setup.adversarial-url.ts +18 -0
  48. package/src/test-setup.adversarial.pg.v6.ts +13 -0
  49. package/src/test-setup.adversarial.pg.v7.ts +9 -0
  50. package/src/test-setup.adversarial.v6.ts +5 -0
  51. package/src/test-setup.adversarial.v7.ts +12 -0
  52. package/src/translator.test.ts +1586 -0
  53. package/src/generated/prisma/internal/class.ts +0 -274
  54. package/src/generated/prisma/internal/prismaNamespace.ts +0 -1333
  55. package/src/generated/prisma/models/Category.ts +0 -1412
  56. package/src/generated/prisma/models/Label.ts +0 -1276
  57. package/src/generated/prisma/models/NestedResource.ts +0 -1562
  58. package/src/generated/prisma/models/NextLevelNestedResource.ts +0 -1337
  59. package/src/generated/prisma/models/Resource.ts +0 -2136
  60. package/src/generated/prisma/models/SubCategory.ts +0 -1412
  61. package/src/generated/prisma/models/Tag.ts +0 -1276
  62. package/src/generated/prisma/models/User.ts +0 -1503
  63. package/src/generated/prisma/models.ts +0 -19
  64. package/src/generated/prisma-v6/index.d.ts +0 -13639
  65. package/src/index.test.ts +0 -6322
  66. package/src/test-setup.v6.ts +0 -5
  67. package/src/test-setup.v7.ts +0 -7
  68. /package/src/generated/{prisma → prisma-adversarial-pg}/enums.ts +0 -0
  69. /package/src/generated/{prisma-v6 → prisma-adversarial-pg-v6}/client.d.ts +0 -0
  70. /package/src/generated/{prisma-v6 → prisma-adversarial-pg-v6}/default.d.ts +0 -0
  71. /package/src/generated/{prisma-v6 → prisma-adversarial-pg-v6}/edge.d.ts +0 -0
  72. /package/src/generated/{prisma-v6 → prisma-adversarial-pg-v6}/runtime/index-browser.d.ts +0 -0
  73. /package/src/generated/{prisma-v6 → prisma-adversarial-pg-v6}/runtime/library.d.ts +0 -0
  74. /package/src/generated/{prisma-v6 → prisma-adversarial-pg-v6}/wasm.d.ts +0 -0
package/src/corpus.ts ADDED
@@ -0,0 +1,414 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+
4
+ import {
5
+ PlanExpression,
6
+ PlanExpressionValue,
7
+ PlanExpressionVariable,
8
+ } from "@cerbos/core";
9
+ import type {
10
+ PlanExpressionOperand,
11
+ PlanResourcesResponse,
12
+ Value,
13
+ } from "@cerbos/core";
14
+
15
+ import { PlanKind, MapperConfig } from ".";
16
+
17
+ /**
18
+ * The parts of the shared `../conformance/` corpus that both of this adapter's suites read.
19
+ *
20
+ * `adversarial.test.ts` plans against a real PDP and executes the translated query;
21
+ * `translator.test.ts` reads the same actions off the golden wire fixtures and asserts nothing
22
+ * but the emitted filter. They must agree on two things or they prove less than they appear to:
23
+ *
24
+ * - **the mapper.** The unit test pins the filter this adapter emits for a mapping; the harness
25
+ * proves that same filter returns the rows the PDP allows. Two copies that drifted would leave
26
+ * the pinned filters describing a mapping no harness ever executes.
27
+ * - **the classification.** Which actions this adapter must refuse, and with which message, is a
28
+ * corpus decision (`actions.json`), not a per-suite one.
29
+ *
30
+ * Test-only: excluded from `tsc --build` by `tsconfig.json`, so nothing here reaches `lib/`.
31
+ */
32
+
33
+ export const CONFORMANCE_DIR = path.join(
34
+ __dirname,
35
+ "..",
36
+ "..",
37
+ "conformance"
38
+ );
39
+
40
+ const WIRE_FIXTURES_DIR = path.join(CONFORMANCE_DIR, "wire-fixtures");
41
+
42
+ /** The Prisma model the corpus's resource kind maps onto. */
43
+ export const MODEL = "AdversarialResource";
44
+
45
+ // -- actions.json --------------------------------------------------------------------------------
46
+
47
+ export interface UnsupportedShape {
48
+ action: string;
49
+ shape: string;
50
+ /** One entry per adapter that must reject the shape; the corpus asserts the key set. */
51
+ messages: Record<string, string>;
52
+ }
53
+
54
+ export interface AdapterUnsupportedEntry {
55
+ action: string;
56
+ reason: string;
57
+ /** Absent on `adapterSupportedExpected` / `nullRepresentationOmitted`, required on a throw. */
58
+ message?: string;
59
+ }
60
+
61
+ /**
62
+ * A `nullRepresentationOmitted` entry. Every adapter must reject these — the two NULL conventions
63
+ * are indistinguishable on the wire — so `messages` names the whole roster with no promotions to
64
+ * subtract.
65
+ */
66
+ export interface NullRepresentationOmittedEntry {
67
+ action: string;
68
+ reason: string;
69
+ messages: Record<string, string>;
70
+ }
71
+
72
+ export interface KnownDivergence {
73
+ action: string;
74
+ adapters: string[];
75
+ }
76
+
77
+ export interface ActionsFile {
78
+ conformance: string[];
79
+ adapterUnsupported?: Record<string, AdapterUnsupportedEntry[]>;
80
+ adapterSupportedExpected?: Record<string, AdapterUnsupportedEntry[]>;
81
+ expectedUnsupported: UnsupportedShape[];
82
+ nullRepresentationOmitted: NullRepresentationOmittedEntry[];
83
+ knownDivergences?: KnownDivergence[];
84
+ }
85
+
86
+ /**
87
+ * A shape this adapter must refuse, with the substring its error has to contain.
88
+ *
89
+ * The message is what turns "it threw" into "it threw for the declared reason": without it a
90
+ * mapper typo or an unrelated validation satisfies the assertion just as well as the limitation
91
+ * the corpus documents (cerbos/query-plan-adapters#326).
92
+ */
93
+ export type ThrowingAction = readonly [
94
+ action: string,
95
+ reason: string,
96
+ message: string,
97
+ ];
98
+
99
+ export interface ActionClassification {
100
+ oracleActions: string[];
101
+ throwingActions: ThrowingAction[];
102
+ supportedExpected: Set<string>;
103
+ }
104
+
105
+ /** The pinned message, or a failure — a throwing action without one asserts nothing. */
106
+ export function requireMessage(
107
+ label: string,
108
+ message: string | undefined
109
+ ): string {
110
+ if (message === undefined || message === "") {
111
+ throw new Error(
112
+ `actions.json pins no throw message for ${label}: the throw suite would accept a failure for any reason`
113
+ );
114
+ }
115
+ return message;
116
+ }
117
+
118
+ export function classifyActionsForAdapter(
119
+ manifest: ActionsFile,
120
+ adapter: string
121
+ ): ActionClassification {
122
+ const unsupported = manifest.adapterUnsupported?.[adapter] ?? [];
123
+ const unsupportedActions = new Set(unsupported.map((entry) => entry.action));
124
+ const supportedExpected = new Set(
125
+ (manifest.adapterSupportedExpected?.[adapter] ?? []).map(
126
+ (entry) => entry.action
127
+ )
128
+ );
129
+ const oracleActions = [
130
+ ...manifest.conformance.filter(
131
+ (action) => !unsupportedActions.has(action)
132
+ ),
133
+ ...supportedExpected,
134
+ ];
135
+ const throwingActions: ThrowingAction[] = [
136
+ ...unsupported.map(
137
+ (entry): ThrowingAction => [
138
+ entry.action,
139
+ entry.reason,
140
+ requireMessage(`adapterUnsupported.${adapter}.${entry.action}`, entry.message),
141
+ ]
142
+ ),
143
+ ...manifest.expectedUnsupported
144
+ .filter((entry) => !supportedExpected.has(entry.action))
145
+ .map((entry): ThrowingAction => [
146
+ entry.action,
147
+ entry.shape,
148
+ requireMessage(
149
+ `expectedUnsupported.${entry.action}.messages.${adapter}`,
150
+ entry.messages?.[adapter]
151
+ ),
152
+ ]),
153
+ ];
154
+
155
+ return {
156
+ oracleActions: [...new Set(oracleActions)].sort(),
157
+ throwingActions: throwingActions.sort(([left], [right]) =>
158
+ left.localeCompare(right)
159
+ ),
160
+ supportedExpected,
161
+ };
162
+ }
163
+
164
+ // -- the golden wire fixtures --------------------------------------------------------------------
165
+
166
+ /**
167
+ * The instant `regenerate-wire-fixtures.sh` substitutes for the one operand it cannot pin.
168
+ *
169
+ * `ts-window` and `ts-vf` compare against `now() - duration("24h")`, which the planner folds to a
170
+ * literal timestamp: a different value on every capture, so the script rewrites it to
171
+ * `__NOW_MINUS_24H__` to keep the drift check deterministic. Reading the fixture back therefore
172
+ * means choosing a value, and the choice is load-bearing rather than arbitrary — Cerbos emits the
173
+ * PDP's clock at nanosecond precision, which is exactly why both actions are `adapterUnsupported`
174
+ * for this adapter (`Timestamp value exceeds millisecond precision`). A tidy millisecond instant
175
+ * here would translate cleanly and quietly contradict `actions.json`, so the fraction carries the
176
+ * nine digits a real plan carries. `translator.test.ts` pins both sides of that boundary, which is
177
+ * what the `plannedAt` override on `planFromWireFixture` is for.
178
+ */
179
+ export const PLANNED_AT = "2026-08-11T09:13:39.123456789Z";
180
+
181
+ interface WireOperand {
182
+ expression?: { operator: string; operands: WireOperand[] };
183
+ variable?: string;
184
+ value?: unknown;
185
+ }
186
+
187
+ interface WireFixture {
188
+ action: string;
189
+ resourceKind: string;
190
+ filter: { kind: string; condition?: WireOperand };
191
+ }
192
+
193
+ function operandFromWire(
194
+ node: WireOperand,
195
+ plannedAt: string
196
+ ): PlanExpressionOperand {
197
+ if (node.expression) {
198
+ return new PlanExpression(
199
+ node.expression.operator,
200
+ node.expression.operands.map((child) => operandFromWire(child, plannedAt))
201
+ );
202
+ }
203
+ if (node.variable !== undefined) {
204
+ return new PlanExpressionVariable(node.variable);
205
+ }
206
+ if (!("value" in node)) {
207
+ throw new Error(
208
+ `Wire fixture operand is neither an expression, a variable nor a value: ${JSON.stringify(node)}`
209
+ );
210
+ }
211
+ // The one cast in this file. A fixture is JSON the PDP produced, so its leaves are already
212
+ // exactly the JSON shapes `Value` admits — but `JSON.parse` cannot say so, and re-validating a
213
+ // file the corpus workflow regenerates and diffs would assert nothing new.
214
+ return new PlanExpressionValue(
215
+ (node.value === "__NOW_MINUS_24H__" ? plannedAt : node.value) as Value
216
+ );
217
+ }
218
+
219
+ /** Every action the corpus has a golden wire fixture for, sorted. */
220
+ export function wireFixtureActions(): string[] {
221
+ return fs
222
+ .readdirSync(WIRE_FIXTURES_DIR)
223
+ .filter((name) => name.endsWith(".json"))
224
+ .map((name) => name.slice(0, -".json".length))
225
+ .sort();
226
+ }
227
+
228
+ /**
229
+ * The plan the pinned PDP produced for `action`, decoded into the shape the SDK hands callers.
230
+ *
231
+ * The fixture is the PDP's HTTP response, so the decoding here is the one `@cerbos/http` performs
232
+ * — `{expression|variable|value}` nodes into `PlanExpression` / `PlanExpressionVariable` /
233
+ * `PlanExpressionValue`. It is deliberately not a hand-built plan: a plan somebody typed is a
234
+ * belief about what the planner emits, and this repository keeps fixtures precisely because that
235
+ * belief has been wrong before. See docs/adr/0006.
236
+ */
237
+ export function planFromWireFixture(
238
+ action: string,
239
+ plannedAt: string = PLANNED_AT
240
+ ): PlanResourcesResponse {
241
+ const fixture: WireFixture = JSON.parse(
242
+ fs.readFileSync(path.join(WIRE_FIXTURES_DIR, `${action}.json`), "utf8")
243
+ );
244
+ const base = {
245
+ cerbosCallId: "",
246
+ requestId: "",
247
+ validationErrors: [],
248
+ metadata: undefined,
249
+ };
250
+ switch (fixture.filter.kind) {
251
+ case PlanKind.CONDITIONAL:
252
+ if (!fixture.filter.condition) {
253
+ throw new Error(`Wire fixture ${action} is conditional with no condition`);
254
+ }
255
+ return {
256
+ ...base,
257
+ kind: PlanKind.CONDITIONAL,
258
+ condition: operandFromWire(fixture.filter.condition, plannedAt),
259
+ };
260
+ case PlanKind.ALWAYS_ALLOWED:
261
+ case PlanKind.ALWAYS_DENIED:
262
+ return { ...base, kind: fixture.filter.kind };
263
+ default:
264
+ throw new Error(
265
+ `Wire fixture ${action} has an unrecognised filter kind ${fixture.filter.kind}`
266
+ );
267
+ }
268
+ }
269
+
270
+ // -- the mapper ----------------------------------------------------------------------------------
271
+
272
+ export const MAPPER: Record<string, MapperConfig> = {
273
+ // The primary key, reached as `request.resource.id` rather than through `attr` (the `id-*`
274
+ // actions). It is a mapping like any other here, which is the point: an adapter that resolves
275
+ // references by stripping a `request.resource.attr.` prefix never sees this name.
276
+ "request.resource.id": { field: "id" },
277
+ "request.resource.attr.aBool": { field: "aBool" },
278
+ "request.resource.attr.aString": { field: "aString" },
279
+ "request.resource.attr.aNumber": { field: "aNumber" },
280
+ "request.resource.attr.aDouble": { field: "aDouble" },
281
+ "request.resource.attr.aOptionalString": { field: "aOptionalString" },
282
+ "request.resource.attr.createdBy": { field: "createdBy" },
283
+ "request.resource.attr.scope": { field: "scope" },
284
+ "request.resource.attr.createdAt": {
285
+ field: "createdAt",
286
+ valueType: "dateTime",
287
+ },
288
+ // `owner` and `coOwner` alias columns that `aOptionalString` and `scope` also map, under the
289
+ // OTHER null convention: the oracle sends a real null attribute for them rather than omitting
290
+ // it. Declaring that here is what makes the equality family definite for these two attributes
291
+ // and leaves it untouched for every other mapping (cerbos/query-plan-adapters#308).
292
+ "request.resource.attr.owner": {
293
+ field: "aOptionalString",
294
+ nullable: true,
295
+ nullAttributeRepresentation: "explicit",
296
+ },
297
+ "request.resource.attr.coOwner": {
298
+ field: "scope",
299
+ nullable: true,
300
+ nullAttributeRepresentation: "explicit",
301
+ },
302
+ // obj.inner is not a real nested column — mirrors aString, same trick the spring-data
303
+ // reference harness uses for the p-struct probe. `parent.inner` below is the opposite: a real
304
+ // two-level join. The two are kept side by side on purpose.
305
+ "request.resource.attr.obj.inner": { field: "aString" },
306
+ // The corpus's one REAL to-one chain (the `rel-*` actions). `type: "one"` is what makes the
307
+ // adapter emit `is:` rather than `some:`, and `is:` on an optional relation is what requires
308
+ // the hop to exist — the absent-parent guard the negated shapes discriminate. `inner` nests
309
+ // the same declaration one level further out; two levels is where alias scoping breaks.
310
+ "request.resource.attr.parent": {
311
+ relation: {
312
+ name: "parent",
313
+ type: "one",
314
+ model: "AdversarialParent",
315
+ fields: {
316
+ aBool: { field: "aBool" },
317
+ aString: { field: "aString" },
318
+ aNumber: { field: "aNumber" },
319
+ aOptionalString: { field: "aOptionalString", nullable: true },
320
+ inner: {
321
+ relation: {
322
+ name: "inner",
323
+ type: "one",
324
+ model: "AdversarialInner",
325
+ fields: {
326
+ aBool: { field: "aBool" },
327
+ aString: { field: "aString" },
328
+ aNumber: { field: "aNumber" },
329
+ aOptionalString: { field: "aOptionalString", nullable: true },
330
+ },
331
+ },
332
+ },
333
+ },
334
+ },
335
+ },
336
+ "request.resource.attr.tags": {
337
+ relation: {
338
+ name: "tags",
339
+ type: "many",
340
+ // Model name enables field-to-field comparisons between tag columns; the nullable
341
+ // flag on `name` enables the adapter's three-valued-logic guards for collection
342
+ // macros over elements whose name column is NULL (a missing attribute — a CEL
343
+ // error, hence deny — on the check side).
344
+ model: "AdversarialTag",
345
+ fields: {
346
+ id: { field: "tagId" },
347
+ name: { field: "name", nullable: true },
348
+ },
349
+ },
350
+ },
351
+ "request.resource.attr.tagNames": {
352
+ relation: {
353
+ name: "tags",
354
+ type: "many",
355
+ field: "name",
356
+ fields: { name: { field: "name", nullable: true } },
357
+ },
358
+ },
359
+ "request.resource.attr.categories": {
360
+ relation: {
361
+ name: "categories",
362
+ type: "many",
363
+ fields: {
364
+ name: { field: "name" },
365
+ subCategories: {
366
+ relation: {
367
+ name: "subCategories",
368
+ type: "many",
369
+ fields: {
370
+ name: { field: "name" },
371
+ labels: {
372
+ relation: {
373
+ name: "labels",
374
+ type: "many",
375
+ fields: {
376
+ name: { field: "name", nullable: true },
377
+ },
378
+ },
379
+ },
380
+ },
381
+ },
382
+ },
383
+ },
384
+ },
385
+ },
386
+ // Multi-hop chain probe (W1): mainCategory mirrors the SAME categories/subCategories relation
387
+ // as a single-object dotted chain on the check side (every seed holds at most one category),
388
+ // pinning that the adapter joins through every intermediate hop, never off the root.
389
+ "request.resource.attr.mainCategory": {
390
+ relation: {
391
+ name: "categories",
392
+ type: "many",
393
+ fields: {
394
+ name: { field: "name" },
395
+ subCategories: {
396
+ relation: {
397
+ name: "subCategories",
398
+ type: "many",
399
+ fields: { name: { field: "name" } },
400
+ },
401
+ },
402
+ // subNames: the same 2-hop chain but with a bare `field`, so plain `in` membership
403
+ // compares the flattened tail's name column directly.
404
+ subNames: {
405
+ relation: {
406
+ name: "subCategories",
407
+ type: "many",
408
+ field: "name",
409
+ },
410
+ },
411
+ },
412
+ },
413
+ },
414
+ };
@@ -0,0 +1,54 @@
1
+
2
+ /* !!! This is code generated by Prisma. Do not edit directly. !!! */
3
+ /* eslint-disable */
4
+ // biome-ignore-all lint: generated file
5
+ // @ts-nocheck
6
+ /*
7
+ * This file should be your main import to use Prisma-related types and utilities in a browser.
8
+ * Use it to get access to models, enums, and input types.
9
+ *
10
+ * This file does not contain a `PrismaClient` class, nor several other helpers that are intended as server-side only.
11
+ * See `client.ts` for the standard, server-side entry point.
12
+ *
13
+ * 🟢 You can import this file directly.
14
+ */
15
+
16
+ import * as Prisma from './internal/prismaNamespaceBrowser.js'
17
+ export { Prisma }
18
+ export * as $Enums from './enums.js'
19
+ export * from './enums.js';
20
+ /**
21
+ * Model AdversarialResource
22
+ *
23
+ */
24
+ export type AdversarialResource = Prisma.AdversarialResourceModel
25
+ /**
26
+ * Model AdversarialTag
27
+ *
28
+ */
29
+ export type AdversarialTag = Prisma.AdversarialTagModel
30
+ /**
31
+ * Model AdversarialCategory
32
+ *
33
+ */
34
+ export type AdversarialCategory = Prisma.AdversarialCategoryModel
35
+ /**
36
+ * Model AdversarialSubCategory
37
+ *
38
+ */
39
+ export type AdversarialSubCategory = Prisma.AdversarialSubCategoryModel
40
+ /**
41
+ * Model AdversarialLabel
42
+ *
43
+ */
44
+ export type AdversarialLabel = Prisma.AdversarialLabelModel
45
+ /**
46
+ * Model AdversarialParent
47
+ *
48
+ */
49
+ export type AdversarialParent = Prisma.AdversarialParentModel
50
+ /**
51
+ * Model AdversarialInner
52
+ *
53
+ */
54
+ export type AdversarialInner = Prisma.AdversarialInnerModel
@@ -0,0 +1,76 @@
1
+
2
+ /* !!! This is code generated by Prisma. Do not edit directly. !!! */
3
+ /* eslint-disable */
4
+ // biome-ignore-all lint: generated file
5
+ // @ts-nocheck
6
+ /*
7
+ * This file should be your main import to use Prisma. Through it you get access to all the models, enums, and input types.
8
+ * If you're looking for something you can import in the client-side of your application, please refer to the `browser.ts` file instead.
9
+ *
10
+ * 🟢 You can import this file directly.
11
+ */
12
+
13
+ import * as process from 'node:process'
14
+ import * as path from 'node:path'
15
+
16
+ import * as runtime from "@prisma/client/runtime/client"
17
+ import * as $Enums from "./enums.js"
18
+ import * as $Class from "./internal/class.js"
19
+ import * as Prisma from "./internal/prismaNamespace.js"
20
+
21
+ export * as $Enums from './enums.js'
22
+ export * from "./enums.js"
23
+ /**
24
+ * ## Prisma Client
25
+ *
26
+ * Type-safe database client for TypeScript
27
+ * @example
28
+ * ```
29
+ * const prisma = new PrismaClient({
30
+ * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL })
31
+ * })
32
+ * // Fetch zero or more AdversarialResources
33
+ * const adversarialResources = await prisma.adversarialResource.findMany()
34
+ * ```
35
+ *
36
+ * Read more in our [docs](https://pris.ly/d/client).
37
+ */
38
+ export const PrismaClient = $Class.getPrismaClientClass()
39
+ export type PrismaClient<LogOpts extends Prisma.LogLevel = never, OmitOpts extends Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>
40
+ export { Prisma }
41
+
42
+ /**
43
+ * Model AdversarialResource
44
+ *
45
+ */
46
+ export type AdversarialResource = Prisma.AdversarialResourceModel
47
+ /**
48
+ * Model AdversarialTag
49
+ *
50
+ */
51
+ export type AdversarialTag = Prisma.AdversarialTagModel
52
+ /**
53
+ * Model AdversarialCategory
54
+ *
55
+ */
56
+ export type AdversarialCategory = Prisma.AdversarialCategoryModel
57
+ /**
58
+ * Model AdversarialSubCategory
59
+ *
60
+ */
61
+ export type AdversarialSubCategory = Prisma.AdversarialSubCategoryModel
62
+ /**
63
+ * Model AdversarialLabel
64
+ *
65
+ */
66
+ export type AdversarialLabel = Prisma.AdversarialLabelModel
67
+ /**
68
+ * Model AdversarialParent
69
+ *
70
+ */
71
+ export type AdversarialParent = Prisma.AdversarialParentModel
72
+ /**
73
+ * Model AdversarialInner
74
+ *
75
+ */
76
+ export type AdversarialInner = Prisma.AdversarialInnerModel