bunsane 0.1.2 → 0.1.3
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/TODO.md +1 -1
- package/bun.lock +156 -150
- package/core/App.ts +188 -31
- package/core/ArcheType.ts +1044 -26
- package/core/ComponentRegistry.ts +172 -29
- package/core/Components.ts +102 -24
- package/core/Decorators.ts +0 -1
- package/core/Entity.ts +55 -7
- package/core/EntityInterface.ts +4 -0
- package/core/EntityManager.ts +4 -4
- package/core/Query.ts +169 -3
- package/core/RequestLoaders.ts +101 -12
- package/core/SchedulerManager.ts +3 -4
- package/core/metadata/definitions/ArcheType.ts +9 -0
- package/core/metadata/definitions/Component.ts +16 -0
- package/core/metadata/definitions/gqlObject.ts +10 -0
- package/core/metadata/getMetadataStorage.ts +14 -0
- package/core/metadata/index.ts +17 -0
- package/core/metadata/metadata-storage.ts +81 -0
- package/database/DatabaseHelper.ts +22 -20
- package/database/sqlHelpers.ts +0 -2
- package/gql/ArchetypeOperations.ts +281 -0
- package/gql/Generator.ts +252 -62
- package/gql/helpers.ts +5 -5
- package/gql/index.ts +19 -17
- package/gql/types.ts +58 -11
- package/index.ts +93 -82
- package/package.json +39 -37
- package/plugins/index.ts +13 -0
- package/scheduler/index.ts +87 -0
- package/service/Service.ts +4 -0
- package/service/ServiceRegistry.ts +5 -1
- package/service/index.ts +1 -1
- package/swagger/decorators.ts +65 -0
- package/swagger/generator.ts +100 -0
- package/swagger/index.ts +2 -0
- package/tests/bench/insert.bench.ts +1 -0
- package/tests/bench/relations.bench.ts +1 -0
- package/tests/bench/sorting.bench.ts +1 -0
- package/tests/component-hooks-simple.test.ts +117 -0
- package/tests/component-hooks.test.ts +83 -31
- package/tests/component.test.ts +1 -0
- package/tests/hooks.test.ts +1 -0
- package/tests/query.test.ts +46 -4
- package/tests/relations.test.ts +1 -0
- package/types/app.types.ts +0 -0
- package/upload/index.ts +0 -2
- package/core/processors/ImageProcessor.ts +0 -423
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { getAllArchetypeSchemas, getArchetypeSchema } from "../core/ArcheType";
|
|
2
|
+
import { logger as MainLogger } from "../core/Logger";
|
|
3
|
+
|
|
4
|
+
const logger = MainLogger.child({ scope: "ArchetypeOperations" });
|
|
5
|
+
|
|
6
|
+
export interface ArchetypeOperationConfig {
|
|
7
|
+
enableQueries?: {
|
|
8
|
+
get?: boolean; // getArchetypeName(id: ID!)
|
|
9
|
+
list?: boolean; // listArchetypeNames(filter, limit, offset)
|
|
10
|
+
};
|
|
11
|
+
enableMutations?: {
|
|
12
|
+
create?: boolean; // createArchetypeName(input)
|
|
13
|
+
update?: boolean; // updateArchetypeName(id, input)
|
|
14
|
+
delete?: boolean; // deleteArchetypeName(id)
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate GraphQL Query and Mutation fields for archetypes
|
|
20
|
+
* This uses the cached archetype schemas to create CRUD operations
|
|
21
|
+
*/
|
|
22
|
+
export function generateArchetypeOperations(config: ArchetypeOperationConfig = {}) {
|
|
23
|
+
const {
|
|
24
|
+
enableQueries = { get: true, list: true },
|
|
25
|
+
enableMutations = { create: true, update: true, delete: true }
|
|
26
|
+
} = config;
|
|
27
|
+
|
|
28
|
+
const schemas = getAllArchetypeSchemas();
|
|
29
|
+
logger.trace(`getAllArchetypeSchemas returned ${schemas.length} schemas`);
|
|
30
|
+
|
|
31
|
+
let typeDefs = "\n# Auto-generated Archetype Types\n";
|
|
32
|
+
const queryFields: string[] = [];
|
|
33
|
+
const mutationFields: string[] = [];
|
|
34
|
+
const resolvers: any = { Query: {}, Mutation: {} };
|
|
35
|
+
|
|
36
|
+
// Track defined types to prevent duplicates
|
|
37
|
+
const definedTypes = new Set<string>();
|
|
38
|
+
|
|
39
|
+
schemas.forEach(({ zodSchema, graphqlSchema }) => {
|
|
40
|
+
// Extract archetype name from the schema
|
|
41
|
+
const archetypeName = extractArchetypeName(graphqlSchema);
|
|
42
|
+
if (!archetypeName) {
|
|
43
|
+
logger.warn(`Could not extract archetype name from schema: ${graphqlSchema.substring(0, 100)}`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
logger.trace(`Generating operations for archetype: ${archetypeName}`);
|
|
48
|
+
|
|
49
|
+
// Add the archetype type definition (without Query/Mutation)
|
|
50
|
+
// Extract and deduplicate type definitions
|
|
51
|
+
const typeDefinitions = extractTypeDefinitions(graphqlSchema);
|
|
52
|
+
const deduplicatedTypes = deduplicateTypeDefinitions(typeDefinitions, definedTypes);
|
|
53
|
+
logger.trace(`Adding ${deduplicatedTypes.length} characters of type definitions for ${archetypeName}`);
|
|
54
|
+
typeDefs += deduplicatedTypes;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
typeDefs += "\n# END AUTO-GENERATED TYPES\n";
|
|
58
|
+
logger.trace(`Final typeDefs length: ${typeDefs.length}`);
|
|
59
|
+
|
|
60
|
+
// Return types only, without operations
|
|
61
|
+
return { typeDefs, queryFields, mutationFields, resolvers };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* WIP
|
|
66
|
+
* Generate full archetype operations including types, queries, and mutations
|
|
67
|
+
*/
|
|
68
|
+
//TODO: Implement this
|
|
69
|
+
export function generateArchetypeOperationsWithCRUD(config: ArchetypeOperationConfig = {}) {
|
|
70
|
+
const {
|
|
71
|
+
enableQueries = { get: true, list: true },
|
|
72
|
+
enableMutations = { create: true, update: true, delete: true }
|
|
73
|
+
} = config;
|
|
74
|
+
|
|
75
|
+
const schemas = getAllArchetypeSchemas();
|
|
76
|
+
let typeDefs = "\n# Auto-generated Archetype Types\n";
|
|
77
|
+
const queryFields: string[] = [];
|
|
78
|
+
const mutationFields: string[] = [];
|
|
79
|
+
const resolvers: any = { Query: {}, Mutation: {} };
|
|
80
|
+
|
|
81
|
+
schemas.forEach(({ zodSchema, graphqlSchema }) => {
|
|
82
|
+
// Extract archetype name from the schema
|
|
83
|
+
const archetypeName = extractArchetypeName(graphqlSchema);
|
|
84
|
+
if (!archetypeName) return;
|
|
85
|
+
|
|
86
|
+
logger.trace(`Generating operations for archetype: ${archetypeName}`);
|
|
87
|
+
|
|
88
|
+
// Add the archetype type definition (without Query/Mutation)
|
|
89
|
+
typeDefs += extractTypeDefinitions(graphqlSchema);
|
|
90
|
+
|
|
91
|
+
// Generate filter input type
|
|
92
|
+
typeDefs += generateFilterInput(archetypeName, zodSchema);
|
|
93
|
+
|
|
94
|
+
// Generate create input type
|
|
95
|
+
typeDefs += generateCreateInput(archetypeName, zodSchema);
|
|
96
|
+
|
|
97
|
+
// Generate update input type
|
|
98
|
+
typeDefs += generateUpdateInput(archetypeName, zodSchema);
|
|
99
|
+
|
|
100
|
+
// Generate Query operations
|
|
101
|
+
if (enableQueries?.get) {
|
|
102
|
+
queryFields.push(`get${archetypeName}(id: ID!): ${archetypeName}`);
|
|
103
|
+
resolvers.Query[`get${archetypeName}`] = createGetResolver(archetypeName);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (enableQueries?.list) {
|
|
107
|
+
queryFields.push(`list${archetypeName}s(filter: ${archetypeName}Filter, limit: Int, offset: Int): [${archetypeName}!]!`);
|
|
108
|
+
resolvers.Query[`list${archetypeName}s`] = createListResolver(archetypeName);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Generate Mutation operations
|
|
112
|
+
if (enableMutations?.create) {
|
|
113
|
+
mutationFields.push(`create${archetypeName}(input: Create${archetypeName}Input!): ${archetypeName}!`);
|
|
114
|
+
resolvers.Mutation[`create${archetypeName}`] = createCreateResolver(archetypeName);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (enableMutations?.update) {
|
|
118
|
+
mutationFields.push(`update${archetypeName}(id: ID!, input: Update${archetypeName}Input!): ${archetypeName}!`);
|
|
119
|
+
resolvers.Mutation[`update${archetypeName}`] = createUpdateResolver(archetypeName);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (enableMutations?.delete) {
|
|
123
|
+
mutationFields.push(`delete${archetypeName}(id: ID!): Boolean!`);
|
|
124
|
+
resolvers.Mutation[`delete${archetypeName}`] = createDeleteResolver(archetypeName);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return { typeDefs, queryFields, mutationFields, resolvers };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function extractArchetypeName(graphqlSchema: string): string | null {
|
|
132
|
+
const match = graphqlSchema.match(/type (\w+) \{/);
|
|
133
|
+
return match ? match[1] ?? null : null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function extractTypeDefinitions(graphqlSchema: string): string {
|
|
137
|
+
// Remove Query and Mutation types, keep only object types and enums
|
|
138
|
+
const lines = graphqlSchema.split('\n');
|
|
139
|
+
const filtered = lines.filter(line => {
|
|
140
|
+
const trimmed = line.trim();
|
|
141
|
+
return !trimmed.startsWith('type Query') &&
|
|
142
|
+
!trimmed.startsWith('type Mutation') &&
|
|
143
|
+
!trimmed.startsWith('type Subscription');
|
|
144
|
+
});
|
|
145
|
+
return filtered.join('\n') + '\n';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Deduplicates type definitions by tracking which types have already been defined.
|
|
150
|
+
* Parses the type definitions and only returns new ones.
|
|
151
|
+
*/
|
|
152
|
+
function deduplicateTypeDefinitions(typeDefinitions: string, definedTypes: Set<string>): string {
|
|
153
|
+
const lines = typeDefinitions.split('\n');
|
|
154
|
+
const result: string[] = [];
|
|
155
|
+
let currentType = '';
|
|
156
|
+
let currentTypeName = '';
|
|
157
|
+
let inTypeDefinition = false;
|
|
158
|
+
|
|
159
|
+
for (const line of lines) {
|
|
160
|
+
const trimmed = line.trim();
|
|
161
|
+
|
|
162
|
+
// Check if this is the start of a type/enum/input definition
|
|
163
|
+
const typeMatch = trimmed.match(/^(type|enum|input)\s+(\w+)/);
|
|
164
|
+
|
|
165
|
+
if (typeMatch) {
|
|
166
|
+
// Save previous type if we were in one
|
|
167
|
+
if (inTypeDefinition && currentTypeName && !definedTypes.has(currentTypeName)) {
|
|
168
|
+
result.push(currentType);
|
|
169
|
+
definedTypes.add(currentTypeName);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Start new type
|
|
173
|
+
currentTypeName = typeMatch[2] || '';
|
|
174
|
+
currentType = line + '\n';
|
|
175
|
+
inTypeDefinition = true;
|
|
176
|
+
} else if (inTypeDefinition) {
|
|
177
|
+
currentType += line + '\n';
|
|
178
|
+
|
|
179
|
+
// Check if this is the closing brace
|
|
180
|
+
if (trimmed === '}') {
|
|
181
|
+
// End of type definition
|
|
182
|
+
if (!definedTypes.has(currentTypeName)) {
|
|
183
|
+
result.push(currentType);
|
|
184
|
+
definedTypes.add(currentTypeName);
|
|
185
|
+
logger.trace(`Added type definition: ${currentTypeName}`);
|
|
186
|
+
} else {
|
|
187
|
+
logger.trace(`Skipped duplicate type definition: ${currentTypeName}`);
|
|
188
|
+
}
|
|
189
|
+
currentType = '';
|
|
190
|
+
currentTypeName = '';
|
|
191
|
+
inTypeDefinition = false;
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
// Not in a type definition, just add the line (could be comments, etc.)
|
|
195
|
+
result.push(line + '\n');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Handle last type if file doesn't end with closing brace
|
|
200
|
+
if (inTypeDefinition && currentTypeName && !definedTypes.has(currentTypeName)) {
|
|
201
|
+
result.push(currentType);
|
|
202
|
+
definedTypes.add(currentTypeName);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return result.join('');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function generateFilterInput(archetypeName: string, zodSchema: any): string {
|
|
209
|
+
// Generate filter input with common filter operators
|
|
210
|
+
// Add a dummy field to make the input type valid until full implementation
|
|
211
|
+
return `
|
|
212
|
+
input ${archetypeName}Filter {
|
|
213
|
+
id: ID
|
|
214
|
+
_placeholder: String
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function generateCreateInput(archetypeName: string, zodSchema: any): string {
|
|
221
|
+
// Generate create input (all fields except id)
|
|
222
|
+
// Add a dummy field to make the input type valid until full implementation
|
|
223
|
+
return `
|
|
224
|
+
input Create${archetypeName}Input {
|
|
225
|
+
_placeholder: String
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
`;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function generateUpdateInput(archetypeName: string, zodSchema: any): string {
|
|
232
|
+
// Generate update input (all fields optional except id)
|
|
233
|
+
// Add a dummy field to make the input type valid until full implementation
|
|
234
|
+
return `
|
|
235
|
+
input Update${archetypeName}Input {
|
|
236
|
+
_placeholder: String
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
`;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Resolver creators
|
|
243
|
+
function createGetResolver(archetypeName: string) {
|
|
244
|
+
return async (_: any, { id }: { id: string }, context: any) => {
|
|
245
|
+
// TODO: Implement actual entity fetching
|
|
246
|
+
logger.trace(`Getting ${archetypeName} with id: ${id}`);
|
|
247
|
+
throw new Error(`get${archetypeName} resolver not implemented`);
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function createListResolver(archetypeName: string) {
|
|
252
|
+
return async (_: any, { filter, limit, offset }: any, context: any) => {
|
|
253
|
+
// TODO: Implement actual entity querying
|
|
254
|
+
logger.trace(`Listing ${archetypeName}s with filter:`, filter);
|
|
255
|
+
throw new Error(`list${archetypeName}s resolver not implemented`);
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function createCreateResolver(archetypeName: string) {
|
|
260
|
+
return async (_: any, { input }: any, context: any) => {
|
|
261
|
+
// TODO: Implement actual entity creation
|
|
262
|
+
logger.trace(`Creating ${archetypeName} with input:`, input);
|
|
263
|
+
throw new Error(`create${archetypeName} resolver not implemented`);
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function createUpdateResolver(archetypeName: string) {
|
|
268
|
+
return async (_: any, { id, input }: any, context: any) => {
|
|
269
|
+
// TODO: Implement actual entity update
|
|
270
|
+
logger.trace(`Updating ${archetypeName} ${id} with input:`, input);
|
|
271
|
+
throw new Error(`update${archetypeName} resolver not implemented`);
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function createDeleteResolver(archetypeName: string) {
|
|
276
|
+
return async (_: any, { id }: { id: string }, context: any) => {
|
|
277
|
+
// TODO: Implement actual entity deletion
|
|
278
|
+
logger.trace(`Deleting ${archetypeName} with id: ${id}`);
|
|
279
|
+
throw new Error(`delete${archetypeName} resolver not implemented`);
|
|
280
|
+
};
|
|
281
|
+
}
|