Skip to content

Commit 4b091bb

Browse files
fix: update operator $addToSet failing schema validation
1 parent 2a15d1f commit 4b091bb

1 file changed

Lines changed: 22 additions & 3 deletions

File tree

src/schema/update.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import {
44
MonarchArray,
55
MonarchDate,
66
MonarchDecimal128,
7+
MonarchDefaulted,
78
MonarchDouble,
89
MonarchInt32,
910
MonarchLong,
11+
MonarchNullable,
1012
MonarchNumber,
1113
MonarchOptional,
1214
MonarchType,
@@ -87,6 +89,20 @@ export function updateParser<T extends AnyMonarchType>(
8789
return input;
8890
}
8991

92+
function unwrapTo<T extends new (...args: any) => AnyMonarchType>(
93+
type: AnyMonarchType,
94+
target: T
95+
): InstanceType<T> {
96+
let unwrapped: any = type;
97+
while (!(unwrapped instanceof target)) {
98+
if (unwrapped instanceof MonarchDefaulted) unwrapped = MonarchDefaulted.type(unwrapped);
99+
else if (unwrapped instanceof MonarchOptional) unwrapped = MonarchOptional.type(unwrapped);
100+
else if (unwrapped instanceof MonarchNullable) unwrapped = MonarchNullable.type(unwrapped);
101+
else break;
102+
}
103+
return unwrapped as InstanceType<T>;
104+
}
105+
90106
function parseFieldsOperator(
91107
op: "$set" | "$min" | "$max",
92108
schemaType: AnyMonarchType,
@@ -127,7 +143,8 @@ function parseArrayOperator(
127143
cause: MonarchParseError.create(`operator '${op}' requires an array field`),
128144
});
129145
}
130-
const elementType = MonarchArray.type(pathType);
146+
const arrayType = unwrapTo(pathType, MonarchArray);
147+
const elementType = MonarchArray.type(arrayType);
131148
const parser = MonarchType.parser(elementType, path);
132149
if (typeof value === "object" && value !== null && "$each" in value) {
133150
const ops = value as { $each: unknown[]; [k: string]: unknown };
@@ -159,7 +176,8 @@ function parseArrayAllOperator(
159176
cause: MonarchParseError.create(`operator '$pullAll' requires an array field`),
160177
});
161178
}
162-
const elementType = MonarchArray.type(pathType);
179+
const arrayType = unwrapTo(pathType, MonarchArray);
180+
const elementType = MonarchArray.type(arrayType);
163181
const parser = MonarchType.parser(elementType, path);
164182
parsed[path] = value.map(parser);
165183
if (schemaUpdates) removeUpdateConflict(path, schemaUpdates);
@@ -333,7 +351,8 @@ function parseRenameOperator(
333351
cause: MonarchParseError.create(`operator '$rename' requires an optional field`),
334352
});
335353
}
336-
const sourceInner = MonarchOptional.type(sourceType);
354+
const sourceOptional = unwrapTo(sourceType, MonarchOptional);
355+
const sourceInner = MonarchOptional.type(sourceOptional);
337356
const destType = MonarchType.index(schemaType, value.split("."), -1);
338357
if (!MonarchType.isInstanceOf(destType, sourceInner.constructor as new (...args: any[]) => AnyMonarchType)) {
339358
throw MonarchParseError.fromCause({

0 commit comments

Comments
 (0)