@appxdigital/appx-core 0.1.121-beta.8 → 0.1.121
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/CHANGELOG.md +50 -4
- package/PRERELEASES.md +129 -0
- package/dist/common/config/permissionsConfigTypes.d.ts +19 -3
- package/dist/common/config/permissionsConfigTypes.d.ts.map +1 -1
- package/dist/config/generate-dtos.js +101 -15
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/modules/auth/auth.module.d.ts +16 -0
- package/dist/modules/auth/auth.module.d.ts.map +1 -1
- package/dist/modules/auth/auth.module.js +45 -16
- package/dist/modules/core/core.controller.d.ts.map +1 -1
- package/dist/modules/core/core.controller.js +3 -23
- package/dist/prisma/permissions-validator.d.ts +51 -0
- package/dist/prisma/permissions-validator.d.ts.map +1 -0
- package/dist/prisma/permissions-validator.js +142 -0
- package/dist/prisma/prisma.service.d.ts +61 -3
- package/dist/prisma/prisma.service.d.ts.map +1 -1
- package/dist/prisma/prisma.service.js +245 -33
- package/docs/README.md +22 -0
- package/docs/authentication.md +220 -0
- package/docs/data-access.md +108 -0
- package/docs/dtos.md +158 -0
- package/docs/graphql.md +72 -0
- package/docs/limitations.md +61 -0
- package/docs/permissions.md +192 -0
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.controller.d.ts","sourceRoot":"","sources":["../../../src/modules/core/core.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAI3C,OAAO,EAAC,kBAAkB,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"core.controller.d.ts","sourceRoot":"","sources":["../../../src/modules/core/core.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAI3C,OAAO,EAAC,kBAAkB,EAAC,MAAM,yCAAyC,CAAC;AAQ3E,8BACsB,cAAc,CAAC,CAAC;IAM9B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;IAL9C,MAAM,KAAK,UAAU,IAAI,MAAM,CAE9B;IAED,SAAS,aACc,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;IAK9C,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAG,kBAAkB,CAAC;IAIrD,OAAO;IAMP,OAAO,CAAc,EAAE,EAAE,MAAM;IAM/B,MAAM,CAAS,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAC;IAiBtD,MAAM,CAAc,EAAE,EAAE,MAAM,EAAU,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAMxD,MAAM,CAAc,EAAE,EAAE,MAAM;CAGvC"}
|
|
@@ -39,33 +39,13 @@ let CoreController = exports.CoreController = CoreController_1 = class CoreContr
|
|
|
39
39
|
const model = this.constructor.entityName;
|
|
40
40
|
const rolePermissions = this.permissionsService.getPermissionsConfig()[model]?.[role];
|
|
41
41
|
const actionPermission = rolePermissions?.['create'];
|
|
42
|
-
if (typeof actionPermission !== 'string' && actionPermission) {
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
for (const field of (actionPermission.restrictedFields ?? [])) {
|
|
46
|
-
delete data[field];
|
|
47
|
-
}
|
|
48
|
-
if (actionPermission.setUserIdField) {
|
|
49
|
-
data[actionPermission.setUserIdField] = user.id;
|
|
50
|
-
}
|
|
42
|
+
if (typeof actionPermission !== 'string' && actionPermission?.setUserIdField) {
|
|
43
|
+
// Force the server-owned user id (so a client can't forge ownership).
|
|
44
|
+
data[actionPermission.setUserIdField] = user.id;
|
|
51
45
|
}
|
|
52
46
|
return this.service.create(data);
|
|
53
47
|
}
|
|
54
48
|
async update(id, data) {
|
|
55
|
-
const user = nestjs_request_context_1.RequestContext.currentContext.req.user;
|
|
56
|
-
const role = user?.role || 'GUEST';
|
|
57
|
-
const model = this.constructor.entityName;
|
|
58
|
-
const rolePermissions = this.permissionsService.getPermissionsConfig()[model]?.[role];
|
|
59
|
-
// The action key is 'updateMany' (matches @Permission('updateMany') and
|
|
60
|
-
// the proxy) — reading 'update' here meant restrictedFields never applied.
|
|
61
|
-
const actionPermission = rolePermissions?.['updateMany'];
|
|
62
|
-
let restrictedFields = [];
|
|
63
|
-
if (typeof actionPermission !== 'string' && actionPermission?.restrictedFields) {
|
|
64
|
-
restrictedFields = actionPermission.restrictedFields;
|
|
65
|
-
}
|
|
66
|
-
for (const field of restrictedFields) {
|
|
67
|
-
delete data[field];
|
|
68
|
-
}
|
|
69
49
|
return this.service.updateById(id, data);
|
|
70
50
|
}
|
|
71
51
|
async delete(id) {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static validation of a `PermissionsConfig` against the Prisma schema.
|
|
3
|
+
*
|
|
4
|
+
* Runs at boot (in the PrismaService constructor). It encodes the Option A
|
|
5
|
+
* authorization model: a create condition judges a model's own scalar fields
|
|
6
|
+
* only, and every foreign-key reference a create establishes is authorized by
|
|
7
|
+
* the target model's `connect` rule. Misconfigurations that would break at
|
|
8
|
+
* runtime are surfaced here — errors reject boot, warnings are advisory.
|
|
9
|
+
*
|
|
10
|
+
* Pure and schema-only (no database), so it is independently unit-testable.
|
|
11
|
+
*/
|
|
12
|
+
import type { PermissionsConfigType } from '../common/config/permissionsConfigTypes';
|
|
13
|
+
export type RelationKind = 'belongsTo' | 'hasMany';
|
|
14
|
+
export interface RelationMeta {
|
|
15
|
+
/** The relation navigation field name on the owning model. */
|
|
16
|
+
field: string;
|
|
17
|
+
/** The target model name (original casing, as in the schema). */
|
|
18
|
+
model: string;
|
|
19
|
+
/** The owning model's scalar FK column (belongsTo only). */
|
|
20
|
+
referencingColumn?: string;
|
|
21
|
+
isRequired: boolean;
|
|
22
|
+
kind: RelationKind;
|
|
23
|
+
/** False when the scalar FK is @NoWrite / @Role(none) (never client-writable). Defaults to writable. */
|
|
24
|
+
fkWritable?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Relations per model, keyed by the lower-cased model name. */
|
|
27
|
+
export type SchemaRelations = Record<string, RelationMeta[]>;
|
|
28
|
+
export type IssueLevel = 'error' | 'warning';
|
|
29
|
+
export type IssueCode = 'relation-in-create-condition' | 'missing-connect-required' | 'missing-connect' | 'connect-on-unwritable' | 'unknown-relation';
|
|
30
|
+
export interface ValidationIssue {
|
|
31
|
+
level: IssueLevel;
|
|
32
|
+
code: IssueCode;
|
|
33
|
+
model: string;
|
|
34
|
+
role: string;
|
|
35
|
+
message: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validates the permissions config against the schema relations.
|
|
39
|
+
*
|
|
40
|
+
* Checks, per model + role that can create the model:
|
|
41
|
+
* - **error** `relation-in-create-condition` — a create condition references a
|
|
42
|
+
* relation. Create conditions are own-scalar-only; relationship checks belong
|
|
43
|
+
* on the target's `connect` rule.
|
|
44
|
+
* - **error** `missing-connect-required` — a *required* belongsTo FK's target
|
|
45
|
+
* has no `connect` rule for the role. Every create sets it, so it will always
|
|
46
|
+
* be denied at runtime.
|
|
47
|
+
* - **warning** `missing-connect-optional` — an *optional* belongsTo FK's target
|
|
48
|
+
* has no `connect` rule for the role. Only denied when the payload sets it.
|
|
49
|
+
*/
|
|
50
|
+
export declare function validatePermissionsConfig(config: PermissionsConfigType, relations: SchemaRelations): ValidationIssue[];
|
|
51
|
+
//# sourceMappingURL=permissions-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions-validator.d.ts","sourceRoot":"","sources":["../../src/prisma/permissions-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAErF,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;AAEnD,MAAM,WAAW,YAAY;IACzB,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,wGAAwG;IACxG,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;AAE7D,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAE7C,MAAM,MAAM,SAAS,GACf,8BAA8B,GAC9B,0BAA0B,GAC1B,iBAAiB,GACjB,uBAAuB,GACvB,kBAAkB,CAAC;AAEzB,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAmBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACrC,MAAM,EAAE,qBAAqB,EAC7B,SAAS,EAAE,eAAe,GAC3B,eAAe,EAAE,CAmHnB"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validatePermissionsConfig = void 0;
|
|
4
|
+
/** Collects condition keys that name a relation (skips AND/OR/NOT, which recurse). */
|
|
5
|
+
function findRelationKeys(cond, relationFields, found = new Set()) {
|
|
6
|
+
if (!cond || typeof cond !== 'object')
|
|
7
|
+
return found;
|
|
8
|
+
const objs = Array.isArray(cond) ? cond : [cond];
|
|
9
|
+
for (const obj of objs) {
|
|
10
|
+
if (!obj || typeof obj !== 'object')
|
|
11
|
+
continue;
|
|
12
|
+
for (const key of Object.keys(obj)) {
|
|
13
|
+
if (key === 'AND' || key === 'OR' || key === 'NOT') {
|
|
14
|
+
findRelationKeys(obj[key], relationFields, found);
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (relationFields.has(key))
|
|
18
|
+
found.add(key);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return found;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Validates the permissions config against the schema relations.
|
|
25
|
+
*
|
|
26
|
+
* Checks, per model + role that can create the model:
|
|
27
|
+
* - **error** `relation-in-create-condition` — a create condition references a
|
|
28
|
+
* relation. Create conditions are own-scalar-only; relationship checks belong
|
|
29
|
+
* on the target's `connect` rule.
|
|
30
|
+
* - **error** `missing-connect-required` — a *required* belongsTo FK's target
|
|
31
|
+
* has no `connect` rule for the role. Every create sets it, so it will always
|
|
32
|
+
* be denied at runtime.
|
|
33
|
+
* - **warning** `missing-connect-optional` — an *optional* belongsTo FK's target
|
|
34
|
+
* has no `connect` rule for the role. Only denied when the payload sets it.
|
|
35
|
+
*/
|
|
36
|
+
function validatePermissionsConfig(config, relations) {
|
|
37
|
+
const issues = [];
|
|
38
|
+
// Iterate the typed config structurally — model/role keys are dynamic, and
|
|
39
|
+
// condition/rule shapes are inspected at runtime.
|
|
40
|
+
const cfg = (config || {});
|
|
41
|
+
const byModel = {};
|
|
42
|
+
for (const m of Object.keys(cfg))
|
|
43
|
+
byModel[m.toLowerCase()] = cfg[m];
|
|
44
|
+
const hasConnectRule = (targetModel, role) => {
|
|
45
|
+
const rules = byModel[targetModel.toLowerCase()]?.[role];
|
|
46
|
+
return !!rules && rules.connect !== undefined && rules.connect !== null;
|
|
47
|
+
};
|
|
48
|
+
// A relation-scoped connect on the source (creating) model authorizes that
|
|
49
|
+
// relation on its own — the target model then needs no connect rule.
|
|
50
|
+
const hasRelationConnect = (sourceRules, field) => !!sourceRules?.relations?.[field]?.connect;
|
|
51
|
+
const canCreate = (rules) => !!rules && (rules.create !== undefined || rules.createMany !== undefined);
|
|
52
|
+
const canUpdate = (rules) => !!rules && (rules.update !== undefined || rules.updateMany !== undefined);
|
|
53
|
+
for (const modelKey of Object.keys(cfg)) {
|
|
54
|
+
const roles = cfg[modelKey] || {};
|
|
55
|
+
const rels = relations[modelKey.toLowerCase()] || [];
|
|
56
|
+
const belongsTo = rels.filter((r) => r.kind === 'belongsTo' && r.referencingColumn);
|
|
57
|
+
const relationFieldNames = new Set(rels.map((r) => r.field));
|
|
58
|
+
for (const role of Object.keys(roles)) {
|
|
59
|
+
const rules = roles[role];
|
|
60
|
+
const creatable = canCreate(rules);
|
|
61
|
+
const updatable = canUpdate(rules);
|
|
62
|
+
if (!creatable && !updatable)
|
|
63
|
+
continue;
|
|
64
|
+
const createRule = rules.create ?? rules.createMany;
|
|
65
|
+
const conditions = createRule && typeof createRule === 'object' ? createRule.conditions : undefined;
|
|
66
|
+
if (conditions) {
|
|
67
|
+
for (const relField of findRelationKeys(conditions, relationFieldNames)) {
|
|
68
|
+
issues.push({
|
|
69
|
+
level: 'error',
|
|
70
|
+
code: 'relation-in-create-condition',
|
|
71
|
+
model: modelKey,
|
|
72
|
+
role,
|
|
73
|
+
message: `create condition on ${modelKey}.${role} references relation '${relField}'. Create conditions judge own scalar fields only — authorize relationships with the target model's 'connect' rule.`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Every foreign key a write can SET must have a connect rule (target
|
|
78
|
+
// or relation-scoped) — otherwise setting it is denied at runtime.
|
|
79
|
+
// A @NoWrite / @Role(none) column is never settable.
|
|
80
|
+
for (const r of belongsTo) {
|
|
81
|
+
const col = r.referencingColumn;
|
|
82
|
+
const writable = r.fkWritable !== false; // not @NoWrite / @Role(none)
|
|
83
|
+
const settableOnCreate = writable && creatable;
|
|
84
|
+
const settableOnUpdate = writable && updatable;
|
|
85
|
+
const relRule = hasRelationConnect(rules, r.field);
|
|
86
|
+
if (!settableOnCreate && !settableOnUpdate) {
|
|
87
|
+
// A relation-scoped connect rule for a field that can't be
|
|
88
|
+
// written is contradictory — flag it rather than silently ignore.
|
|
89
|
+
if (relRule) {
|
|
90
|
+
issues.push({
|
|
91
|
+
level: 'error',
|
|
92
|
+
code: 'connect-on-unwritable',
|
|
93
|
+
model: modelKey,
|
|
94
|
+
role,
|
|
95
|
+
message: `${modelKey}.${role}.relations.${r.field}.connect is set, but its foreign key '${col}' is not writable (@NoWrite / @Role(none)). Make the field writable or remove the relation rule.`,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (relRule || hasConnectRule(r.model, role))
|
|
101
|
+
continue;
|
|
102
|
+
const fix = `Declare '${r.model}.${role}.connect' (or 'ALL'), or scope it to this relation with '${modelKey}.${role}.relations.${r.field}.connect'.`;
|
|
103
|
+
if (settableOnCreate && r.isRequired) {
|
|
104
|
+
issues.push({
|
|
105
|
+
level: 'error',
|
|
106
|
+
code: 'missing-connect-required',
|
|
107
|
+
model: modelKey,
|
|
108
|
+
role,
|
|
109
|
+
message: `${modelKey}.${role} can create, but its required foreign key '${col}' → ${r.model} has no 'connect' rule for ${role}. Every create sets it, so the create is always denied. ${fix}`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
issues.push({
|
|
114
|
+
level: 'error',
|
|
115
|
+
code: 'missing-connect',
|
|
116
|
+
model: modelKey,
|
|
117
|
+
role,
|
|
118
|
+
message: `${modelKey}.${role} can set foreign key '${col}' → ${r.model} (on ${settableOnCreate ? 'create' : ''}${settableOnCreate && settableOnUpdate ? '/' : ''}${settableOnUpdate ? 'update' : ''}), but ${r.model} has no 'connect' rule for ${role}, so any write that sets it is denied. ${fix}`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// A `relations` key that doesn't name a real relation of this model is
|
|
123
|
+
// almost certainly a typo — it silently does nothing.
|
|
124
|
+
const relationsMap = rules.relations;
|
|
125
|
+
if (relationsMap && typeof relationsMap === 'object') {
|
|
126
|
+
for (const relField of Object.keys(relationsMap)) {
|
|
127
|
+
if (!relationFieldNames.has(relField)) {
|
|
128
|
+
issues.push({
|
|
129
|
+
level: 'warning',
|
|
130
|
+
code: 'unknown-relation',
|
|
131
|
+
model: modelKey,
|
|
132
|
+
role,
|
|
133
|
+
message: `${modelKey}.${role}.relations.${relField} does not name a relation of ${modelKey} — it has no effect. Check the field name.`,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return issues;
|
|
141
|
+
}
|
|
142
|
+
exports.validatePermissionsConfig = validatePermissionsConfig;
|
|
@@ -52,6 +52,13 @@ export declare class PrismaService {
|
|
|
52
52
|
*/
|
|
53
53
|
private rawClient;
|
|
54
54
|
constructor(prismaClient: PrismaClient, permissionsConfig: PermissionsConfigType);
|
|
55
|
+
/**
|
|
56
|
+
* Validates the permissions config against the schema at boot. Warnings are
|
|
57
|
+
* logged; errors (a create condition that crosses a relation, or a required
|
|
58
|
+
* FK whose target has no `connect` rule) reject boot — the misconfiguration
|
|
59
|
+
* would otherwise surface as a runtime 403.
|
|
60
|
+
*/
|
|
61
|
+
private validatePermissions;
|
|
55
62
|
debugQueries(enable: boolean): void;
|
|
56
63
|
withExposedModels(models: string[], callback: () => Promise<void>): Promise<void>;
|
|
57
64
|
private debug;
|
|
@@ -114,6 +121,43 @@ export declare class PrismaService {
|
|
|
114
121
|
* cannot evaluate, rather than silently allowing the insert.
|
|
115
122
|
*/
|
|
116
123
|
private enforceCreateConditions;
|
|
124
|
+
/**
|
|
125
|
+
* Authorizes every relation a write establishes. Relationship authorization
|
|
126
|
+
* lives entirely in the `connect` action — create conditions judge a model's
|
|
127
|
+
* own scalar fields only.
|
|
128
|
+
*
|
|
129
|
+
* Runs on create AND update: a `create` can nest relation writes or set raw
|
|
130
|
+
* FKs; an `updateMany` (scalar-only) can re-point a raw FK. Both go through
|
|
131
|
+
* the same `connect` authorization.
|
|
132
|
+
*
|
|
133
|
+
* - A raw scalar foreign key (`courseId: 7`) → the target's `connect` rule.
|
|
134
|
+
* - `relation: { connect }` → the target's `connect` rule. `connect` is a
|
|
135
|
+
* DEDICATED action: being allowed to READ a record does not authorize
|
|
136
|
+
* associating it.
|
|
137
|
+
* - `relation: { create }` → the target's `create` rule (recurses, so deeper
|
|
138
|
+
* nesting is authorized too). Every other nested operator is rejected.
|
|
139
|
+
*
|
|
140
|
+
* The one exception is `trustedFk`: the scalar FK that points back to the row
|
|
141
|
+
* we're nested under. Prisma fills it at write time and the parent already
|
|
142
|
+
* authorized itself, so it is not re-checked.
|
|
143
|
+
*/
|
|
144
|
+
private enforceNestedWrites;
|
|
145
|
+
/** Authorizes each operator inside one relation's nested-write object. */
|
|
146
|
+
private enforceNestedRelationOps;
|
|
147
|
+
/** If `column` is the scalar FK backing a belongsTo relation, returns that relation's field + target. */
|
|
148
|
+
private foreignKeyColumn;
|
|
149
|
+
/** The child's scalar FK column pointing back to the parent it's nested under (trusted). */
|
|
150
|
+
private backReferenceFk;
|
|
151
|
+
/**
|
|
152
|
+
* Authorizes attaching `relatedModel` (identified by `where`) through the
|
|
153
|
+
* `field` relation on `sourceModel`. Two rules can apply, evaluated against
|
|
154
|
+
* the candidate target row:
|
|
155
|
+
* - a relation-scoped rule on the source (`sourceModel[role].relations[field].connect`)
|
|
156
|
+
* - the target model's own rule (`relatedModel[role].connect`)
|
|
157
|
+
* When both exist they are ANDed (the relation rule can only strengthen).
|
|
158
|
+
* When only one exists it stands alone; when neither exists, default-deny.
|
|
159
|
+
*/
|
|
160
|
+
private assertConnectAllowed;
|
|
117
161
|
/**
|
|
118
162
|
* True only in an explicit local-development environment. Deliberately NOT
|
|
119
163
|
* `!== 'production'` — staging and other envs should behave like production
|
|
@@ -128,12 +172,25 @@ export declare class PrismaService {
|
|
|
128
172
|
* (gated by the caller).
|
|
129
173
|
*/
|
|
130
174
|
private warnIfCreatedRowNotFindable;
|
|
131
|
-
/**
|
|
175
|
+
/**
|
|
176
|
+
* A view of a create `row` where a belongsTo relation given via `connect`
|
|
177
|
+
* (`owner: { connect: { id } }`) is also surfaced as its scalar FK (`ownerId`),
|
|
178
|
+
* so scalar-FK create conditions match either payload form. Metadata-driven
|
|
179
|
+
* (`referencingColumn`/`foreignKey`); resolvable only when the connect targets
|
|
180
|
+
* the referenced column. Explicit scalar wins; row is not mutated.
|
|
181
|
+
*/
|
|
182
|
+
private resolveConnectForeignKeys;
|
|
183
|
+
/**
|
|
184
|
+
* Evaluates a (placeholder-resolved) create condition against a to-be-created
|
|
185
|
+
* row. Create conditions judge the model's OWN scalar fields only — a clause
|
|
186
|
+
* that reaches into a relation is not a create concern (relationships are
|
|
187
|
+
* authorized by the target's `connect` rule) and is skipped here; the config
|
|
188
|
+
* validator rejects such clauses at boot. `trustedFk` (the back-reference to a
|
|
189
|
+
* same-request nesting parent) is likewise skipped — its value doesn't exist yet.
|
|
190
|
+
*/
|
|
132
191
|
private matchesCreateConditions;
|
|
133
192
|
/** Evaluates a scalar-field condition (value or Prisma operator object) against the row's value. */
|
|
134
193
|
private matchesCreateScalar;
|
|
135
|
-
/** Verifies the parent referenced by a belongsTo condition exists and satisfies the nested condition. */
|
|
136
|
-
private matchesCreateRelation;
|
|
137
194
|
/**
|
|
138
195
|
* Builds dynamic conditions based on the type of clause (OR, AND, or field conditions).
|
|
139
196
|
* Each condition is processed, and placeholders (like `$USER_ID`) are replaced with actual values.
|
|
@@ -178,6 +235,7 @@ export declare class PrismaService {
|
|
|
178
235
|
relation: string;
|
|
179
236
|
foreignKey?: string;
|
|
180
237
|
referencingColumn?: string;
|
|
238
|
+
relationName?: string;
|
|
181
239
|
isRequired: boolean;
|
|
182
240
|
};
|
|
183
241
|
selectPermission(permissions: any, action: string, modelName: string, userRole: string): any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prisma.service.d.ts","sourceRoot":"","sources":["../../src/prisma/prisma.service.ts"],"names":[],"mappings":";AACA,OAAO,EAAC,MAAM,EAAE,YAAY,EAAC,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAC,qBAAqB,EAAkB,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"prisma.service.d.ts","sourceRoot":"","sources":["../../src/prisma/prisma.service.ts"],"names":[],"mappings":";AACA,OAAO,EAAC,MAAM,EAAE,YAAY,EAAC,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAC,qBAAqB,EAAkB,MAAM,yCAAyC,CAAC;AAG/F,OAAO,KAAK,EAAC,YAAY,IAAI,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAGlE,OAAO,EAAC,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAEnD,eAAO,MAAM,iBAAiB;mBACX,MAAM,EAAE;EACvB,CAAC;AAEL,KAAK,QAAQ,GAAG,MAAM,aAAa,CAAC;AAEpC,oDAAoD;AACpD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF,4EAA4E;AAC5E,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAEtE;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,YAAY,GAAG,mBAAmB,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAAG;IACjG,UAAU,EAAE,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACrC,iBAAiB,EAAE,QAAQ,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;IACnD,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;IAClC,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;CACrC,CAAC;AAGF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,IAAI,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpF;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;KAC7B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;KAAE,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACpG,CAAC;AAEF,qBACa,aAAa;IAaY,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAZpE,OAAO,CAAC,YAAY,CAA2B;IAC/C,YAAY,EAAE,YAAY,CAAC;IAC3B;;;;;OAKG;IACH,OAAO,CAAC,SAAS,CAAgB;gBAG7B,YAAY,EAAE,YAAY,EACqB,iBAAiB,EAAE,qBAAqB;IAQ3F;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IA6B3B,YAAY,CAAC,MAAM,EAAE,OAAO;IAO5B,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAWjE,OAAO,CAAC,KAAK;IAQb,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC;IAIpE,WAAW;IAkFX;;;;OAIG;IACH,gBAAgB,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;IAYlE,IAAI,KAAK,IAAI,gBAAgB,CAAC,aAAa,CAAC,CAU3C;IAED,IAAI,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAElC;IAED,IAAI,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAExC;IAED,IAAI,gBAAgB,QAEnB;IAED;;;OAGG;IACH,WAAW;IA+DX;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAkE1B,IAAI,2BAA2B,QAM9B;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,oBAAoB;IA8K5B;;;;;;;;;;;;;;;;OAgBG;YACW,uBAAuB;IAkDrC;;;;;;;;;;;;;;;;;;;OAmBG;YACW,mBAAmB;IA2BjC,0EAA0E;YAC5D,wBAAwB;IAmCtC,yGAAyG;IACzG,OAAO,CAAC,gBAAgB;IAWxB,4FAA4F;IAC5F,OAAO,CAAC,eAAe;IAcvB;;;;;;;;OAQG;YACW,oBAAoB;IA6ClC;;;;OAIG;IACH,OAAO,CAAC,SAAS;IAKjB;;;;;;OAMG;YACW,2BAA2B;IAqBzC;;;;;;OAMG;IACH,OAAO,CAAC,yBAAyB;IAmBjC;;;;;;;OAOG;YACW,uBAAuB;IA8BrC,oGAAoG;IACpG,OAAO,CAAC,mBAAmB;IAwB3B;;;;;;;OAOG;WACW,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG;IAgBjE;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA2BlC;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAUvB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,iBAAiB;IA8EzB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,IAAI,GAAG;QAC5E,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,OAAO,CAAA;KACtB;IAoBD,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAyBzF"}
|