-
-
Notifications
You must be signed in to change notification settings - Fork 127
merge dev to main (v2.5.2) #1722
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
ab261ae
8b56d7d
1395892
1ea8e55
7880bad
f2a3686
57652a1
cb68815
738bba6
64198a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,7 @@ plugins { | |
| } | ||
|
|
||
| group = "dev.zenstack" | ||
| version = "2.5.1" | ||
| version = "2.5.2" | ||
|
|
||
| repositories { | ||
| mavenCentral() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |
| import deepmerge, { type ArrayMergeOptions } from 'deepmerge'; | ||
| import { isPlainObject } from 'is-plain-object'; | ||
| import { lowerCaseFirst } from 'lower-case-first'; | ||
| import traverse from 'traverse'; | ||
| import { DELEGATE_AUX_RELATION_PREFIX } from '../../constants'; | ||
| import { | ||
| FieldInfo, | ||
|
|
@@ -77,6 +78,10 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| this.injectWhereHierarchy(model, args?.where); | ||
| this.injectSelectIncludeHierarchy(model, args); | ||
|
|
||
| // discriminator field is needed during post process to determine the | ||
| // actual concrete model type | ||
| this.ensureDiscriminatorSelection(model, args); | ||
|
|
||
| if (args.orderBy) { | ||
| // `orderBy` may contain fields from base types | ||
| this.injectWhereHierarchy(this.model, args.orderBy); | ||
|
|
@@ -94,6 +99,23 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| } | ||
| } | ||
|
|
||
| private ensureDiscriminatorSelection(model: string, args: any) { | ||
| const modelInfo = getModelInfo(this.options.modelMeta, model); | ||
| if (!modelInfo?.discriminator) { | ||
| return; | ||
| } | ||
|
|
||
| if (args.select && typeof args.select === 'object') { | ||
| args.select[modelInfo.discriminator] = true; | ||
| return; | ||
| } | ||
|
|
||
| if (args.omit && typeof args.omit === 'object') { | ||
| args.omit[modelInfo.discriminator] = false; | ||
| return; | ||
| } | ||
| } | ||
|
Comment on lines
+111
to
+126
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Verify the usage of It appears that |
||
|
|
||
| private injectWhereHierarchy(model: string, where: any) { | ||
| if (!where || !isPlainObject(where)) { | ||
| return; | ||
|
|
@@ -168,16 +190,20 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| } | ||
| } | ||
|
|
||
| if (value !== undefined) { | ||
| if (value?.orderBy) { | ||
| // refetch the field select/include value because it may have been | ||
| // updated during injection | ||
| const fieldValue = args[kind][field]; | ||
|
|
||
| if (fieldValue !== undefined) { | ||
| if (fieldValue.orderBy) { | ||
| // `orderBy` may contain fields from base types | ||
| this.injectWhereHierarchy(fieldInfo.type, value.orderBy); | ||
| this.injectWhereHierarchy(fieldInfo.type, fieldValue.orderBy); | ||
| } | ||
|
|
||
| if (this.injectBaseFieldSelect(model, field, value, args, kind)) { | ||
| if (this.injectBaseFieldSelect(model, field, fieldValue, args, kind)) { | ||
| delete args[kind][field]; | ||
| } else if (fieldInfo.isDataModel) { | ||
| let nextValue = value; | ||
| let nextValue = fieldValue; | ||
| if (nextValue === true) { | ||
| // make sure the payload is an object | ||
| args[kind][field] = nextValue = {}; | ||
|
|
@@ -333,6 +359,8 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| ); | ||
| } | ||
|
|
||
| this.sanitizeMutationPayload(args.data); | ||
|
|
||
| if (isDelegateModel(this.options.modelMeta, this.model)) { | ||
| throw prismaClientValidationError( | ||
| this.prisma, | ||
|
|
@@ -348,6 +376,24 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| return this.doCreate(this.prisma, this.model, args); | ||
| } | ||
|
|
||
| private sanitizeMutationPayload(data: any) { | ||
| if (!data) { | ||
| return; | ||
| } | ||
|
|
||
| const prisma = this.prisma; | ||
| const prismaModule = this.options.prismaModule; | ||
| traverse(data).forEach(function () { | ||
| if (this.key?.startsWith(DELEGATE_AUX_RELATION_PREFIX)) { | ||
| throw prismaClientValidationError( | ||
| prisma, | ||
| prismaModule, | ||
| `Auxiliary relation field "${this.key}" cannot be set directly` | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| override createMany(args: { data: any; skipDuplicates?: boolean }): Promise<{ count: number }> { | ||
| if (!args) { | ||
| throw prismaClientValidationError(this.prisma, this.options.prismaModule, 'query argument is required'); | ||
|
|
@@ -360,6 +406,8 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| ); | ||
| } | ||
|
|
||
| this.sanitizeMutationPayload(args.data); | ||
|
|
||
| if (!this.involvesDelegateModel(this.model)) { | ||
| return super.createMany(args); | ||
| } | ||
|
|
@@ -399,6 +447,8 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| ); | ||
| } | ||
|
|
||
| this.sanitizeMutationPayload(args.data); | ||
|
|
||
| if (!this.involvesDelegateModel(this.model)) { | ||
| return super.createManyAndReturn(args); | ||
| } | ||
|
|
@@ -585,6 +635,8 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| ); | ||
| } | ||
|
|
||
| this.sanitizeMutationPayload(args.data); | ||
|
|
||
| if (!this.involvesDelegateModel(this.model)) { | ||
| return super.update(args); | ||
| } | ||
|
|
@@ -604,6 +656,8 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| ); | ||
| } | ||
|
|
||
| this.sanitizeMutationPayload(args.data); | ||
|
|
||
| if (!this.involvesDelegateModel(this.model)) { | ||
| return super.updateMany(args); | ||
| } | ||
|
|
@@ -631,6 +685,9 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| ); | ||
| } | ||
|
|
||
| this.sanitizeMutationPayload(args.update); | ||
| this.sanitizeMutationPayload(args.create); | ||
|
|
||
| if (isDelegateModel(this.options.modelMeta, this.model)) { | ||
| throw prismaClientValidationError( | ||
| this.prisma, | ||
|
|
@@ -1158,11 +1215,11 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| const base = this.getBaseModel(model); | ||
|
|
||
| if (base) { | ||
| // merge base fields | ||
| // fully merge base fields | ||
| const baseRelationName = this.makeAuxRelationName(base); | ||
| const baseData = entity[baseRelationName]; | ||
| if (baseData && typeof baseData === 'object') { | ||
| const baseAssembled = this.assembleUp(base.name, baseData); | ||
| const baseAssembled = this.assembleHierarchy(base.name, baseData); | ||
| Object.assign(result, baseAssembled); | ||
| } | ||
| } | ||
|
|
@@ -1209,14 +1266,14 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler { | |
| const modelInfo = getModelInfo(this.options.modelMeta, model, true); | ||
|
|
||
| if (modelInfo.discriminator) { | ||
| // model is a delegate, merge sub model fields | ||
| // model is a delegate, fully merge concrete model fields | ||
| const subModelName = entity[modelInfo.discriminator]; | ||
| if (subModelName) { | ||
| const subModel = getModelInfo(this.options.modelMeta, subModelName, true); | ||
| const subRelationName = this.makeAuxRelationName(subModel); | ||
| const subData = entity[subRelationName]; | ||
| if (subData && typeof subData === 'object') { | ||
| const subAssembled = this.assembleDown(subModel.name, subData); | ||
| const subAssembled = this.assembleHierarchy(subModel.name, subData); | ||
| Object.assign(result, subAssembled); | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { enumerate, getModelFields, resolveField } from '../../cross'; | |||||||||||||||||||||||||||||
| import { DbClientContract } from '../../types'; | ||||||||||||||||||||||||||||||
| import { InternalEnhancementOptions } from './create-enhancement'; | ||||||||||||||||||||||||||||||
| import { DefaultPrismaProxyHandler, makeProxy } from './proxy'; | ||||||||||||||||||||||||||||||
| import { QueryUtils } from './query-utils'; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||
| * Gets an enhanced Prisma client that supports `@omit` attribute. | ||||||||||||||||||||||||||||||
|
|
@@ -21,8 +22,11 @@ export function withOmit<DbClient extends object>(prisma: DbClient, options: Int | |||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| class OmitHandler extends DefaultPrismaProxyHandler { | ||||||||||||||||||||||||||||||
| private queryUtils: QueryUtils; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| constructor(prisma: DbClientContract, model: string, options: InternalEnhancementOptions) { | ||||||||||||||||||||||||||||||
| super(prisma, model, options); | ||||||||||||||||||||||||||||||
| this.queryUtils = new QueryUtils(prisma, options); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // base override | ||||||||||||||||||||||||||||||
|
|
@@ -67,8 +71,10 @@ class OmitHandler extends DefaultPrismaProxyHandler { | |||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| private async doPostProcess(entityData: any, model: string) { | ||||||||||||||||||||||||||||||
| const realModel = this.queryUtils.getDelegateConcreteModel(model, entityData); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| for (const field of getModelFields(entityData)) { | ||||||||||||||||||||||||||||||
| const fieldInfo = await resolveField(this.options.modelMeta, model, field); | ||||||||||||||||||||||||||||||
| const fieldInfo = await resolveField(this.options.modelMeta, realModel, field); | ||||||||||||||||||||||||||||||
|
Comment on lines
+74
to
+77
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure When calling Apply this diff to add a validation check: private async doPostProcess(entityData: any, model: string) {
const realModel = this.queryUtils.getDelegateConcreteModel(model, entityData);
+ if (!realModel) {
+ // Handle the error appropriately
+ return;
+ }
for (const field of getModelFields(entityData)) {
const fieldInfo = await resolveField(this.options.modelMeta, realModel, field);Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||
| if (!fieldInfo) { | ||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -214,4 +214,22 @@ export class QueryUtils { | |||||||||||||
| safeClone(value: unknown): any { | ||||||||||||||
| return value ? clone(value) : value === undefined || value === null ? {} : value; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| getDelegateConcreteModel(model: string, data: any) { | ||||||||||||||
| if (!data || typeof data !== 'object') { | ||||||||||||||
| return model; | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+219
to
+221
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure Currently, the condition if (!data || typeof data !== 'object' || Array.isArray(data)) {
return model;
}Committable suggestion
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| const modelInfo = getModelInfo(this.options.modelMeta, model); | ||||||||||||||
| if (modelInfo?.discriminator) { | ||||||||||||||
|
Comment on lines
+223
to
+224
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle potential
const modelInfo = getModelInfo(this.options.modelMeta, model);
-if (modelInfo?.discriminator) {
+if (modelInfo && modelInfo.discriminator) {Committable suggestion
Suggested change
|
||||||||||||||
| // model has a discriminator so it can be a polymorphic base, | ||||||||||||||
| // need to find the concrete model | ||||||||||||||
| const concreteModelName = data[modelInfo.discriminator]; | ||||||||||||||
| if (concreteModelName) { | ||||||||||||||
| return concreteModelName; | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| return model; | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tip
Codebase Verification
Changelog is severely outdated and missing version 2.5.2
The changelog has not been updated to include version 2.5.2 or any other 2.x versions. In fact, the most recent entry in the main CHANGELOG.md file is for version 0.5.0, dated 2022-12-15. This significant gap in documentation is a critical issue that needs immediate attention.
Action items:
Analysis chain
LGTM!
The version update aligns with the PR objective of merging dev to main for v2.5.2.
Please verify that the changelog has been updated to reflect the changes included in this release.
Scripts executed
The following scripts were executed for the analysis:
Script:
Length of output: 433
Script:
Length of output: 4639