@palmares/schemas 0.0.1 → 0.1.1

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 (175) hide show
  1. package/.turbo/turbo-build$colon$watch.log +12 -410
  2. package/.turbo/turbo-build.log +13 -4
  3. package/CHANGELOG.md +26 -0
  4. package/__tests__/.drizzle/migrations/0000_skinny_harrier.sql +22 -0
  5. package/__tests__/.drizzle/migrations/meta/0000_snapshot.json +156 -0
  6. package/__tests__/.drizzle/migrations/meta/_journal.json +13 -0
  7. package/__tests__/.drizzle/schema.ts +35 -0
  8. package/__tests__/drizzle.config.ts +11 -0
  9. package/__tests__/eslint.config.js +10 -0
  10. package/__tests__/manage.ts +5 -0
  11. package/__tests__/node_modules/.bin/drizzle-kit +17 -0
  12. package/__tests__/node_modules/.bin/esbuild +14 -0
  13. package/__tests__/node_modules/.bin/tsc +17 -0
  14. package/__tests__/node_modules/.bin/tsserver +17 -0
  15. package/__tests__/node_modules/.bin/tsx +17 -0
  16. package/__tests__/package.json +36 -0
  17. package/__tests__/sqlite.db +0 -0
  18. package/__tests__/src/core/array.test.ts +130 -0
  19. package/__tests__/src/core/boolean.test.ts +66 -0
  20. package/__tests__/src/core/datetime.test.ts +102 -0
  21. package/__tests__/src/core/index.ts +35 -0
  22. package/__tests__/src/core/model.test.ts +260 -0
  23. package/__tests__/src/core/models.ts +50 -0
  24. package/__tests__/src/core/numbers.test.ts +177 -0
  25. package/__tests__/src/core/object.test.ts +198 -0
  26. package/__tests__/src/core/string.test.ts +222 -0
  27. package/__tests__/src/core/test.test.ts +59 -0
  28. package/__tests__/src/core/types.test.ts +97 -0
  29. package/__tests__/src/core/union.test.ts +99 -0
  30. package/__tests__/src/settings.ts +71 -0
  31. package/__tests__/tsconfig.json +11 -0
  32. package/dist/cjs/src/adapter/fields/index.js +2 -2
  33. package/dist/cjs/src/adapter/fields/object.js +9 -0
  34. package/dist/cjs/src/adapter/index.js +1 -0
  35. package/dist/cjs/src/constants.js +1 -7
  36. package/dist/cjs/src/domain.js +146 -1
  37. package/dist/cjs/src/index.js +69 -74
  38. package/dist/cjs/src/model.js +206 -206
  39. package/dist/cjs/src/schema/array.js +185 -58
  40. package/dist/cjs/src/schema/boolean.js +105 -44
  41. package/dist/cjs/src/schema/datetime.js +104 -38
  42. package/dist/cjs/src/schema/number.js +134 -114
  43. package/dist/cjs/src/schema/object.js +106 -43
  44. package/dist/cjs/src/schema/schema.js +123 -75
  45. package/dist/cjs/src/schema/string.js +152 -58
  46. package/dist/cjs/src/schema/union.js +412 -290
  47. package/dist/cjs/src/utils.js +42 -15
  48. package/dist/cjs/src/validators/array.js +6 -1
  49. package/dist/cjs/src/validators/boolean.js +2 -0
  50. package/dist/cjs/src/validators/datetime.js +4 -0
  51. package/dist/cjs/src/validators/number.js +12 -40
  52. package/dist/cjs/src/validators/object.js +1 -0
  53. package/dist/cjs/src/validators/schema.js +5 -1
  54. package/dist/cjs/src/validators/string.js +30 -2
  55. package/dist/cjs/src/validators/union.js +5 -4
  56. package/dist/cjs/src/validators/utils.js +99 -27
  57. package/dist/cjs/tsconfig.types.tsbuildinfo +1 -1
  58. package/dist/cjs/types/adapter/fields/array.d.ts +2 -2
  59. package/dist/cjs/types/adapter/fields/array.d.ts.map +1 -1
  60. package/dist/cjs/types/adapter/fields/boolean.d.ts.map +1 -1
  61. package/dist/cjs/types/adapter/fields/datetime.d.ts.map +1 -1
  62. package/dist/cjs/types/adapter/fields/index.d.ts +2 -2
  63. package/dist/cjs/types/adapter/fields/index.d.ts.map +1 -1
  64. package/dist/cjs/types/adapter/fields/number.d.ts.map +1 -1
  65. package/dist/cjs/types/adapter/fields/object.d.ts +2 -1
  66. package/dist/cjs/types/adapter/fields/object.d.ts.map +1 -1
  67. package/dist/cjs/types/adapter/fields/string.d.ts.map +1 -1
  68. package/dist/cjs/types/adapter/fields/union.d.ts.map +1 -1
  69. package/dist/cjs/types/adapter/index.d.ts +1 -0
  70. package/dist/cjs/types/adapter/index.d.ts.map +1 -1
  71. package/dist/cjs/types/adapter/types.d.ts +28 -18
  72. package/dist/cjs/types/adapter/types.d.ts.map +1 -1
  73. package/dist/cjs/types/constants.d.ts +0 -1
  74. package/dist/cjs/types/constants.d.ts.map +1 -1
  75. package/dist/cjs/types/domain.d.ts +5 -4
  76. package/dist/cjs/types/domain.d.ts.map +1 -1
  77. package/dist/cjs/types/index.d.ts +78 -55
  78. package/dist/cjs/types/index.d.ts.map +1 -1
  79. package/dist/cjs/types/model.d.ts +17 -17
  80. package/dist/cjs/types/model.d.ts.map +1 -1
  81. package/dist/cjs/types/schema/array.d.ts +168 -47
  82. package/dist/cjs/types/schema/array.d.ts.map +1 -1
  83. package/dist/cjs/types/schema/boolean.d.ts +103 -44
  84. package/dist/cjs/types/schema/boolean.d.ts.map +1 -1
  85. package/dist/cjs/types/schema/datetime.d.ts +90 -30
  86. package/dist/cjs/types/schema/datetime.d.ts.map +1 -1
  87. package/dist/cjs/types/schema/number.d.ts +133 -125
  88. package/dist/cjs/types/schema/number.d.ts.map +1 -1
  89. package/dist/cjs/types/schema/object.d.ts +104 -35
  90. package/dist/cjs/types/schema/object.d.ts.map +1 -1
  91. package/dist/cjs/types/schema/schema.d.ts +62 -44
  92. package/dist/cjs/types/schema/schema.d.ts.map +1 -1
  93. package/dist/cjs/types/schema/string.d.ts +152 -65
  94. package/dist/cjs/types/schema/string.d.ts.map +1 -1
  95. package/dist/cjs/types/schema/types.d.ts +11 -2
  96. package/dist/cjs/types/schema/types.d.ts.map +1 -1
  97. package/dist/cjs/types/schema/union.d.ts +133 -40
  98. package/dist/cjs/types/schema/union.d.ts.map +1 -1
  99. package/dist/cjs/types/types.d.ts +35 -0
  100. package/dist/cjs/types/types.d.ts.map +1 -1
  101. package/dist/cjs/types/utils.d.ts +41 -27
  102. package/dist/cjs/types/utils.d.ts.map +1 -1
  103. package/dist/cjs/types/validators/array.d.ts.map +1 -1
  104. package/dist/cjs/types/validators/boolean.d.ts.map +1 -1
  105. package/dist/cjs/types/validators/datetime.d.ts.map +1 -1
  106. package/dist/cjs/types/validators/number.d.ts +5 -6
  107. package/dist/cjs/types/validators/number.d.ts.map +1 -1
  108. package/dist/cjs/types/validators/object.d.ts.map +1 -1
  109. package/dist/cjs/types/validators/schema.d.ts +2 -2
  110. package/dist/cjs/types/validators/schema.d.ts.map +1 -1
  111. package/dist/cjs/types/validators/string.d.ts +9 -9
  112. package/dist/cjs/types/validators/string.d.ts.map +1 -1
  113. package/dist/cjs/types/validators/utils.d.ts +44 -27
  114. package/dist/cjs/types/validators/utils.d.ts.map +1 -1
  115. package/dist/esm/src/adapter/fields/index.js +2 -2
  116. package/dist/esm/src/adapter/fields/object.js +6 -0
  117. package/dist/esm/src/adapter/index.js +1 -0
  118. package/dist/esm/src/constants.js +1 -2
  119. package/dist/esm/src/domain.js +11 -1
  120. package/dist/esm/src/index.js +38 -73
  121. package/dist/esm/src/model.js +83 -78
  122. package/dist/esm/src/schema/array.js +136 -54
  123. package/dist/esm/src/schema/boolean.js +98 -44
  124. package/dist/esm/src/schema/datetime.js +91 -38
  125. package/dist/esm/src/schema/number.js +127 -110
  126. package/dist/esm/src/schema/object.js +98 -43
  127. package/dist/esm/src/schema/schema.js +102 -67
  128. package/dist/esm/src/schema/string.js +147 -59
  129. package/dist/esm/src/schema/union.js +119 -40
  130. package/dist/esm/src/types.js +14 -1
  131. package/dist/esm/src/utils.js +56 -27
  132. package/dist/esm/src/validators/array.js +6 -1
  133. package/dist/esm/src/validators/boolean.js +2 -0
  134. package/dist/esm/src/validators/datetime.js +4 -0
  135. package/dist/esm/src/validators/number.js +9 -23
  136. package/dist/esm/src/validators/object.js +1 -0
  137. package/dist/esm/src/validators/schema.js +5 -1
  138. package/dist/esm/src/validators/string.js +30 -2
  139. package/dist/esm/src/validators/union.js +5 -4
  140. package/dist/esm/src/validators/utils.js +62 -36
  141. package/package.json +3 -3
  142. package/src/adapter/fields/array.ts +2 -2
  143. package/src/adapter/fields/boolean.ts +3 -8
  144. package/src/adapter/fields/datetime.ts +3 -9
  145. package/src/adapter/fields/index.ts +11 -11
  146. package/src/adapter/fields/number.ts +3 -9
  147. package/src/adapter/fields/object.ts +13 -10
  148. package/src/adapter/fields/string.ts +3 -9
  149. package/src/adapter/fields/union.ts +3 -9
  150. package/src/adapter/index.ts +1 -0
  151. package/src/adapter/types.ts +60 -45
  152. package/src/constants.ts +1 -3
  153. package/src/domain.ts +15 -1
  154. package/src/index.ts +189 -211
  155. package/src/model.ts +119 -115
  156. package/src/schema/array.ts +274 -90
  157. package/src/schema/boolean.ts +145 -60
  158. package/src/schema/datetime.ts +133 -49
  159. package/src/schema/number.ts +210 -173
  160. package/src/schema/object.ts +167 -74
  161. package/src/schema/schema.ts +205 -126
  162. package/src/schema/string.ts +221 -94
  163. package/src/schema/types.ts +44 -16
  164. package/src/schema/union.ts +193 -68
  165. package/src/types.ts +53 -0
  166. package/src/utils.ts +115 -57
  167. package/src/validators/array.ts +46 -27
  168. package/src/validators/boolean.ts +13 -7
  169. package/src/validators/datetime.ts +24 -16
  170. package/src/validators/number.ts +53 -63
  171. package/src/validators/object.ts +6 -5
  172. package/src/validators/schema.ts +33 -25
  173. package/src/validators/string.ts +122 -59
  174. package/src/validators/union.ts +8 -8
  175. package/src/validators/utils.ts +67 -42
@@ -0,0 +1,260 @@
1
+ import * as p from '@palmares/schemas';
2
+ import { afterAll, beforeAll, describe } from '@palmares/tests';
3
+ import { Company, User } from './models';
4
+
5
+ describe('Model tests', ({ test }) => {
6
+ beforeAll(async () => {
7
+ await Company.default.set({
8
+ name: 'Targaryen',
9
+ usersOfCompany: [{
10
+ name: 'Rhaenyra Targaryen',
11
+ age: 25
12
+ }, {
13
+ name: 'Aegon Targaryen',
14
+ age: 21
15
+ }]
16
+ }, {
17
+ includes: [{
18
+ model: User
19
+ }]
20
+ })
21
+ await Company.default.set({
22
+ name: 'Stark',
23
+ usersOfCompany: [{
24
+ name: 'Arya Stark',
25
+ age: 22
26
+ }, {
27
+ name: 'Ned Stark',
28
+ age: 46
29
+ }, {
30
+ name: 'Sansa Stark',
31
+ age: 26
32
+ }]
33
+ }, {
34
+ includes: [{
35
+ model: User
36
+ }]
37
+ })
38
+ });
39
+
40
+
41
+ test('basic', async ({ expect }) => {
42
+ const modelWithAllFields = p.modelSchema(User, {
43
+ omit: []
44
+ });
45
+ const modelWithFieldsOmitted = p.modelSchema(User, {
46
+ omit: ['id', 'createdAt']
47
+ });
48
+ const modelWithAFewFieldsShown = p.modelSchema(User, {
49
+ show: ['name', 'age', 'companyId']
50
+ });
51
+ const data = await User.default.get({
52
+ search: {
53
+ name: {
54
+ like: '%Stark'
55
+ }
56
+ }
57
+ })
58
+
59
+ const [
60
+ dataWithAllFields,
61
+ dataWithFieldsOmitted,
62
+ dataWithFewFieldsShown,
63
+ { parsed: parsedDataWithAllFields, errors: errorsOfAllFields },
64
+ { parsed: parsedDataWithFieldsOmitted, errors: errorsOfFieldsOmitted },
65
+ { parsed: parsedDataWithFewFieldsShown, errors: errorsOfAFewFieldsShown }
66
+ ] = await Promise.all([
67
+ modelWithAllFields.data(structuredClone(data[0])),
68
+ modelWithFieldsOmitted.data(structuredClone(data[0])),
69
+ modelWithAFewFieldsShown.data(structuredClone(data[0])),
70
+ modelWithAllFields.parse(structuredClone(data[0])),
71
+ modelWithFieldsOmitted.parse(structuredClone(data[0])),
72
+ modelWithAFewFieldsShown.parse(structuredClone(data[0])),
73
+ ])
74
+
75
+ expect(
76
+ Object.keys(dataWithAllFields).every((key) => ['id', 'name', 'age', 'updatedAt', 'createdAt', 'companyId'].includes(key))
77
+ ).toBe(true);
78
+ expect(
79
+ Object.keys(dataWithFieldsOmitted).every((key) => ['name', 'age', 'updatedAt', 'companyId'].includes(key)) &&
80
+ Object.keys(dataWithFieldsOmitted).every((key) => !['id', 'createdAt'].includes(key))
81
+ ).toBe(true);
82
+ expect(
83
+ Object.keys(dataWithFewFieldsShown).every((key) => ['age', 'name', 'companyId'].includes(key)) &&
84
+ Object.keys(dataWithFewFieldsShown).every((key) => !['createdAt', 'id', 'updatedAt'].includes(key))
85
+ ).toBe(true);
86
+ expect(
87
+ Object.keys(parsedDataWithAllFields).every((key) => ['id', 'name', 'age', 'updatedAt', 'createdAt', 'companyId'].includes(key))
88
+ ).toBe(true);
89
+ expect(
90
+ Object.keys(parsedDataWithFieldsOmitted).every((key) => ['name', 'age', 'updatedAt', 'companyId'].includes(key)) &&
91
+ Object.keys(parsedDataWithFieldsOmitted).every((key) => !['id', 'createdAt'].includes(key))
92
+ ).toBe(true);
93
+ expect(
94
+ Object.keys(parsedDataWithFewFieldsShown).every((key) => ['age', 'name', 'companyId'].includes(key)) &&
95
+ Object.keys(parsedDataWithFewFieldsShown).every((key) => !['createdAt', 'id', 'updatedAt'].includes(key))
96
+ ).toBe(true);
97
+ expect((errorsOfAllFields || []).length).toBe(0);
98
+ expect((errorsOfFieldsOmitted || []).length).toBe(0);
99
+ expect((errorsOfAFewFieldsShown || []).length).toBe(0);
100
+ });
101
+
102
+ test('array', async ({expect}) => {
103
+ const modelWithAllFields = p.modelSchema(User, {
104
+ many: true,
105
+ omit: []
106
+ });
107
+ const modelWithFieldsOmitted = p.modelSchema(User, {
108
+ many: true,
109
+ omit: ['id', 'createdAt']
110
+ });
111
+ const modelWithAFewFieldsShown = p.modelSchema(User, {
112
+ many: true,
113
+ show: ['name', 'age', 'companyId']
114
+ });
115
+ const data = await User.default.get({
116
+ search: {
117
+ name: {
118
+ like: '%Stark'
119
+ }
120
+ }
121
+ });
122
+
123
+ const [
124
+ dataWithAllFields,
125
+ dataWithFieldsOmitted,
126
+ dataWithFewFieldsShown,
127
+ { parsed: parsedDataWithAllFields, errors: errorsOfAllFields },
128
+ { parsed: parsedDataWithFieldsOmitted, errors: errorsOfFieldsOmitted },
129
+ { parsed: parsedDataWithFewFieldsShown, errors: errorsOfAFewFieldsShown }
130
+ ] = await Promise.all([
131
+ modelWithAllFields.data(structuredClone(data)),
132
+ modelWithFieldsOmitted.data(structuredClone(data)),
133
+ modelWithAFewFieldsShown.data(structuredClone(data)),
134
+ modelWithAllFields.parse(structuredClone(data)),
135
+ modelWithFieldsOmitted.parse(structuredClone(data)),
136
+ modelWithAFewFieldsShown.parse(structuredClone(data)),
137
+ ])
138
+
139
+ expect(
140
+ Object.keys(dataWithAllFields[0]).every((key) => ['id', 'name', 'age', 'updatedAt', 'createdAt', 'companyId'].includes(key))
141
+ ).toBe(true);
142
+ expect(
143
+ Object.keys(dataWithFieldsOmitted[0]).every((key) => ['name', 'age', 'updatedAt', 'companyId'].includes(key)) &&
144
+ Object.keys(dataWithFieldsOmitted[0]).every((key) => !['id', 'createdAt'].includes(key))
145
+ ).toBe(true);
146
+ expect(
147
+ Object.keys(dataWithFewFieldsShown[0]).every((key) => ['age', 'name', 'companyId'].includes(key)) &&
148
+ Object.keys(dataWithFewFieldsShown[0]).every((key) => !['createdAt', 'id', 'updatedAt'].includes(key))
149
+ ).toBe(true);
150
+ expect(
151
+ Object.keys(parsedDataWithAllFields[0]).every((key) => ['id', 'name', 'age', 'updatedAt', 'createdAt', 'companyId'].includes(key))
152
+ ).toBe(true);
153
+ expect(
154
+ Object.keys(parsedDataWithFieldsOmitted[0]).every((key) => ['name', 'age', 'updatedAt', 'companyId'].includes(key)) &&
155
+ Object.keys(parsedDataWithFieldsOmitted[0]).every((key) => !['id', 'createdAt'].includes(key))
156
+ ).toBe(true);
157
+ expect(
158
+ Object.keys(parsedDataWithFewFieldsShown[0]).every((key) => ['age', 'name', 'companyId'].includes(key)) &&
159
+ Object.keys(parsedDataWithFewFieldsShown[0]).every((key) => !['createdAt', 'id', 'updatedAt'].includes(key))
160
+ ).toBe(true);
161
+ expect(dataWithAllFields.length).toBe(data.length);
162
+ expect(dataWithFieldsOmitted.length).toBe(data.length);
163
+ expect(dataWithFewFieldsShown.length).toBe(data.length);
164
+ expect(parsedDataWithAllFields.length).toBe(data.length);
165
+ expect(parsedDataWithFieldsOmitted.length).toBe(data.length);
166
+ expect(parsedDataWithFewFieldsShown.length).toBe(data.length);
167
+ expect((errorsOfAllFields || []).length).toBe(0);
168
+ expect((errorsOfFieldsOmitted || []).length).toBe(0);
169
+ expect((errorsOfAFewFieldsShown || []).length).toBe(0);
170
+ });
171
+
172
+ test('auto join', async ({ expect }) => {
173
+ const companyModel = p.modelSchema(Company, {
174
+ omit: ['translatable'],
175
+ }).optional({ outputOnly: true });
176
+ const userModel = p.modelSchema(User, {
177
+ many: true,
178
+ omit: []
179
+ }).optional({ outputOnly: true });
180
+
181
+ const arrayModelDirectly = p.modelSchema(User, {
182
+ many: true,
183
+ fields: {
184
+ company: companyModel
185
+ },
186
+ omit: [],
187
+ });
188
+ const arrayModelIndirectly = p.modelSchema(Company, {
189
+ many: true,
190
+ fields: {
191
+ usersOfCompany: userModel
192
+ },
193
+ omit: [],
194
+ })
195
+ const objectModelDirectly = p.modelSchema(User, {
196
+ fields: {
197
+ company: companyModel
198
+ },
199
+ omit: [],
200
+ });
201
+
202
+ const objectModelIndirectly = p.modelSchema(Company, {
203
+ fields: {
204
+ usersOfCompany: userModel
205
+ },
206
+ omit: [],
207
+ });
208
+
209
+ const userData = await User.default.get({
210
+ search: {
211
+ name: {
212
+ like: '%Stark'
213
+ }
214
+ }
215
+ });
216
+ const companyData = await Company.default.get({
217
+ search: {
218
+ name: 'Targaryen'
219
+ }
220
+ });
221
+
222
+ const [
223
+ arrayModelDirectlyData,
224
+ arrayModelIndirectlyData,
225
+ objectModelDirectlyData,
226
+ objectModelIndirectlyData
227
+ ] = await Promise.all([
228
+ arrayModelDirectly.data(structuredClone(userData)),
229
+ arrayModelIndirectly.data(structuredClone(companyData)),
230
+ objectModelDirectly.data(structuredClone(userData[0])),
231
+ objectModelIndirectly.data(structuredClone(companyData[0]))
232
+ ]);
233
+
234
+ expect(arrayModelDirectlyData.length).toBe(3);
235
+ expect(arrayModelDirectlyData[0].company.name).toBe('Stark');
236
+ expect(arrayModelDirectlyData[2].company.name).toBe('Stark')
237
+ expect(arrayModelIndirectlyData[0].usersOfCompany.length).toBe(2);
238
+ expect(arrayModelIndirectlyData[0].usersOfCompany[0].companyId).toBe(arrayModelIndirectlyData[0].id as number);
239
+ expect(objectModelDirectlyData.company.name).toBe('Stark');
240
+ expect(objectModelIndirectlyData.usersOfCompany.length).toBe(2);
241
+ expect(objectModelIndirectlyData.usersOfCompany[0].companyId).toBe(objectModelIndirectlyData.id as number);
242
+ });
243
+
244
+ afterAll(async () => {
245
+ await User.default.remove({
246
+ search: {
247
+ name: {
248
+ in: ['Arya Stark', 'Ned Stark', 'Sansa Stark', 'Sansa Start', 'Rhaenyra Targaryen', 'Aegon Targaryen']
249
+ }
250
+ }
251
+ });
252
+ await Company.default.remove({
253
+ search: {
254
+ name: {
255
+ in: ['Stark', 'Targaryen']
256
+ }
257
+ }
258
+ });
259
+ });
260
+ });
@@ -0,0 +1,50 @@
1
+ import {
2
+ AutoField,
3
+ CharField,
4
+ DateField,
5
+ ForeignKeyField,
6
+ IntegerField,
7
+ Model,
8
+ ON_DELETE,
9
+ TranslatableField,
10
+ define
11
+ } from '@palmares/databases';
12
+
13
+ import type { ModelOptionsType } from '@palmares/databases';
14
+
15
+ export const Company = define('Company', {
16
+ fields: {
17
+ id: AutoField.new(),
18
+ name: CharField.new({ maxLength: 255 }),
19
+ translatable: TranslatableField.new({
20
+ // eslint-disable-next-line ts/require-await
21
+ translate: async () => {
22
+ return `d.real('translatable')`;
23
+ }
24
+ })
25
+ },
26
+ options: {
27
+ tableName: 'companies'
28
+ }
29
+ });
30
+
31
+ export class User extends Model<User>() {
32
+ fields = {
33
+ id: AutoField.new(),
34
+ companyId: ForeignKeyField.new({
35
+ onDelete: ON_DELETE.CASCADE,
36
+ relatedName: 'usersOfCompany',
37
+ relationName: 'company',
38
+ toField: 'id',
39
+ relatedTo: Company
40
+ }),
41
+ name: CharField.new({ maxLength: 255, dbIndex: true, allowNull: true }),
42
+ age: IntegerField.new({ dbIndex: true }),
43
+ updatedAt: DateField.new({ autoNow: true }),
44
+ createdAt: DateField.new({ autoNowAdd: true })
45
+ };
46
+
47
+ options: ModelOptionsType<User> = {
48
+ tableName: 'users'
49
+ };
50
+ }
@@ -0,0 +1,177 @@
1
+ import * as p from '@palmares/schemas';
2
+ import { describe } from '@palmares/tests';
3
+
4
+ import type JestTestAdapter from '@palmares/jest-tests';
5
+
6
+ describe<JestTestAdapter>('Number Tests', ({ test }) => {
7
+ test('optional', async ({ expect }) => {
8
+ const numberSchema = p.number();
9
+ const numberSchemaWithCustomMessage = p.number().nonOptional({ message: 'hello' });
10
+
11
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
12
+ await Promise.all([
13
+ numberSchema.parse(undefined as any),
14
+ numberSchemaWithCustomMessage.parse(undefined as any),
15
+ numberSchema.parse(1)
16
+ ]);
17
+
18
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
19
+ expect(errorsOnFail?.[0]?.code).toBe('required');
20
+ expect(errorsOnFail?.[0]?.message).toBe('Required');
21
+ expect((errorsOnValid || []).length).toBe(0);
22
+ expect(parsed).toBe(1);
23
+ });
24
+
25
+ test('nullable', async ({ expect }) => {
26
+ const numberSchema = p.number();
27
+ const numberSchemaWithCustomMessage = p.number().nonNullable({ message: 'hello' });
28
+
29
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
30
+ await Promise.all([
31
+ numberSchema.parse(null as any),
32
+ numberSchemaWithCustomMessage.parse(null as any),
33
+ numberSchema.parse(1)
34
+ ]);
35
+
36
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
37
+ expect(errorsOnFail?.[0]?.code).toBe('null');
38
+ expect(errorsOnFail?.[0]?.message).toBe('Cannot be null');
39
+ expect((errorsOnValid || []).length).toBe(0);
40
+ expect(parsed).toBe(1);
41
+ });
42
+
43
+ test('maxDigits', async ({ expect }) => {
44
+ const numberSchema = p.number().maxDigits(5);
45
+ const numberSchemaWithCustomMessage = p.number().maxDigits(5, { message: 'hello' });
46
+
47
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
48
+ await Promise.all([
49
+ numberSchema.parse(1234567),
50
+ numberSchemaWithCustomMessage.parse(1234567),
51
+ numberSchema.parse(1)
52
+ ]);
53
+
54
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
55
+ expect(errorsOnFail?.[0]?.code).toBe('maxDigits');
56
+ expect(errorsOnFail?.[0]?.message).toBe('The number should have at most 5 digits');
57
+ expect((errorsOnValid || []).length).toBe(0);
58
+ expect(parsed).toBe(1);
59
+ });
60
+
61
+ test('decimalPlaces', async ({ expect }) => {
62
+ const numberSchema = p.number().decimalPlaces(2);
63
+ const numberSchemaWithCustomMessage = p.number().decimalPlaces(2, { message: 'hello' });
64
+
65
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
66
+ await Promise.all([
67
+ numberSchema.parse(123.4567),
68
+ numberSchemaWithCustomMessage.parse(123.4567),
69
+ numberSchema.parse(1)
70
+ ]);
71
+
72
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
73
+ expect(errorsOnFail?.[0]?.code).toBe('decimalPlaces');
74
+ expect(errorsOnFail?.[0]?.message).toBe('The number should have 2 decimal places');
75
+ expect((errorsOnValid || []).length).toBe(0);
76
+ expect(parsed).toBe(1);
77
+ });
78
+
79
+ test('is', async ({ expect }) => {
80
+ const numberSchema = p.number().is([1, 2]);
81
+ const numberSchemaWithCustomMessage = p.number().is([1, 2], { message: 'hello' });
82
+
83
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
84
+ await Promise.all([
85
+ numberSchema.parse(123.4567 as any),
86
+ numberSchemaWithCustomMessage.parse(123.4567 as any),
87
+ numberSchema.parse(1)
88
+ ]);
89
+
90
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
91
+ expect(errorsOnFail?.[0]?.code).toBe('is');
92
+ expect(errorsOnFail?.[0]?.message).toBe('The value should be equal to 1,2');
93
+ expect((errorsOnValid || []).length).toBe(0);
94
+ expect(parsed).toBe(1);
95
+ });
96
+
97
+ test('is', async ({ expect }) => {
98
+ const numberSchema = p.number().is([1, 2]);
99
+ const numberSchemaWithCustomMessage = p.number().is([1, 2], { message: 'hello' });
100
+
101
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
102
+ await Promise.all([
103
+ numberSchema.parse(123.4567 as any),
104
+ numberSchemaWithCustomMessage.parse(123.4567 as any),
105
+ numberSchema.parse(1)
106
+ ]);
107
+
108
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
109
+ expect(errorsOnFail?.[0]?.code).toBe('is');
110
+ expect(errorsOnFail?.[0]?.message).toBe('The value should be equal to 1,2');
111
+ expect((errorsOnValid || []).length).toBe(0);
112
+ expect(parsed).toBe(1);
113
+ });
114
+
115
+ test('integer', async ({ expect }) => {
116
+ const numberSchema = p.number().integer();
117
+ const numberSchemaWithCustomMessage = p.number().integer({ message: 'hello' });
118
+
119
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
120
+ await Promise.all([
121
+ numberSchema.parse(123.4567 as any),
122
+ numberSchemaWithCustomMessage.parse(123.4567 as any),
123
+ numberSchema.parse(1)
124
+ ]);
125
+
126
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
127
+ expect(errorsOnFail?.[0]?.code).toBe('integer');
128
+ expect(errorsOnFail?.[0]?.message).toBe('The number should be an integer.');
129
+ expect((errorsOnValid || []).length).toBe(0);
130
+ expect(parsed).toBe(1);
131
+ });
132
+
133
+ test('max', async ({ expect }) => {
134
+ const numberSchema = p.number().max(100, { inclusive: true });
135
+ const numberSchemaWithCustomMessage = p.number().max(100, { message: 'hello' });
136
+
137
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
138
+ await Promise.all([
139
+ numberSchema.parse(123 as any),
140
+ numberSchemaWithCustomMessage.parse(123 as any),
141
+ numberSchema.parse(100)
142
+ ]);
143
+
144
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
145
+ expect(errorsOnFail?.[0]?.code).toBe('max');
146
+ expect(errorsOnFail?.[0]?.message).toBe(
147
+ 'The number is greater than the allowed 100. The value 100 is accepted as well.'
148
+ );
149
+ expect((errorsOnValid || []).length).toBe(0);
150
+ expect(parsed).toBe(100);
151
+ });
152
+
153
+ test('min', async ({ expect }) => {
154
+ const numberSchema = p.number().min(100, { inclusive: true });
155
+ const numberSchemaWithCustomMessage = p.number().min(100, { message: 'hello' });
156
+
157
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
158
+ await Promise.all([numberSchema.parse(1), numberSchemaWithCustomMessage.parse(1), numberSchema.parse(100)]);
159
+
160
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
161
+ expect(errorsOnFail?.[0]?.code).toBe('min');
162
+ expect(errorsOnFail?.[0]?.message).toBe(
163
+ 'The number is less than the allowed 100. The value 100 is accepted as well.'
164
+ );
165
+ expect((errorsOnValid || []).length).toBe(0);
166
+ expect(parsed).toBe(100);
167
+ });
168
+
169
+ test('allowString', async ({ expect }) => {
170
+ const numberSchema = p.number().allowString();
171
+
172
+ const { errors, parsed } = await numberSchema.parse('100');
173
+
174
+ expect((errors || []).length).toBe(0);
175
+ expect(parsed).toBe(100);
176
+ });
177
+ });
@@ -0,0 +1,198 @@
1
+ import * as p from '@palmares/schemas';
2
+ import { describe } from '@palmares/tests';
3
+
4
+ import type JestTestAdapter from '@palmares/jest-tests';
5
+
6
+ describe<JestTestAdapter>('Object Tests', ({ test }) => {
7
+ test('optional', async ({ expect }) => {
8
+ const objectSchema = p.object({
9
+ name: p.string(),
10
+ age: p.number()
11
+ });
12
+ const objectSchemaWithCustomMessage = p
13
+ .object({
14
+ name: p.string(),
15
+ age: p.number()
16
+ })
17
+ .nonOptional({ message: 'hello' });
18
+
19
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
20
+ await Promise.all([
21
+ objectSchema.parse(undefined as any),
22
+ objectSchemaWithCustomMessage.parse(undefined as any),
23
+ objectSchema.parse({
24
+ name: 'John',
25
+ age: 30
26
+ })
27
+ ]);
28
+
29
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
30
+ expect(errorsOnFail?.[0]?.code).toBe('required');
31
+ expect(errorsOnFail?.[0]?.message).toBe('Required');
32
+ expect((errorsOnValid || []).length).toBe(0);
33
+ expect(parsed.age).toBe(30);
34
+ expect(parsed.name).toBe('John');
35
+ });
36
+
37
+ test('nullable', async ({ expect }) => {
38
+ const objectSchema = p.object({
39
+ name: p.string(),
40
+ age: p.number()
41
+ });
42
+ const objectSchemaWithCustomMessage = p
43
+ .object({
44
+ name: p.string(),
45
+ age: p.number()
46
+ })
47
+ .nonNullable({ message: 'hello' });
48
+
49
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
50
+ await Promise.all([
51
+ objectSchema.parse(null as any),
52
+ objectSchemaWithCustomMessage.parse(null as any),
53
+ objectSchema.parse({
54
+ name: 'John',
55
+ age: 30
56
+ })
57
+ ]);
58
+
59
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
60
+ expect(errorsOnFail?.[0]?.code).toBe('null');
61
+ expect(errorsOnFail?.[0]?.message).toBe('Cannot be null');
62
+ expect((errorsOnValid || []).length).toBe(0);
63
+ expect(parsed.age).toBe(30);
64
+ expect(parsed.name).toBe('John');
65
+ });
66
+
67
+ test('optional on key', async ({ expect }) => {
68
+ const objectSchema = p.object({
69
+ name: p.string(),
70
+ age: p.number()
71
+ });
72
+ const objectSchemaWithCustomMessage = p.object({
73
+ name: p.string(),
74
+ age: p.number().nonOptional({ message: 'hello' })
75
+ });
76
+
77
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
78
+ await Promise.all([
79
+ objectSchema.parse({
80
+ name: 'John'
81
+ } as any),
82
+ objectSchemaWithCustomMessage.parse({
83
+ name: 'John'
84
+ } as any),
85
+ objectSchema.parse({
86
+ name: 'John',
87
+ age: 30
88
+ })
89
+ ]);
90
+
91
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
92
+ expect(errorsOnFail?.[0]?.code).toBe('required');
93
+ expect(errorsOnFail?.[0]?.message).toBe('Required');
94
+ expect(errorsOnFail?.[0]?.path?.[0]).toBe('age');
95
+ expect((errorsOnValid || []).length).toBe(0);
96
+ expect(parsed.age).toBe(30);
97
+ expect(parsed.name).toBe('John');
98
+ });
99
+
100
+ test('nullable on key', async ({ expect }) => {
101
+ const objectSchema = p.object({
102
+ name: p.string(),
103
+ age: p.number()
104
+ });
105
+ const objectSchemaWithCustomMessage = p.object({
106
+ name: p.string(),
107
+ age: p.number().nonNullable({ message: 'hello' })
108
+ });
109
+
110
+ const [{ errors: errorsOnFail }, { errors: errorsOnFailWithCustomMessage }, { errors: errorsOnValid, parsed }] =
111
+ await Promise.all([
112
+ objectSchema.parse({
113
+ name: 'John',
114
+ age: null
115
+ } as any),
116
+ objectSchemaWithCustomMessage.parse({
117
+ name: 'John',
118
+ age: null
119
+ } as any),
120
+ objectSchema.parse({
121
+ name: 'John',
122
+ age: 30
123
+ })
124
+ ]);
125
+
126
+ expect(errorsOnFailWithCustomMessage?.[0]?.message).toBe('hello');
127
+ expect(errorsOnFail?.[0]?.code).toBe('null');
128
+ expect(errorsOnFail?.[0]?.message).toBe('Cannot be null');
129
+ expect(errorsOnFail?.[0]?.path?.[0]).toBe('age');
130
+ expect((errorsOnValid || []).length).toBe(0);
131
+ expect(parsed.age).toBe(30);
132
+ expect(parsed.name).toBe('John');
133
+ });
134
+
135
+ test('max from string and number', async ({ expect }) => {
136
+ const objectSchema = p.object({
137
+ name: p.string().maxLength(10),
138
+ age: p.number().max(10)
139
+ });
140
+
141
+ const [{ errors: errorsWhenString }, { errors: errorWhenNumber }] = await Promise.all([
142
+ objectSchema.parse({
143
+ name: 'John12345789123',
144
+ age: 10
145
+ } as any),
146
+ objectSchema.parse({
147
+ name: 'John',
148
+ age: 12
149
+ } as any)
150
+ ]);
151
+
152
+ expect(errorsWhenString?.[0]?.code).toBe('maxLength');
153
+ expect(errorWhenNumber?.[0]?.code).toBe('max');
154
+ });
155
+
156
+ test('min from string and number', async ({ expect }) => {
157
+ const objectSchema = p.object({
158
+ name: p.string().minLength(10),
159
+ age: p.number().min(10)
160
+ });
161
+
162
+ const [{ errors: errorsWhenString }, { errors: errorWhenNumber }] = await Promise.all([
163
+ objectSchema.parse({
164
+ name: 'John',
165
+ age: 11
166
+ } as any),
167
+ objectSchema.parse({
168
+ name: 'John123456789123',
169
+ age: 9
170
+ } as any)
171
+ ]);
172
+
173
+ expect(errorsWhenString?.[0]?.code).toBe('minLength');
174
+ expect(errorWhenNumber?.[0]?.code).toBe('min');
175
+ });
176
+
177
+ test('nested issue', async ({ expect }) => {
178
+ const objectSchema = p.object({
179
+ nested: p.object({
180
+ name: p.string(),
181
+ age: p.number().max(10)
182
+ }),
183
+ value: p.number()
184
+ });
185
+
186
+ const { errors } = await objectSchema.parse({
187
+ nested: {
188
+ name: 'John',
189
+ age: 12
190
+ },
191
+ value: 20
192
+ });
193
+
194
+ expect(errors?.[0]?.code).toBe('max');
195
+ expect(errors?.[0]?.path?.[0]).toBe('nested');
196
+ expect(errors?.[0]?.path?.[1]).toBe('age');
197
+ });
198
+ });