Skip to content

Commit 1bd7fee

Browse files
authored
Merge pull request #84 from monarch-orm/extend-types
Preserve type instance with type modifier methods
2 parents d473b73 + 666818b commit 1bd7fee

26 files changed

Lines changed: 397 additions & 253 deletions

.changeset/kind-areas-fix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"monarch-orm": patch
3+
---
4+
5+
Preserve concrete type with type modifier methods

src/types/array.ts

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,22 @@ export class MonarchArray<T extends AnyMonarchType> extends MonarchType<InferTyp
3939
this.elementType = type;
4040
}
4141

42+
protected copy() {
43+
return new MonarchArray(this.elementType);
44+
}
45+
4246
/**
4347
* Validates minimum array length.
4448
*
4549
* @param length - Minimum length
4650
* @returns MonarchArray with length validation
4751
*/
4852
public min(length: number) {
49-
return array(this.elementType).extend(this, {
50-
parse: (input) => {
51-
if (input.length < length) {
52-
throw new MonarchParseError(`array must have at least ${length} elements`);
53-
}
54-
return input;
55-
},
53+
return this.parse((input) => {
54+
if (input.length < length) {
55+
throw new MonarchParseError(`array must have at least ${length} elements`);
56+
}
57+
return input;
5658
});
5759
}
5860

@@ -63,13 +65,11 @@ export class MonarchArray<T extends AnyMonarchType> extends MonarchType<InferTyp
6365
* @returns MonarchArray with length validation
6466
*/
6567
public max(length: number) {
66-
return array(this.elementType).extend(this, {
67-
parse: (input) => {
68-
if (input.length > length) {
69-
throw new MonarchParseError(`array must have at most ${length} elements`);
70-
}
71-
return input;
72-
},
68+
return this.parse((input) => {
69+
if (input.length > length) {
70+
throw new MonarchParseError(`array must have at most ${length} elements`);
71+
}
72+
return input;
7373
});
7474
}
7575

@@ -80,13 +80,11 @@ export class MonarchArray<T extends AnyMonarchType> extends MonarchType<InferTyp
8080
* @returns MonarchArray with length validation
8181
*/
8282
public length(length: number) {
83-
return array(this.elementType).extend(this, {
84-
parse: (input) => {
85-
if (input.length !== length) {
86-
throw new MonarchParseError(`array must have exactly ${length} elements`);
87-
}
88-
return input;
89-
},
83+
return this.parse((input) => {
84+
if (input.length !== length) {
85+
throw new MonarchParseError(`array must have exactly ${length} elements`);
86+
}
87+
return input;
9088
});
9189
}
9290

@@ -96,6 +94,11 @@ export class MonarchArray<T extends AnyMonarchType> extends MonarchType<InferTyp
9694
* @returns MonarchArray with non-empty validation
9795
*/
9896
public nonempty() {
99-
return this.min(1);
97+
return this.parse((input) => {
98+
if (input.length === 0) {
99+
throw new MonarchParseError("array must not be empty");
100+
}
101+
return input;
102+
});
100103
}
101104
}

src/types/binary.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,8 @@ export class MonarchBinary extends MonarchType<Buffer | Binary, Binary> {
2020
throw new MonarchParseError(`expected 'Buffer' or 'Binary' received '${typeof input}'`);
2121
});
2222
}
23+
24+
protected copy() {
25+
return new MonarchBinary();
26+
}
2327
}

src/types/boolean.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@ export class MonarchBoolean extends MonarchType<boolean, boolean> {
1818
throw new MonarchParseError(`expected 'boolean' received '${typeof input}'`);
1919
});
2020
}
21+
22+
protected copy() {
23+
return new MonarchBoolean();
24+
}
2125
}

src/types/date.ts

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,22 @@ export class MonarchDate extends MonarchType<Date, Date> {
1919
});
2020
}
2121

22+
protected copy() {
23+
return new MonarchDate();
24+
}
25+
2226
/**
2327
* Validates date is after a target date.
2428
*
2529
* @param targetDate - Target date for comparison
2630
* @returns MonarchDate with after validation
2731
*/
2832
public after(targetDate: Date) {
29-
return date().extend(this, {
30-
parse: (input) => {
31-
if (input <= targetDate) {
32-
throw new MonarchParseError(`date must be after ${targetDate.toISOString()}`);
33-
}
34-
return input;
35-
},
33+
return this.parse((input) => {
34+
if (input <= targetDate) {
35+
throw new MonarchParseError(`date must be after ${targetDate.toISOString()}`);
36+
}
37+
return input;
3638
});
3739
}
3840

@@ -43,13 +45,11 @@ export class MonarchDate extends MonarchType<Date, Date> {
4345
* @returns MonarchDate with before validation
4446
*/
4547
public before(targetDate: Date) {
46-
return date().extend(this, {
47-
parse: (input) => {
48-
if (input >= targetDate) {
49-
throw new MonarchParseError(`date must be before ${targetDate.toISOString()}`);
50-
}
51-
return input;
52-
},
48+
return this.parse((input) => {
49+
if (input >= targetDate) {
50+
throw new MonarchParseError(`date must be before ${targetDate.toISOString()}`);
51+
}
52+
return input;
5353
});
5454
}
5555
}
@@ -66,10 +66,7 @@ export const createdAt = () => date().default(() => new Date());
6666
*
6767
* @returns MonarchDate with update and default values
6868
*/
69-
export const updatedAt = () => {
70-
const base = date();
71-
return base.extend(base, { onUpdate: () => new Date() }).default(() => new Date());
72-
};
69+
export const updatedAt = () => createdAt().onUpdate(() => new Date());
7370

7471
/**
7572
* Date string type that accepts ISO date strings.
@@ -91,20 +88,22 @@ export class MonarchDateString extends MonarchType<string, Date> {
9188
});
9289
}
9390

91+
protected copy() {
92+
return new MonarchDateString();
93+
}
94+
9495
/**
9596
* Validates date is after a target date.
9697
*
9798
* @param targetDate - Target date for comparison
9899
* @returns MonarchDateString with after validation
99100
*/
100101
public after(targetDate: Date) {
101-
return dateString().extend(this, {
102-
parse: (input) => {
103-
if (input <= targetDate) {
104-
throw new MonarchParseError(`date must be after ${targetDate.toISOString()}`);
105-
}
106-
return input;
107-
},
102+
return this.parse((input: Date) => {
103+
if (input <= targetDate) {
104+
throw new MonarchParseError(`date must be after ${targetDate.toISOString()}`);
105+
}
106+
return input;
108107
});
109108
}
110109

@@ -115,13 +114,11 @@ export class MonarchDateString extends MonarchType<string, Date> {
115114
* @returns MonarchDateString with before validation
116115
*/
117116
public before(targetDate: Date) {
118-
return dateString().extend(this, {
119-
parse: (input) => {
120-
if (input >= targetDate) {
121-
throw new MonarchParseError(`date must be before ${targetDate.toISOString()}`);
122-
}
123-
return input;
124-
},
117+
return this.parse((input: Date) => {
118+
if (input >= targetDate) {
119+
throw new MonarchParseError(`date must be before ${targetDate.toISOString()}`);
120+
}
121+
return input;
125122
});
126123
}
127124
}

src/types/decimal128.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,8 @@ export class MonarchDecimal128 extends MonarchType<Decimal128 | string, Decimal1
2020
throw new MonarchParseError(`expected 'Decimal128' or 'string' received '${typeof input}'`);
2121
});
2222
}
23+
24+
protected copy() {
25+
return new MonarchDecimal128();
26+
}
2327
}

src/types/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ export {
2121
defaulted,
2222
nullable,
2323
optional,
24-
pipeParser,
2524
type,
2625
type AnyMonarchType,
2726
type Parser,

src/types/literal.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ export const literal = <T extends string | number | boolean>(...values: T[]) =>
1313
* Type for literal fields.
1414
*/
1515
export class MonarchLiteral<T extends string | number | boolean> extends MonarchType<T, T> {
16-
constructor(values: T[]) {
16+
constructor(private values: T[]) {
1717
super((input) => {
1818
const _values = new Set(values);
1919
if (_values.has(input)) return input;
2020
throw new MonarchParseError(`unknown value '${input}', literal may only specify known values`);
2121
});
2222
}
23+
24+
protected copy() {
25+
return new MonarchLiteral(this.values);
26+
}
2327
}

src/types/long.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,8 @@ export class MonarchLong extends MonarchType<Long | number | bigint, Long | numb
2727
throw new MonarchParseError(`expected 'Long', 'number', or 'bigint' received '${typeof input}'`);
2828
});
2929
}
30+
31+
protected copy() {
32+
return new MonarchLong();
33+
}
3034
}

src/types/mixed.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,8 @@ export class MonarchMixed extends MonarchType<unknown, unknown> {
1616
return input;
1717
});
1818
}
19+
20+
protected copy() {
21+
return new MonarchMixed();
22+
}
1923
}

0 commit comments

Comments
 (0)