bunsane 0.1.4 → 0.2.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/.claude/settings.local.json +47 -0
- package/.claude/skills/update-memory.md +74 -0
- package/.prettierrc +4 -0
- package/.serena/memories/architectural-decision-no-dependency-injection.md +76 -0
- package/.serena/memories/architecture.md +154 -0
- package/.serena/memories/cache-interface-refactoring-2026-01-24.md +165 -0
- package/.serena/memories/code_style_and_conventions.md +76 -0
- package/.serena/memories/project_overview.md +43 -0
- package/.serena/memories/schema-dsl-plan.md +107 -0
- package/.serena/memories/suggested_commands.md +80 -0
- package/.serena/memories/typescript-compilation-status.md +54 -0
- package/.serena/project.yml +114 -0
- package/TODO.md +1 -7
- package/bun.lock +150 -4
- package/bunfig.toml +10 -0
- package/config/cache.config.ts +77 -0
- package/config/upload.config.ts +4 -5
- package/core/App.ts +870 -123
- package/core/ArcheType.ts +2268 -377
- package/core/BatchLoader.ts +181 -71
- package/core/Config.ts +153 -0
- package/core/Decorators.ts +4 -1
- package/core/Entity.ts +621 -92
- package/core/EntityHookManager.ts +1 -1
- package/core/EntityInterface.ts +3 -1
- package/core/EntityManager.ts +1 -13
- package/core/ErrorHandler.ts +8 -2
- package/core/Logger.ts +9 -0
- package/core/Middleware.ts +34 -0
- package/core/RequestContext.ts +5 -1
- package/core/RequestLoaders.ts +227 -93
- package/core/SchedulerManager.ts +193 -52
- package/core/cache/CacheAnalytics.ts +399 -0
- package/core/cache/CacheFactory.ts +145 -0
- package/core/cache/CacheManager.ts +520 -0
- package/core/cache/CacheProvider.ts +34 -0
- package/core/cache/CacheWarmer.ts +157 -0
- package/core/cache/CompressionUtils.ts +110 -0
- package/core/cache/MemoryCache.ts +251 -0
- package/core/cache/MultiLevelCache.ts +180 -0
- package/core/cache/NoOpCache.ts +53 -0
- package/core/cache/RedisCache.ts +464 -0
- package/core/cache/TTLStrategy.ts +254 -0
- package/core/cache/index.ts +6 -0
- package/core/components/BaseComponent.ts +120 -0
- package/core/{ComponentRegistry.ts → components/ComponentRegistry.ts} +148 -54
- package/core/components/Decorators.ts +88 -0
- package/core/components/Interfaces.ts +7 -0
- package/core/components/index.ts +5 -0
- package/core/decorators/EntityHooks.ts +0 -3
- package/core/decorators/IndexedField.ts +26 -0
- package/core/decorators/ScheduledTask.ts +0 -47
- package/core/events/EntityLifecycleEvents.ts +1 -1
- package/core/health.ts +112 -0
- package/core/metadata/definitions/ArcheType.ts +14 -0
- package/core/metadata/definitions/Component.ts +9 -0
- package/core/metadata/definitions/gqlObject.ts +1 -1
- package/core/metadata/index.ts +42 -1
- package/core/metadata/metadata-storage.ts +28 -2
- package/core/middleware/AccessLog.ts +59 -0
- package/core/middleware/RequestId.ts +38 -0
- package/core/middleware/SecurityHeaders.ts +62 -0
- package/core/middleware/index.ts +3 -0
- package/core/scheduler/DistributedLock.ts +266 -0
- package/core/scheduler/index.ts +15 -0
- package/core/validateEnv.ts +92 -0
- package/database/DatabaseHelper.ts +416 -40
- package/database/IndexingStrategy.ts +342 -0
- package/database/PreparedStatementCache.ts +226 -0
- package/database/index.ts +32 -7
- package/database/sqlHelpers.ts +14 -2
- package/endpoints/archetypes.ts +362 -0
- package/endpoints/components.ts +58 -0
- package/endpoints/entity.ts +80 -0
- package/endpoints/index.ts +27 -0
- package/endpoints/query.ts +93 -0
- package/endpoints/stats.ts +76 -0
- package/endpoints/tables.ts +212 -0
- package/endpoints/types.ts +155 -0
- package/gql/ArchetypeOperations.ts +32 -86
- package/gql/Generator.ts +27 -315
- package/gql/GeneratorV2.ts +37 -0
- package/gql/builders/InputTypeBuilder.ts +99 -0
- package/gql/builders/ResolverBuilder.ts +234 -0
- package/gql/builders/TypeDefBuilder.ts +105 -0
- package/gql/builders/index.ts +3 -0
- package/gql/decorators/Upload.ts +1 -1
- package/gql/depthLimit.ts +85 -0
- package/gql/graph/GraphNode.ts +224 -0
- package/gql/graph/SchemaGraph.ts +278 -0
- package/gql/helpers.ts +8 -2
- package/gql/index.ts +56 -4
- package/gql/middleware.ts +79 -0
- package/gql/orchestration/GraphQLSchemaOrchestrator.ts +241 -0
- package/gql/orchestration/index.ts +1 -0
- package/gql/scanner/ServiceScanner.ts +347 -0
- package/gql/schema/index.ts +458 -0
- package/gql/strategies/TypeGenerationStrategy.ts +329 -0
- package/gql/types.ts +1 -0
- package/gql/utils/TypeSignature.ts +220 -0
- package/gql/utils/index.ts +1 -0
- package/gql/visitors/ArchetypePreprocessorVisitor.ts +80 -0
- package/gql/visitors/DeduplicationVisitor.ts +82 -0
- package/gql/visitors/GraphVisitor.ts +78 -0
- package/gql/visitors/ResolverGeneratorVisitor.ts +122 -0
- package/gql/visitors/SchemaGeneratorVisitor.ts +851 -0
- package/gql/visitors/TypeCollectorVisitor.ts +79 -0
- package/gql/visitors/VisitorComposer.ts +96 -0
- package/gql/visitors/index.ts +7 -0
- package/package.json +59 -37
- package/plugins/index.ts +2 -2
- package/query/CTENode.ts +97 -0
- package/query/ComponentInclusionNode.ts +689 -0
- package/query/FilterBuilder.ts +127 -0
- package/query/FilterBuilderRegistry.ts +202 -0
- package/query/OrNode.ts +517 -0
- package/query/OrQuery.ts +42 -0
- package/query/Query.ts +1022 -0
- package/query/QueryContext.ts +170 -0
- package/query/QueryDAG.ts +122 -0
- package/query/QueryNode.ts +65 -0
- package/query/SourceNode.ts +53 -0
- package/query/builders/FullTextSearchBuilder.ts +236 -0
- package/query/index.ts +21 -0
- package/scheduler/index.ts +40 -8
- package/service/Service.ts +2 -1
- package/service/ServiceRegistry.ts +6 -5
- package/{core/storage → storage}/LocalStorageProvider.ts +2 -2
- package/storage/S3StorageProvider.ts +316 -0
- package/{core/storage → storage}/StorageProvider.ts +7 -3
- package/studio/bun.lock +482 -0
- package/studio/index.html +13 -0
- package/studio/package.json +39 -0
- package/studio/postcss.config.js +6 -0
- package/studio/src/components/DataTable.tsx +211 -0
- package/studio/src/components/Layout.tsx +13 -0
- package/studio/src/components/PageContainer.tsx +9 -0
- package/studio/src/components/PageHeader.tsx +13 -0
- package/studio/src/components/SearchBar.tsx +57 -0
- package/studio/src/components/Sidebar.tsx +294 -0
- package/studio/src/components/ui/button.tsx +56 -0
- package/studio/src/components/ui/checkbox.tsx +26 -0
- package/studio/src/components/ui/input.tsx +25 -0
- package/studio/src/hooks/useDataTable.ts +131 -0
- package/studio/src/index.css +36 -0
- package/studio/src/lib/api.ts +186 -0
- package/studio/src/lib/utils.ts +13 -0
- package/studio/src/main.tsx +17 -0
- package/studio/src/pages/ArcheType.tsx +239 -0
- package/studio/src/pages/Components.tsx +124 -0
- package/studio/src/pages/EntityInspector.tsx +302 -0
- package/studio/src/pages/QueryRunner.tsx +246 -0
- package/studio/src/pages/Table.tsx +94 -0
- package/studio/src/pages/Welcome.tsx +241 -0
- package/studio/src/routes.tsx +45 -0
- package/studio/src/store/archeTypeSettings.ts +30 -0
- package/studio/src/store/studio.ts +65 -0
- package/studio/src/utils/columnHelpers.tsx +114 -0
- package/studio/studio-instructions.md +81 -0
- package/studio/tailwind.config.js +77 -0
- package/studio/tsconfig.json +24 -0
- package/studio/utils.ts +54 -0
- package/studio/vite.config.js +19 -0
- package/swagger/generator.ts +1 -1
- package/tests/e2e/http.test.ts +126 -0
- package/tests/fixtures/archetypes/TestUserArchetype.ts +21 -0
- package/tests/fixtures/components/TestOrder.ts +23 -0
- package/tests/fixtures/components/TestProduct.ts +23 -0
- package/tests/fixtures/components/TestUser.ts +20 -0
- package/tests/fixtures/components/index.ts +6 -0
- package/tests/graphql/SchemaGeneration.test.ts +90 -0
- package/tests/graphql/builders/ResolverBuilder.test.ts +223 -0
- package/tests/graphql/builders/TypeDefBuilder.test.ts +153 -0
- package/tests/integration/archetype/ArcheType.persistence.test.ts +241 -0
- package/tests/integration/cache/CacheInvalidation.test.ts +259 -0
- package/tests/integration/entity/Entity.persistence.test.ts +333 -0
- package/tests/integration/query/Query.exec.test.ts +523 -0
- package/tests/pglite-setup.ts +61 -0
- package/tests/setup.ts +164 -0
- package/tests/stress/BenchmarkRunner.ts +203 -0
- package/tests/stress/DataSeeder.ts +190 -0
- package/tests/stress/StressTestReporter.ts +229 -0
- package/tests/stress/cursor-perf-test.ts +171 -0
- package/tests/stress/fixtures/StressTestComponents.ts +58 -0
- package/tests/stress/index.ts +7 -0
- package/tests/stress/scenarios/query-benchmarks.test.ts +285 -0
- package/tests/unit/BatchLoader.test.ts +82 -0
- package/tests/unit/archetype/ArcheType.test.ts +107 -0
- package/tests/unit/cache/CacheManager.test.ts +347 -0
- package/tests/unit/cache/MemoryCache.test.ts +260 -0
- package/tests/unit/cache/RedisCache.test.ts +411 -0
- package/tests/unit/entity/Entity.components.test.ts +244 -0
- package/tests/unit/entity/Entity.test.ts +345 -0
- package/tests/unit/gql/depthLimit.test.ts +203 -0
- package/tests/unit/gql/operationMiddleware.test.ts +293 -0
- package/tests/unit/health/Health.test.ts +129 -0
- package/tests/unit/middleware/AccessLog.test.ts +37 -0
- package/tests/unit/middleware/Middleware.test.ts +98 -0
- package/tests/unit/middleware/RequestId.test.ts +54 -0
- package/tests/unit/middleware/SecurityHeaders.test.ts +66 -0
- package/tests/unit/query/FilterBuilder.test.ts +111 -0
- package/tests/unit/query/Query.test.ts +308 -0
- package/tests/unit/scheduler/DistributedLock.test.ts +274 -0
- package/tests/unit/schema/schema-integration.test.ts +426 -0
- package/tests/unit/schema/schema.test.ts +580 -0
- package/tests/unit/storage/S3StorageProvider.test.ts +571 -0
- package/tests/unit/upload/RestUpload.test.ts +267 -0
- package/tests/unit/validateEnv.test.ts +82 -0
- package/tests/utils/entity-tracker.ts +57 -0
- package/tests/utils/index.ts +13 -0
- package/tests/utils/test-context.ts +149 -0
- package/tsconfig.json +5 -1
- package/types/archetype.types.ts +6 -0
- package/types/hooks.types.ts +1 -1
- package/types/query.types.ts +110 -0
- package/types/scheduler.types.ts +68 -7
- package/types/upload.types.ts +1 -0
- package/{core → upload}/FileValidator.ts +10 -1
- package/upload/RestUpload.ts +130 -0
- package/{core/components → upload}/UploadComponent.ts +11 -11
- package/{core → upload}/UploadManager.ts +3 -3
- package/upload/index.ts +23 -7
- package/utils/UploadHelper.ts +27 -6
- package/utils/cronParser.ts +16 -6
- package/.github/workflows/deploy-docs.yml +0 -57
- package/core/Components.ts +0 -202
- package/core/EntityCache.ts +0 -15
- package/core/Query.ts +0 -880
- package/docs/README.md +0 -149
- package/docs/_coverpage.md +0 -36
- package/docs/_sidebar.md +0 -23
- package/docs/api/core.md +0 -568
- package/docs/api/hooks.md +0 -554
- package/docs/api/index.md +0 -222
- package/docs/api/query.md +0 -678
- package/docs/api/service.md +0 -744
- package/docs/core-concepts/archetypes.md +0 -512
- package/docs/core-concepts/components.md +0 -498
- package/docs/core-concepts/entity.md +0 -314
- package/docs/core-concepts/hooks.md +0 -683
- package/docs/core-concepts/query.md +0 -588
- package/docs/core-concepts/services.md +0 -647
- package/docs/examples/code-examples.md +0 -425
- package/docs/getting-started.md +0 -337
- package/docs/index.html +0 -97
- package/tests/bench/insert.bench.ts +0 -60
- package/tests/bench/relations.bench.ts +0 -270
- package/tests/bench/sorting.bench.ts +0 -416
- package/tests/component-hooks-simple.test.ts +0 -117
- package/tests/component-hooks.test.ts +0 -1461
- package/tests/component.test.ts +0 -339
- package/tests/errorHandling.test.ts +0 -155
- package/tests/hooks.test.ts +0 -667
- package/tests/query-sorting.test.ts +0 -101
- package/tests/query.test.ts +0 -81
- package/tests/relations.test.ts +0 -170
- package/tests/scheduler.test.ts +0 -724
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import db from "../database";
|
|
2
|
+
import type {
|
|
3
|
+
StudioTableQueryParams,
|
|
4
|
+
StudioTableResponse,
|
|
5
|
+
DeleteTableRowsRequest,
|
|
6
|
+
DeleteResponse,
|
|
7
|
+
TableColumn,
|
|
8
|
+
TableRowData,
|
|
9
|
+
} from "./types";
|
|
10
|
+
|
|
11
|
+
export async function handleStudioTableRequest(
|
|
12
|
+
tableName: string,
|
|
13
|
+
params: StudioTableQueryParams = {}
|
|
14
|
+
): Promise<Response> {
|
|
15
|
+
const limit = Math.min(Math.max(params.limit ?? 50, 1), 1000);
|
|
16
|
+
const offset = Math.max(params.offset ?? 0, 0);
|
|
17
|
+
const searchTerm = params.search ?? "";
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const columnsResult = await db`
|
|
21
|
+
SELECT
|
|
22
|
+
column_name,
|
|
23
|
+
data_type,
|
|
24
|
+
is_nullable,
|
|
25
|
+
column_default
|
|
26
|
+
FROM information_schema.columns
|
|
27
|
+
WHERE table_name = ${tableName}
|
|
28
|
+
AND table_schema = 'public'
|
|
29
|
+
ORDER BY ordinal_position
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
if (columnsResult.length === 0) {
|
|
33
|
+
return new Response(
|
|
34
|
+
JSON.stringify({ error: `Table '${tableName}' not found` }),
|
|
35
|
+
{
|
|
36
|
+
status: 404,
|
|
37
|
+
headers: { "Content-Type": "application/json" },
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const primaryKeyResult = await db`
|
|
43
|
+
SELECT kcu.column_name
|
|
44
|
+
FROM information_schema.table_constraints tc
|
|
45
|
+
JOIN information_schema.key_column_usage kcu
|
|
46
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
47
|
+
AND tc.table_schema = kcu.table_schema
|
|
48
|
+
WHERE tc.constraint_type = 'PRIMARY KEY'
|
|
49
|
+
AND tc.table_name = ${tableName}
|
|
50
|
+
AND tc.table_schema = 'public'
|
|
51
|
+
`;
|
|
52
|
+
const primaryKeyColumns = new Set(
|
|
53
|
+
primaryKeyResult.map((row: { column_name: string }) => row.column_name)
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const columns: TableColumn[] = columnsResult.map((col: {
|
|
57
|
+
column_name: string;
|
|
58
|
+
data_type: string;
|
|
59
|
+
is_nullable: string;
|
|
60
|
+
}) => ({
|
|
61
|
+
name: col.column_name,
|
|
62
|
+
type: col.data_type,
|
|
63
|
+
nullable: col.is_nullable === "YES",
|
|
64
|
+
primary: primaryKeyColumns.has(col.column_name),
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
const textColumns = columnsResult
|
|
68
|
+
.filter((col: { data_type: string }) =>
|
|
69
|
+
["character varying", "text", "varchar", "char", "uuid"].includes(col.data_type)
|
|
70
|
+
)
|
|
71
|
+
.map((col: { column_name: string }) => col.column_name);
|
|
72
|
+
|
|
73
|
+
let rows: TableRowData[];
|
|
74
|
+
let totalResult: { count: number }[];
|
|
75
|
+
|
|
76
|
+
if (searchTerm && textColumns.length > 0) {
|
|
77
|
+
const searchPattern = `%${searchTerm}%`;
|
|
78
|
+
const searchConditions = textColumns
|
|
79
|
+
.map((col: string) => `"${col}"::text ILIKE $1`)
|
|
80
|
+
.join(" OR ");
|
|
81
|
+
|
|
82
|
+
rows = await db.unsafe(
|
|
83
|
+
`SELECT * FROM "${tableName}"
|
|
84
|
+
WHERE ${searchConditions}
|
|
85
|
+
ORDER BY created_at DESC NULLS LAST
|
|
86
|
+
LIMIT $2 OFFSET $3`,
|
|
87
|
+
[searchPattern, limit, offset]
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
totalResult = await db.unsafe(
|
|
91
|
+
`SELECT COUNT(*) as count FROM "${tableName}" WHERE ${searchConditions}`,
|
|
92
|
+
[searchPattern]
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
rows = await db.unsafe(
|
|
96
|
+
`SELECT * FROM "${tableName}"
|
|
97
|
+
ORDER BY created_at DESC NULLS LAST
|
|
98
|
+
LIMIT $1 OFFSET $2`,
|
|
99
|
+
[limit, offset]
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
totalResult = await db.unsafe(
|
|
103
|
+
`SELECT COUNT(*) as count FROM "${tableName}"`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const total = Number(totalResult[0]?.count ?? 0);
|
|
108
|
+
|
|
109
|
+
const responseData: StudioTableResponse = {
|
|
110
|
+
name: tableName,
|
|
111
|
+
columns,
|
|
112
|
+
rows,
|
|
113
|
+
total,
|
|
114
|
+
limit,
|
|
115
|
+
offset,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
return new Response(JSON.stringify(responseData), {
|
|
119
|
+
headers: { "Content-Type": "application/json" },
|
|
120
|
+
});
|
|
121
|
+
} catch (error) {
|
|
122
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
123
|
+
return new Response(
|
|
124
|
+
JSON.stringify({ error: `Failed to fetch table data: ${errorMessage}` }),
|
|
125
|
+
{
|
|
126
|
+
status: 500,
|
|
127
|
+
headers: { "Content-Type": "application/json" },
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export async function handleStudioTableDeleteRequest(
|
|
134
|
+
tableName: string,
|
|
135
|
+
requestBody: DeleteTableRowsRequest
|
|
136
|
+
): Promise<Response> {
|
|
137
|
+
const { ids } = requestBody;
|
|
138
|
+
|
|
139
|
+
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
|
140
|
+
return new Response(
|
|
141
|
+
JSON.stringify({ error: "ids array is required and must not be empty" }),
|
|
142
|
+
{
|
|
143
|
+
status: 400,
|
|
144
|
+
headers: { "Content-Type": "application/json" },
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const idPlaceholders = ids.map((_, index) => `$${index + 1}`).join(", ");
|
|
151
|
+
|
|
152
|
+
await db.unsafe(
|
|
153
|
+
`DELETE FROM "${tableName}" WHERE id IN (${idPlaceholders})`,
|
|
154
|
+
ids
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const deletedCount = ids.length;
|
|
158
|
+
|
|
159
|
+
const responseData: DeleteResponse = {
|
|
160
|
+
success: true,
|
|
161
|
+
deletedCount,
|
|
162
|
+
message: `Successfully deleted ${deletedCount} row(s) from ${tableName}`,
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
return new Response(JSON.stringify(responseData), {
|
|
166
|
+
headers: { "Content-Type": "application/json" },
|
|
167
|
+
});
|
|
168
|
+
} catch (error) {
|
|
169
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
170
|
+
return new Response(
|
|
171
|
+
JSON.stringify({ error: `Failed to delete rows: ${errorMessage}` }),
|
|
172
|
+
{
|
|
173
|
+
status: 500,
|
|
174
|
+
headers: { "Content-Type": "application/json" },
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export async function handleGetTables(): Promise<Response> {
|
|
181
|
+
try {
|
|
182
|
+
// Fetch all tables except ECS tables
|
|
183
|
+
const ecsTables = ['components', 'entities', 'entity_components', 'spatial_ref_sys'];
|
|
184
|
+
const ecsTablePlaceholders = ecsTables.map((_, index) => `$${index + 1}`).join(", ");
|
|
185
|
+
|
|
186
|
+
const result = await db.unsafe(
|
|
187
|
+
`SELECT table_name
|
|
188
|
+
FROM information_schema.tables
|
|
189
|
+
WHERE table_schema = 'public'
|
|
190
|
+
AND table_type = 'BASE TABLE'
|
|
191
|
+
AND table_name NOT IN (${ecsTablePlaceholders})
|
|
192
|
+
AND table_name NOT LIKE 'components_%'
|
|
193
|
+
ORDER BY table_name`,
|
|
194
|
+
ecsTables
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
const tables = result.map((row: { table_name: string }) => row.table_name);
|
|
198
|
+
|
|
199
|
+
return new Response(JSON.stringify({ tables }), {
|
|
200
|
+
headers: { "Content-Type": "application/json" },
|
|
201
|
+
});
|
|
202
|
+
} catch (error) {
|
|
203
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
204
|
+
return new Response(
|
|
205
|
+
JSON.stringify({ error: `Failed to fetch tables: ${errorMessage}` }),
|
|
206
|
+
{
|
|
207
|
+
status: 500,
|
|
208
|
+
headers: { "Content-Type": "application/json" },
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
interface StudioTableQueryParams {
|
|
2
|
+
limit?: number;
|
|
3
|
+
offset?: number;
|
|
4
|
+
search?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
interface StudioArcheTypeQueryParams {
|
|
8
|
+
limit?: number;
|
|
9
|
+
offset?: number;
|
|
10
|
+
search?: string;
|
|
11
|
+
include_deleted?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface TableColumn {
|
|
15
|
+
name: string;
|
|
16
|
+
type: string;
|
|
17
|
+
nullable: boolean;
|
|
18
|
+
primary: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface TableRowData {
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface StudioTableResponse {
|
|
26
|
+
name: string;
|
|
27
|
+
columns: TableColumn[];
|
|
28
|
+
rows: TableRowData[];
|
|
29
|
+
total: number;
|
|
30
|
+
limit: number;
|
|
31
|
+
offset: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface ArcheTypeField {
|
|
35
|
+
fieldName: string;
|
|
36
|
+
componentName: string;
|
|
37
|
+
fieldLabel: string;
|
|
38
|
+
nullable?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface ArcheTypeEntityRecord {
|
|
42
|
+
entityId: string;
|
|
43
|
+
components: Record<string, unknown>;
|
|
44
|
+
deleted_at?: string | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface StudioArcheTypeResponse {
|
|
48
|
+
name: string;
|
|
49
|
+
fields: ArcheTypeField[];
|
|
50
|
+
indicatorComponent: string | null;
|
|
51
|
+
entities: ArcheTypeEntityRecord[];
|
|
52
|
+
total: number;
|
|
53
|
+
limit: number;
|
|
54
|
+
offset: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface DeleteTableRowsRequest {
|
|
58
|
+
ids: string[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface DeleteArcheTypeEntitiesRequest {
|
|
62
|
+
entityIds: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface DeleteResponse {
|
|
66
|
+
success: boolean;
|
|
67
|
+
deletedCount: number;
|
|
68
|
+
message: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface EntityComponent {
|
|
72
|
+
id: string;
|
|
73
|
+
name: string;
|
|
74
|
+
type_id: string;
|
|
75
|
+
data: unknown;
|
|
76
|
+
created_at: string;
|
|
77
|
+
updated_at: string;
|
|
78
|
+
deleted_at: string | null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface EntityInspectorResponse {
|
|
82
|
+
entity: {
|
|
83
|
+
id: string;
|
|
84
|
+
created_at: string;
|
|
85
|
+
updated_at: string;
|
|
86
|
+
deleted_at: string | null;
|
|
87
|
+
};
|
|
88
|
+
components: EntityComponent[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface ComponentTypeStats {
|
|
92
|
+
name: string;
|
|
93
|
+
count: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface ArcheTypeStats {
|
|
97
|
+
name: string;
|
|
98
|
+
entityCount: number;
|
|
99
|
+
componentCount: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
interface StudioStatsResponse {
|
|
103
|
+
entities: {
|
|
104
|
+
active: number;
|
|
105
|
+
deleted: number;
|
|
106
|
+
total: number;
|
|
107
|
+
};
|
|
108
|
+
componentTypes: ComponentTypeStats[];
|
|
109
|
+
archetypes: ArcheTypeStats[];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
interface ComponentTypeInfo {
|
|
113
|
+
name: string;
|
|
114
|
+
entityCount: number;
|
|
115
|
+
partitionTable: string;
|
|
116
|
+
fields: string[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
interface StudioComponentsResponse {
|
|
120
|
+
components: ComponentTypeInfo[];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
interface StudioQueryRequest {
|
|
124
|
+
sql: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
interface StudioQueryResponse {
|
|
128
|
+
columns: string[];
|
|
129
|
+
rows: Record<string, unknown>[];
|
|
130
|
+
rowCount: number;
|
|
131
|
+
duration: number;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export type {
|
|
135
|
+
StudioTableQueryParams,
|
|
136
|
+
StudioArcheTypeQueryParams,
|
|
137
|
+
TableColumn,
|
|
138
|
+
TableRowData,
|
|
139
|
+
StudioTableResponse,
|
|
140
|
+
ArcheTypeField,
|
|
141
|
+
ArcheTypeEntityRecord,
|
|
142
|
+
StudioArcheTypeResponse,
|
|
143
|
+
DeleteTableRowsRequest,
|
|
144
|
+
DeleteArcheTypeEntitiesRequest,
|
|
145
|
+
DeleteResponse,
|
|
146
|
+
EntityComponent,
|
|
147
|
+
EntityInspectorResponse,
|
|
148
|
+
ComponentTypeStats,
|
|
149
|
+
ArcheTypeStats,
|
|
150
|
+
StudioStatsResponse,
|
|
151
|
+
ComponentTypeInfo,
|
|
152
|
+
StudioComponentsResponse,
|
|
153
|
+
StudioQueryRequest,
|
|
154
|
+
StudioQueryResponse,
|
|
155
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getAllArchetypeSchemas, getArchetypeSchema } from "../core/ArcheType";
|
|
1
|
+
import { getAllArchetypeSchemas, getArchetypeSchema, weaveAllArchetypes } from "../core/ArcheType";
|
|
2
2
|
import { logger as MainLogger } from "../core/Logger";
|
|
3
3
|
|
|
4
4
|
const logger = MainLogger.child({ scope: "ArchetypeOperations" });
|
|
@@ -25,9 +25,6 @@ export function generateArchetypeOperations(config: ArchetypeOperationConfig = {
|
|
|
25
25
|
enableMutations = { create: true, update: true, delete: true }
|
|
26
26
|
} = config;
|
|
27
27
|
|
|
28
|
-
const schemas = getAllArchetypeSchemas();
|
|
29
|
-
logger.trace(`getAllArchetypeSchemas returned ${schemas.length} schemas`);
|
|
30
|
-
|
|
31
28
|
let typeDefs = "\n# Auto-generated Archetype Types\n";
|
|
32
29
|
const queryFields: string[] = [];
|
|
33
30
|
const mutationFields: string[] = [];
|
|
@@ -36,23 +33,39 @@ export function generateArchetypeOperations(config: ArchetypeOperationConfig = {
|
|
|
36
33
|
// Track defined types to prevent duplicates
|
|
37
34
|
const definedTypes = new Set<string>();
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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);
|
|
36
|
+
// Get the full weaved schema that includes all archetypes and their relations
|
|
37
|
+
const fullSchema = weaveAllArchetypes();
|
|
38
|
+
if (fullSchema) {
|
|
39
|
+
logger.trace(`Using full weaved schema for type definitions`);
|
|
40
|
+
// Extract and deduplicate type definitions from the full schema
|
|
41
|
+
const typeDefinitions = extractTypeDefinitions(fullSchema);
|
|
52
42
|
const deduplicatedTypes = deduplicateTypeDefinitions(typeDefinitions, definedTypes);
|
|
53
|
-
logger.trace(`Adding ${deduplicatedTypes.length} characters of type definitions
|
|
43
|
+
logger.trace(`Adding ${deduplicatedTypes.length} characters of type definitions`);
|
|
54
44
|
typeDefs += deduplicatedTypes;
|
|
55
|
-
}
|
|
45
|
+
} else {
|
|
46
|
+
logger.warn(`No full schema available, falling back to individual schemas`);
|
|
47
|
+
// Fallback to individual schemas if weaving fails
|
|
48
|
+
const schemas = getAllArchetypeSchemas();
|
|
49
|
+
logger.trace(`getAllArchetypeSchemas returned ${schemas.length} schemas`);
|
|
50
|
+
|
|
51
|
+
schemas.forEach(({ zodSchema, graphqlSchema }) => {
|
|
52
|
+
// Extract archetype name from the schema
|
|
53
|
+
const archetypeName = extractArchetypeName(graphqlSchema);
|
|
54
|
+
if (!archetypeName) {
|
|
55
|
+
logger.warn(`Could not extract archetype name from schema: ${graphqlSchema.substring(0, 100)}`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
logger.trace(`Generating operations for archetype: ${archetypeName}`);
|
|
60
|
+
|
|
61
|
+
// Add the archetype type definition (without Query/Mutation)
|
|
62
|
+
// Extract and deduplicate type definitions
|
|
63
|
+
const typeDefinitions = extractTypeDefinitions(graphqlSchema);
|
|
64
|
+
const deduplicatedTypes = deduplicateTypeDefinitions(typeDefinitions, definedTypes);
|
|
65
|
+
logger.trace(`Adding ${deduplicatedTypes.length} characters of type definitions for ${archetypeName}`);
|
|
66
|
+
typeDefs += deduplicatedTypes;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
56
69
|
|
|
57
70
|
typeDefs += "\n# END AUTO-GENERATED TYPES\n";
|
|
58
71
|
logger.trace(`Final typeDefs length: ${typeDefs.length}`);
|
|
@@ -61,73 +74,6 @@ export function generateArchetypeOperations(config: ArchetypeOperationConfig = {
|
|
|
61
74
|
return { typeDefs, queryFields, mutationFields, resolvers };
|
|
62
75
|
}
|
|
63
76
|
|
|
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
77
|
function extractArchetypeName(graphqlSchema: string): string | null {
|
|
132
78
|
const match = graphqlSchema.match(/type (\w+) \{/);
|
|
133
79
|
return match ? match[1] ?? null : null;
|