@opensaas/stack-core 0.18.1 → 0.19.0
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +153 -0
- package/dist/access/engine.d.ts.map +1 -1
- package/dist/access/engine.js +41 -18
- package/dist/access/engine.js.map +1 -1
- package/dist/access/types.d.ts +9 -0
- package/dist/access/types.d.ts.map +1 -1
- package/dist/config/types.d.ts +69 -41
- package/dist/config/types.d.ts.map +1 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +5 -1
- package/dist/context/index.js.map +1 -1
- package/dist/fields/index.d.ts.map +1 -1
- package/dist/fields/index.js +109 -32
- package/dist/fields/index.js.map +1 -1
- package/dist/fields/select.test.d.ts +2 -0
- package/dist/fields/select.test.d.ts.map +1 -0
- package/dist/fields/select.test.js +194 -0
- package/dist/fields/select.test.js.map +1 -0
- package/dist/validation/schema.test.js +45 -0
- package/dist/validation/schema.test.js.map +1 -1
- package/package.json +2 -2
- package/src/access/engine.ts +44 -22
- package/src/access/types.ts +7 -0
- package/src/config/types.ts +69 -40
- package/src/context/index.ts +14 -1
- package/src/fields/index.ts +129 -33
- package/src/fields/select.test.ts +237 -0
- package/src/validation/schema.test.ts +51 -0
- package/tests/access-relationships.test.ts +17 -0
- package/tests/field-types.test.ts +187 -3
- package/tests/singleton.test.ts +14 -13
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { select } from './index.js';
|
|
3
|
+
describe('select field builder', () => {
|
|
4
|
+
describe('string type (default)', () => {
|
|
5
|
+
it('should throw when no options are provided', () => {
|
|
6
|
+
expect(() => select({ options: [] })).toThrow('Select field must have at least one option');
|
|
7
|
+
});
|
|
8
|
+
it('should return String prisma type for default select field', () => {
|
|
9
|
+
const field = select({
|
|
10
|
+
options: [
|
|
11
|
+
{ label: 'Draft', value: 'draft' },
|
|
12
|
+
{ label: 'Published', value: 'published' },
|
|
13
|
+
],
|
|
14
|
+
});
|
|
15
|
+
const result = field.getPrismaType('status', 'sqlite', 'Post');
|
|
16
|
+
expect(result.type).toBe('String');
|
|
17
|
+
expect(result.enumValues).toBeUndefined();
|
|
18
|
+
});
|
|
19
|
+
it('should add ? modifier for optional string select', () => {
|
|
20
|
+
const field = select({
|
|
21
|
+
options: [{ label: 'Draft', value: 'draft' }],
|
|
22
|
+
});
|
|
23
|
+
const result = field.getPrismaType('status', 'sqlite', 'Post');
|
|
24
|
+
expect(result.modifiers).toBe('?');
|
|
25
|
+
});
|
|
26
|
+
it('should not add ? modifier for required string select', () => {
|
|
27
|
+
const field = select({
|
|
28
|
+
options: [{ label: 'Draft', value: 'draft' }],
|
|
29
|
+
validation: { isRequired: true },
|
|
30
|
+
});
|
|
31
|
+
const result = field.getPrismaType('status', 'sqlite', 'Post');
|
|
32
|
+
expect(result.modifiers).toBeUndefined();
|
|
33
|
+
});
|
|
34
|
+
it('should generate quoted default value for string select', () => {
|
|
35
|
+
const field = select({
|
|
36
|
+
options: [
|
|
37
|
+
{ label: 'Draft', value: 'draft' },
|
|
38
|
+
{ label: 'Published', value: 'published' },
|
|
39
|
+
],
|
|
40
|
+
defaultValue: 'draft',
|
|
41
|
+
});
|
|
42
|
+
const result = field.getPrismaType('status', 'sqlite', 'Post');
|
|
43
|
+
expect(result.modifiers).toBe(' @default("draft")');
|
|
44
|
+
});
|
|
45
|
+
it('should generate union TypeScript type from options', () => {
|
|
46
|
+
const field = select({
|
|
47
|
+
options: [
|
|
48
|
+
{ label: 'Draft', value: 'draft' },
|
|
49
|
+
{ label: 'Published', value: 'published' },
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
const result = field.getTypeScriptType();
|
|
53
|
+
expect(result.type).toBe("'draft' | 'published'");
|
|
54
|
+
expect(result.optional).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
it('should mark TypeScript type as non-optional when required', () => {
|
|
57
|
+
const field = select({
|
|
58
|
+
options: [
|
|
59
|
+
{ label: 'Draft', value: 'draft' },
|
|
60
|
+
{ label: 'Published', value: 'published' },
|
|
61
|
+
],
|
|
62
|
+
validation: { isRequired: true },
|
|
63
|
+
});
|
|
64
|
+
const result = field.getTypeScriptType();
|
|
65
|
+
expect(result.optional).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('enum type (db.type: enum)', () => {
|
|
69
|
+
it('should throw for values that are not valid Prisma identifiers (hyphens)', () => {
|
|
70
|
+
expect(() => select({
|
|
71
|
+
options: [{ label: 'In Progress', value: 'in-progress' }],
|
|
72
|
+
db: { type: 'enum' },
|
|
73
|
+
})).toThrow(/valid Prisma identifiers/);
|
|
74
|
+
});
|
|
75
|
+
it('should throw for values starting with a digit', () => {
|
|
76
|
+
expect(() => select({
|
|
77
|
+
options: [{ label: 'First', value: '1st' }],
|
|
78
|
+
db: { type: 'enum' },
|
|
79
|
+
})).toThrow(/valid Prisma identifiers/);
|
|
80
|
+
});
|
|
81
|
+
it('should throw for values with spaces', () => {
|
|
82
|
+
expect(() => select({
|
|
83
|
+
options: [{ label: 'In Progress', value: 'in progress' }],
|
|
84
|
+
db: { type: 'enum' },
|
|
85
|
+
})).toThrow(/valid Prisma identifiers/);
|
|
86
|
+
});
|
|
87
|
+
it('should accept values with underscores', () => {
|
|
88
|
+
expect(() => select({
|
|
89
|
+
options: [
|
|
90
|
+
{ label: 'In Progress', value: 'in_progress' },
|
|
91
|
+
{ label: 'Done', value: 'done' },
|
|
92
|
+
],
|
|
93
|
+
db: { type: 'enum' },
|
|
94
|
+
})).not.toThrow();
|
|
95
|
+
});
|
|
96
|
+
it('should return derived enum name from listName + fieldName', () => {
|
|
97
|
+
const field = select({
|
|
98
|
+
options: [
|
|
99
|
+
{ label: 'Draft', value: 'draft' },
|
|
100
|
+
{ label: 'Published', value: 'published' },
|
|
101
|
+
],
|
|
102
|
+
db: { type: 'enum' },
|
|
103
|
+
});
|
|
104
|
+
const result = field.getPrismaType('status', 'sqlite', 'Post');
|
|
105
|
+
expect(result.type).toBe('PostStatus');
|
|
106
|
+
});
|
|
107
|
+
it('should capitalize fieldName when deriving enum name', () => {
|
|
108
|
+
const field = select({
|
|
109
|
+
options: [
|
|
110
|
+
{ label: 'Article', value: 'article' },
|
|
111
|
+
{ label: 'Video', value: 'video' },
|
|
112
|
+
],
|
|
113
|
+
db: { type: 'enum' },
|
|
114
|
+
});
|
|
115
|
+
const result = field.getPrismaType('contentType', 'sqlite', 'Post');
|
|
116
|
+
expect(result.type).toBe('PostContentType');
|
|
117
|
+
});
|
|
118
|
+
it('should fall back to capitalized fieldName when listName is not provided', () => {
|
|
119
|
+
const field = select({
|
|
120
|
+
options: [{ label: 'Draft', value: 'draft' }],
|
|
121
|
+
db: { type: 'enum' },
|
|
122
|
+
});
|
|
123
|
+
const result = field.getPrismaType('status');
|
|
124
|
+
expect(result.type).toBe('Status');
|
|
125
|
+
});
|
|
126
|
+
it('should return enumValues in getPrismaType result', () => {
|
|
127
|
+
const field = select({
|
|
128
|
+
options: [
|
|
129
|
+
{ label: 'Draft', value: 'draft' },
|
|
130
|
+
{ label: 'Published', value: 'published' },
|
|
131
|
+
],
|
|
132
|
+
db: { type: 'enum' },
|
|
133
|
+
});
|
|
134
|
+
const result = field.getPrismaType('status', 'sqlite', 'Post');
|
|
135
|
+
expect(result.enumValues).toEqual(['draft', 'published']);
|
|
136
|
+
});
|
|
137
|
+
it('should add ? modifier for optional enum field', () => {
|
|
138
|
+
const field = select({
|
|
139
|
+
options: [{ label: 'Draft', value: 'draft' }],
|
|
140
|
+
db: { type: 'enum' },
|
|
141
|
+
});
|
|
142
|
+
const result = field.getPrismaType('status', 'sqlite', 'Post');
|
|
143
|
+
expect(result.modifiers).toBe('?');
|
|
144
|
+
});
|
|
145
|
+
it('should not add ? modifier for required enum field', () => {
|
|
146
|
+
const field = select({
|
|
147
|
+
options: [{ label: 'Draft', value: 'draft' }],
|
|
148
|
+
db: { type: 'enum' },
|
|
149
|
+
validation: { isRequired: true },
|
|
150
|
+
});
|
|
151
|
+
const result = field.getPrismaType('status', 'sqlite', 'Post');
|
|
152
|
+
expect(result.modifiers).toBeUndefined();
|
|
153
|
+
});
|
|
154
|
+
it('should generate unquoted default value for enum field', () => {
|
|
155
|
+
const field = select({
|
|
156
|
+
options: [
|
|
157
|
+
{ label: 'Draft', value: 'draft' },
|
|
158
|
+
{ label: 'Published', value: 'published' },
|
|
159
|
+
],
|
|
160
|
+
db: { type: 'enum' },
|
|
161
|
+
defaultValue: 'draft',
|
|
162
|
+
});
|
|
163
|
+
const result = field.getPrismaType('status', 'sqlite', 'Post');
|
|
164
|
+
expect(result.modifiers).toBe(' @default(draft)');
|
|
165
|
+
// Explicitly check there are no quotes
|
|
166
|
+
expect(result.modifiers).not.toContain('"');
|
|
167
|
+
});
|
|
168
|
+
it('should include @map modifier for enum field with map option', () => {
|
|
169
|
+
const field = select({
|
|
170
|
+
options: [{ label: 'Draft', value: 'draft' }],
|
|
171
|
+
db: { type: 'enum', map: 'post_status' },
|
|
172
|
+
});
|
|
173
|
+
const result = field.getPrismaType('status', 'sqlite', 'Post');
|
|
174
|
+
expect(result.modifiers).toContain('@map("post_status")');
|
|
175
|
+
});
|
|
176
|
+
it('should generate same union TypeScript type as string select', () => {
|
|
177
|
+
const enumField = select({
|
|
178
|
+
options: [
|
|
179
|
+
{ label: 'Draft', value: 'draft' },
|
|
180
|
+
{ label: 'Published', value: 'published' },
|
|
181
|
+
],
|
|
182
|
+
db: { type: 'enum' },
|
|
183
|
+
});
|
|
184
|
+
const stringField = select({
|
|
185
|
+
options: [
|
|
186
|
+
{ label: 'Draft', value: 'draft' },
|
|
187
|
+
{ label: 'Published', value: 'published' },
|
|
188
|
+
],
|
|
189
|
+
});
|
|
190
|
+
expect(enumField.getTypeScriptType()).toEqual(stringField.getTypeScriptType());
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
//# sourceMappingURL=select.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.test.js","sourceRoot":"","sources":["../../src/fields/select.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEnC,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAA;QAC7F,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;YACnE,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;oBAClC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;iBAC3C;aACF,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAClC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,aAAa,EAAE,CAAA;QAC3C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;aAC9C,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACpC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAC9D,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;gBAC7C,UAAU,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;aACjC,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAA;QAC1C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;oBAClC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;iBAC3C;gBACD,YAAY,EAAE,OAAO;aACtB,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QACrD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;oBAClC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;iBAC3C;aACF,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,iBAAkB,EAAE,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;YACjD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACpC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;YACnE,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;oBAClC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;iBAC3C;gBACD,UAAU,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;aACjC,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,iBAAkB,EAAE,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACrC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACzC,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;YACjF,MAAM,CAAC,GAAG,EAAE,CACV,MAAM,CAAC;gBACL,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;gBACzD,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACrB,CAAC,CACH,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAA;QACvC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,MAAM,CAAC,GAAG,EAAE,CACV,MAAM,CAAC;gBACL,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;gBAC3C,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACrB,CAAC,CACH,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAA;QACvC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,CAAC,GAAG,EAAE,CACV,MAAM,CAAC;gBACL,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;gBACzD,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACrB,CAAC,CACH,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAA;QACvC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,CAAC,GAAG,EAAE,CACV,MAAM,CAAC;gBACL,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;oBAC9C,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;iBACjC;gBACD,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACrB,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAA;QACjB,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;YACnE,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;oBAClC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;iBAC3C;gBACD,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACrB,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;oBACtC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;iBACnC;gBACD,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACrB,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YACpE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;QAC7C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;YACjF,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;gBAC7C,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACrB,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,CAAC,CAAA;YAC7C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACpC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;oBAClC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;iBAC3C;gBACD,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACrB,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAA;QAC3D,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;gBAC7C,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACrB,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACpC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;gBAC7C,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;gBACpB,UAAU,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;aACjC,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAA;QAC1C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;YAC/D,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;oBAClC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;iBAC3C;gBACD,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;gBACpB,YAAY,EAAE,OAAO;aACtB,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;YACjD,uCAAuC;YACvC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QAC7C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;YACrE,MAAM,KAAK,GAAG,MAAM,CAAC;gBACnB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;gBAC7C,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE;aACzC,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAA;QAC3D,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;YACrE,MAAM,SAAS,GAAG,MAAM,CAAC;gBACvB,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;oBAClC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;iBAC3C;gBACD,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACrB,CAAC,CAAA;YAEF,MAAM,WAAW,GAAG,MAAM,CAAC;gBACzB,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;oBAClC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;iBAC3C;aACF,CAAC,CAAA;YAEF,MAAM,CAAC,SAAS,CAAC,iBAAkB,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,iBAAkB,EAAE,CAAC,CAAA;QAClF,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -39,6 +39,20 @@ describe('Zod Schema Generation', () => {
|
|
|
39
39
|
const schema = generateZodSchema(fields, 'create');
|
|
40
40
|
expect(schema).toBeDefined();
|
|
41
41
|
});
|
|
42
|
+
it('should generate schema for enum select field', () => {
|
|
43
|
+
const fields = {
|
|
44
|
+
status: select({
|
|
45
|
+
options: [
|
|
46
|
+
{ label: 'Draft', value: 'draft' },
|
|
47
|
+
{ label: 'Published', value: 'published' },
|
|
48
|
+
],
|
|
49
|
+
db: { type: 'enum' },
|
|
50
|
+
validation: { isRequired: true },
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
const schema = generateZodSchema(fields, 'create');
|
|
54
|
+
expect(schema).toBeDefined();
|
|
55
|
+
});
|
|
42
56
|
it('should make fields optional in update mode', () => {
|
|
43
57
|
const fields = {
|
|
44
58
|
name: text({ validation: { isRequired: true } }),
|
|
@@ -123,6 +137,37 @@ describe('Zod Schema Generation', () => {
|
|
|
123
137
|
expect(result.errors.status).toBeDefined();
|
|
124
138
|
}
|
|
125
139
|
});
|
|
140
|
+
it('should pass validation for valid enum select value', () => {
|
|
141
|
+
const fields = {
|
|
142
|
+
status: select({
|
|
143
|
+
options: [
|
|
144
|
+
{ label: 'Draft', value: 'draft' },
|
|
145
|
+
{ label: 'Published', value: 'published' },
|
|
146
|
+
],
|
|
147
|
+
db: { type: 'enum' },
|
|
148
|
+
validation: { isRequired: true },
|
|
149
|
+
}),
|
|
150
|
+
};
|
|
151
|
+
const result = validateWithZod({ status: 'draft' }, fields, 'create');
|
|
152
|
+
expect(result.success).toBe(true);
|
|
153
|
+
});
|
|
154
|
+
it('should fail validation for invalid enum select value', () => {
|
|
155
|
+
const fields = {
|
|
156
|
+
status: select({
|
|
157
|
+
options: [
|
|
158
|
+
{ label: 'Draft', value: 'draft' },
|
|
159
|
+
{ label: 'Published', value: 'published' },
|
|
160
|
+
],
|
|
161
|
+
db: { type: 'enum' },
|
|
162
|
+
validation: { isRequired: true },
|
|
163
|
+
}),
|
|
164
|
+
};
|
|
165
|
+
const result = validateWithZod({ status: 'archived' }, fields, 'create');
|
|
166
|
+
expect(result.success).toBe(false);
|
|
167
|
+
if (!result.success) {
|
|
168
|
+
expect(result.errors.status).toBeDefined();
|
|
169
|
+
}
|
|
170
|
+
});
|
|
126
171
|
it('should skip system fields in validation', () => {
|
|
127
172
|
const fields = {
|
|
128
173
|
id: text(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.test.js","sourceRoot":"","sources":["../../src/validation/schema.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema.test.js","sourceRoot":"","sources":["../../src/validation/schema.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensaas/stack-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Core stack for OpenSaas - schema definition, access control, and runtime utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@prisma/client": "^7.1.0",
|
|
52
|
-
"@types/node": "^24.
|
|
52
|
+
"@types/node": "^24.11.0",
|
|
53
53
|
"@vitest/coverage-v8": "^4.0.15",
|
|
54
54
|
"typescript": "^5.9.3",
|
|
55
55
|
"vitest": "^4.0.15"
|
package/src/access/engine.ts
CHANGED
|
@@ -204,6 +204,14 @@ export async function buildIncludeWithAccessControl(
|
|
|
204
204
|
return undefined
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
// Skip auto-including relationships when inside a resolveOutput hook
|
|
208
|
+
// This prevents infinite loops when hooks make DB queries that include
|
|
209
|
+
// relationships back to the same entity (e.g., User virtual field queries Posts
|
|
210
|
+
// which includes author back to User, triggering the virtual field again)
|
|
211
|
+
if (args.context._resolveOutputCounter.depth > 0) {
|
|
212
|
+
return undefined
|
|
213
|
+
}
|
|
214
|
+
|
|
207
215
|
type IncludeEntry = boolean | { where?: PrismaFilter; include?: Record<string, IncludeEntry> }
|
|
208
216
|
|
|
209
217
|
const include: Record<string, IncludeEntry> = {}
|
|
@@ -347,17 +355,24 @@ export async function filterReadableFields<T extends Record<string, unknown>>(
|
|
|
347
355
|
// Cast to runtime type for generic execution
|
|
348
356
|
// At runtime, the hook will receive the correct value type for the field
|
|
349
357
|
const hook = fieldConfig.hooks.resolveOutput as unknown as ResolveOutputHookRuntime
|
|
350
|
-
//
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
358
|
+
// Increment depth counter to prevent infinite loops from hooks making DB queries
|
|
359
|
+
// that include relationships back to the same entity
|
|
360
|
+
args.context._resolveOutputCounter.depth++
|
|
361
|
+
try {
|
|
362
|
+
// Use Promise.resolve() to handle both sync and async hooks
|
|
363
|
+
filtered[fieldName] = await Promise.resolve(
|
|
364
|
+
hook({
|
|
365
|
+
value,
|
|
366
|
+
operation: 'query',
|
|
367
|
+
fieldName,
|
|
368
|
+
listKey,
|
|
369
|
+
item,
|
|
370
|
+
context: args.context,
|
|
371
|
+
}),
|
|
372
|
+
)
|
|
373
|
+
} finally {
|
|
374
|
+
args.context._resolveOutputCounter.depth--
|
|
375
|
+
}
|
|
361
376
|
} else {
|
|
362
377
|
filtered[fieldName] = value
|
|
363
378
|
}
|
|
@@ -390,17 +405,24 @@ export async function filterReadableFields<T extends Record<string, unknown>>(
|
|
|
390
405
|
// Virtual fields must have resolveOutput hook to compute their value
|
|
391
406
|
if (fieldConfig.hooks?.resolveOutput && listKey) {
|
|
392
407
|
const hook = fieldConfig.hooks.resolveOutput as unknown as ResolveOutputHookRuntime
|
|
393
|
-
//
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
408
|
+
// Increment depth counter to prevent infinite loops from hooks making DB queries
|
|
409
|
+
// that include relationships back to the same entity
|
|
410
|
+
args.context._resolveOutputCounter.depth++
|
|
411
|
+
try {
|
|
412
|
+
// Use Promise.resolve() to handle both sync and async hooks
|
|
413
|
+
filtered[fieldName] = await Promise.resolve(
|
|
414
|
+
hook({
|
|
415
|
+
value: undefined, // Virtual fields don't have a database value
|
|
416
|
+
operation: 'query',
|
|
417
|
+
fieldName,
|
|
418
|
+
listKey,
|
|
419
|
+
item: filtered, // Pass filtered item so virtual field can access other fields
|
|
420
|
+
context: args.context,
|
|
421
|
+
}),
|
|
422
|
+
)
|
|
423
|
+
} finally {
|
|
424
|
+
args.context._resolveOutputCounter.depth--
|
|
425
|
+
}
|
|
404
426
|
}
|
|
405
427
|
}
|
|
406
428
|
|
package/src/access/types.ts
CHANGED
|
@@ -163,6 +163,13 @@ export interface AccessContext<TPrisma extends PrismaClientLike = PrismaClientLi
|
|
|
163
163
|
storage: StorageUtils
|
|
164
164
|
plugins: Record<string, unknown>
|
|
165
165
|
_isSudo: boolean
|
|
166
|
+
/**
|
|
167
|
+
* Internal mutable counter to track resolveOutput hook depth.
|
|
168
|
+
* When depth > 0, we skip auto-including relationships to prevent infinite loops
|
|
169
|
+
* when hooks make database queries that include relationships back to the original entity.
|
|
170
|
+
* We use a mutable object so that spreading the context preserves the reference.
|
|
171
|
+
*/
|
|
172
|
+
_resolveOutputCounter: { depth: number }
|
|
166
173
|
}
|
|
167
174
|
|
|
168
175
|
/**
|
package/src/config/types.ts
CHANGED
|
@@ -374,6 +374,52 @@ export type BaseFieldConfig<TTypeInfo extends TypeInfo> = {
|
|
|
374
374
|
* ```
|
|
375
375
|
*/
|
|
376
376
|
map?: string
|
|
377
|
+
/**
|
|
378
|
+
* Controls DB-level nullability independently of validation.isRequired.
|
|
379
|
+
* When specified, overrides the default behavior where nullability is inferred
|
|
380
|
+
* from validation.isRequired (required = non-nullable, optional = nullable).
|
|
381
|
+
*
|
|
382
|
+
* This allows you to:
|
|
383
|
+
* - Make a field non-nullable at the DB level without making it API-required
|
|
384
|
+
* - Explicitly mark a field as nullable even when it has isRequired validation
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```typescript
|
|
388
|
+
* // DB non-nullable, but API optional (relies on a default value or hook)
|
|
389
|
+
* fields: {
|
|
390
|
+
* phoneNumber: text({
|
|
391
|
+
* db: { isNullable: false }
|
|
392
|
+
* })
|
|
393
|
+
* // Generates: phoneNumber String (non-nullable)
|
|
394
|
+
*
|
|
395
|
+
* // DB nullable (explicit), regardless of validation
|
|
396
|
+
* lastMessagePreview: text({
|
|
397
|
+
* db: { isNullable: true }
|
|
398
|
+
* })
|
|
399
|
+
* // Generates: lastMessagePreview String? (nullable)
|
|
400
|
+
* }
|
|
401
|
+
* ```
|
|
402
|
+
*/
|
|
403
|
+
isNullable?: boolean
|
|
404
|
+
/**
|
|
405
|
+
* Override the native database type for the column.
|
|
406
|
+
* Generates a @db.<nativeType> attribute in the Prisma schema.
|
|
407
|
+
* The available types depend on your database provider.
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* ```typescript
|
|
411
|
+
* // PostgreSQL: use TEXT instead of VARCHAR
|
|
412
|
+
* fields: {
|
|
413
|
+
* description: text({ db: { nativeType: 'Text' } })
|
|
414
|
+
* // Generates: description String? @db.Text
|
|
415
|
+
*
|
|
416
|
+
* // PostgreSQL: use SMALLINT instead of INT
|
|
417
|
+
* count: integer({ db: { nativeType: 'SmallInt' } })
|
|
418
|
+
* // Generates: count Int? @db.SmallInt
|
|
419
|
+
* }
|
|
420
|
+
* ```
|
|
421
|
+
*/
|
|
422
|
+
nativeType?: string
|
|
377
423
|
}
|
|
378
424
|
ui?: {
|
|
379
425
|
/**
|
|
@@ -415,14 +461,21 @@ export type BaseFieldConfig<TTypeInfo extends TypeInfo> = {
|
|
|
415
461
|
* Get Prisma type and modifiers for schema generation
|
|
416
462
|
* @param fieldName - The name of the field (for generating modifiers)
|
|
417
463
|
* @param provider - Optional database provider ('sqlite', 'postgresql', 'mysql', etc.)
|
|
418
|
-
* @
|
|
464
|
+
* @param listName - Optional list name (used for generating enum type names)
|
|
465
|
+
* @returns Prisma type string, optional modifiers, and optional enum values
|
|
419
466
|
*/
|
|
420
467
|
getPrismaType?: (
|
|
421
468
|
fieldName: string,
|
|
422
469
|
provider?: string,
|
|
470
|
+
listName?: string,
|
|
423
471
|
) => {
|
|
424
472
|
type: string
|
|
425
473
|
modifiers?: string
|
|
474
|
+
/**
|
|
475
|
+
* If set, this field requires a Prisma enum definition with these values.
|
|
476
|
+
* The enum name is the value of `type`.
|
|
477
|
+
*/
|
|
478
|
+
enumValues?: string[]
|
|
426
479
|
}
|
|
427
480
|
/**
|
|
428
481
|
* Get TypeScript type information for type generation
|
|
@@ -465,37 +518,6 @@ export type TextField<TTypeInfo extends TypeInfo = TypeInfo> = BaseFieldConfig<T
|
|
|
465
518
|
}
|
|
466
519
|
}
|
|
467
520
|
isIndexed?: boolean | 'unique'
|
|
468
|
-
db?: {
|
|
469
|
-
map?: string
|
|
470
|
-
/**
|
|
471
|
-
* Prisma native database type attribute
|
|
472
|
-
* Allows overriding the default String type for the database provider
|
|
473
|
-
* @example
|
|
474
|
-
* ```typescript
|
|
475
|
-
* // PostgreSQL/MySQL
|
|
476
|
-
* fields: {
|
|
477
|
-
* description: text({ db: { nativeType: 'Text' } })
|
|
478
|
-
* // Generates: description String @db.Text
|
|
479
|
-
* }
|
|
480
|
-
* ```
|
|
481
|
-
*/
|
|
482
|
-
nativeType?: string
|
|
483
|
-
/**
|
|
484
|
-
* Controls nullability in the database schema
|
|
485
|
-
* When specified, overrides the default behavior (isRequired determines nullability)
|
|
486
|
-
* @example
|
|
487
|
-
* ```typescript
|
|
488
|
-
* fields: {
|
|
489
|
-
* description: text({
|
|
490
|
-
* validation: { isRequired: true },
|
|
491
|
-
* db: { isNullable: false }
|
|
492
|
-
* })
|
|
493
|
-
* // Generates: description String (non-nullable)
|
|
494
|
-
* }
|
|
495
|
-
* ```
|
|
496
|
-
*/
|
|
497
|
-
isNullable?: boolean
|
|
498
|
-
}
|
|
499
521
|
ui?: {
|
|
500
522
|
displayMode?: 'input' | 'textarea'
|
|
501
523
|
}
|
|
@@ -515,10 +537,6 @@ export type DecimalField<TTypeInfo extends TypeInfo = TypeInfo> = BaseFieldConfi
|
|
|
515
537
|
defaultValue?: string
|
|
516
538
|
precision?: number
|
|
517
539
|
scale?: number
|
|
518
|
-
db?: {
|
|
519
|
-
map?: string
|
|
520
|
-
isNullable?: boolean
|
|
521
|
-
}
|
|
522
540
|
validation?: {
|
|
523
541
|
isRequired?: boolean
|
|
524
542
|
min?: string
|
|
@@ -539,10 +557,6 @@ export type TimestampField<TTypeInfo extends TypeInfo = TypeInfo> = BaseFieldCon
|
|
|
539
557
|
export type CalendarDayField<TTypeInfo extends TypeInfo = TypeInfo> = BaseFieldConfig<TTypeInfo> & {
|
|
540
558
|
type: 'calendarDay'
|
|
541
559
|
defaultValue?: string
|
|
542
|
-
db?: {
|
|
543
|
-
map?: string
|
|
544
|
-
isNullable?: boolean
|
|
545
|
-
}
|
|
546
560
|
validation?: {
|
|
547
561
|
isRequired?: boolean
|
|
548
562
|
}
|
|
@@ -559,6 +573,21 @@ export type PasswordField<TTypeInfo extends TypeInfo = TypeInfo> = BaseFieldConf
|
|
|
559
573
|
export type SelectField<TTypeInfo extends TypeInfo = TypeInfo> = BaseFieldConfig<TTypeInfo> & {
|
|
560
574
|
type: 'select'
|
|
561
575
|
options: Array<{ label: string; value: string }>
|
|
576
|
+
defaultValue?: string
|
|
577
|
+
db?: {
|
|
578
|
+
/**
|
|
579
|
+
* Whether to store as a native database enum type.
|
|
580
|
+
* - 'string' (default): stores as a plain string/varchar column
|
|
581
|
+
* - 'enum': stores as a Prisma enum, generating a native enum type in the schema
|
|
582
|
+
*
|
|
583
|
+
* Note: enum values must be valid Prisma identifiers (letters, numbers, underscores,
|
|
584
|
+
* starting with a letter) when using 'enum' type.
|
|
585
|
+
*
|
|
586
|
+
* @default 'string'
|
|
587
|
+
*/
|
|
588
|
+
type?: 'string' | 'enum'
|
|
589
|
+
map?: string
|
|
590
|
+
}
|
|
562
591
|
validation?: {
|
|
563
592
|
isRequired?: boolean
|
|
564
593
|
}
|
package/src/context/index.ts
CHANGED
|
@@ -38,6 +38,16 @@ async function executeFieldResolveInputHooks(
|
|
|
38
38
|
item?: any,
|
|
39
39
|
): Promise<Record<string, unknown>> {
|
|
40
40
|
let result = { ...resolvedData }
|
|
41
|
+
console.log(
|
|
42
|
+
'Executing field resolveInput hooks for list:',
|
|
43
|
+
listKey,
|
|
44
|
+
'operation:',
|
|
45
|
+
operation,
|
|
46
|
+
'inputData:',
|
|
47
|
+
inputData,
|
|
48
|
+
'resolvedData before field hooks:',
|
|
49
|
+
resolvedData,
|
|
50
|
+
)
|
|
41
51
|
|
|
42
52
|
for (const [fieldKey, fieldConfig] of Object.entries(fields)) {
|
|
43
53
|
// Skip if field not in data
|
|
@@ -430,6 +440,7 @@ export function getContext<
|
|
|
430
440
|
},
|
|
431
441
|
plugins: {}, // Will be populated with plugin runtime services
|
|
432
442
|
_isSudo,
|
|
443
|
+
_resolveOutputCounter: { depth: 0 },
|
|
433
444
|
}
|
|
434
445
|
|
|
435
446
|
// Create access-controlled operations for each list
|
|
@@ -882,8 +893,10 @@ function createCreate<TPrisma extends PrismaClientLike>(
|
|
|
882
893
|
// Access Prisma model dynamically - required because model names are generated at runtime
|
|
883
894
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
884
895
|
const model = (prisma as any)[getDbKey(listName)]
|
|
896
|
+
// Singleton lists use Int @id with value always 1 (matching Keystone 6 behaviour)
|
|
897
|
+
const createData = isSingletonList(listConfig) ? { id: 1, ...data } : data
|
|
885
898
|
const item = await model.create({
|
|
886
|
-
data,
|
|
899
|
+
data: createData,
|
|
887
900
|
})
|
|
888
901
|
|
|
889
902
|
// 9. Execute list-level afterOperation hook
|