bunsane 0.3.1 → 0.4.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.
Files changed (224) hide show
  1. package/CHANGELOG.md +445 -318
  2. package/config/cache.config.ts +35 -1
  3. package/core/App.ts +24 -1064
  4. package/core/ArcheType.ts +78 -2110
  5. package/core/BatchLoader.ts +56 -32
  6. package/core/Entity.ts +85 -1043
  7. package/core/EntityHookManager.ts +52 -754
  8. package/core/Logger.ts +10 -0
  9. package/core/RequestContext.ts +64 -6
  10. package/core/RequestLoaders.ts +187 -36
  11. package/core/SchedulerManager.ts +28 -600
  12. package/core/app/bootstrap.ts +133 -0
  13. package/core/app/cors.ts +85 -0
  14. package/core/app/graphqlSetup.ts +56 -0
  15. package/core/app/healthEndpoints.ts +31 -0
  16. package/core/app/metricsCollector.ts +27 -0
  17. package/core/app/preparedStatementWarmup.ts +15 -0
  18. package/core/app/processHandlers.ts +43 -0
  19. package/core/app/requestRouter.ts +310 -0
  20. package/core/app/restRegistry.ts +80 -0
  21. package/core/app/shutdown.ts +97 -0
  22. package/core/app/studioRouter.ts +83 -0
  23. package/core/archetype/customTypes.ts +100 -0
  24. package/core/archetype/decorators.ts +171 -0
  25. package/core/archetype/fieldResolvers.ts +666 -0
  26. package/core/archetype/helpers.ts +29 -0
  27. package/core/archetype/relationLoader.ts +161 -0
  28. package/core/archetype/schemaBuilder.ts +141 -0
  29. package/core/archetype/weaver.ts +218 -0
  30. package/core/archetype/zodSchemaBuilder.ts +527 -0
  31. package/core/cache/CacheManager.ts +173 -267
  32. package/core/cache/CompressionUtils.ts +34 -3
  33. package/core/cache/MemoryCache.ts +40 -37
  34. package/core/cache/RedisCache.ts +4 -4
  35. package/core/cache/health.ts +30 -0
  36. package/core/cache/invalidation.ts +96 -0
  37. package/core/cache/strategies/writeInvalidate.ts +111 -0
  38. package/core/cache/strategies/writeThrough.ts +233 -0
  39. package/core/components/BaseComponent.ts +16 -8
  40. package/core/components/ComponentRegistry.ts +28 -0
  41. package/core/decorators/IndexedField.ts +1 -1
  42. package/core/entity/cacheStrategies.ts +97 -0
  43. package/core/entity/componentAccess.ts +364 -0
  44. package/core/entity/finders.ts +202 -0
  45. package/core/entity/pendingOps.ts +72 -0
  46. package/core/entity/saveEntity.ts +377 -0
  47. package/core/hooks/dispatcher.ts +439 -0
  48. package/core/hooks/guards.ts +155 -0
  49. package/core/hooks/registry.ts +247 -0
  50. package/core/metadata/definitions/Component.ts +1 -1
  51. package/core/metadata/index.ts +15 -4
  52. package/core/middleware/AccessLog.ts +8 -1
  53. package/core/middleware/RateLimit.ts +102 -105
  54. package/core/middleware/RequestId.ts +2 -9
  55. package/core/middleware/SecurityHeaders.ts +2 -11
  56. package/core/middleware/headers.ts +28 -0
  57. package/core/remote/OutboxWorker.ts +213 -183
  58. package/core/remote/RemoteManager.ts +401 -400
  59. package/core/remote/types.ts +153 -151
  60. package/core/requestScope.ts +34 -0
  61. package/core/scheduler/cronEvaluator.ts +174 -0
  62. package/core/scheduler/lifecycleHooks.ts +21 -0
  63. package/core/scheduler/lockCoordinator.ts +27 -0
  64. package/core/scheduler/metrics.ts +14 -0
  65. package/core/scheduler/taskRunner.ts +420 -0
  66. package/database/DatabaseHelper.ts +128 -101
  67. package/database/IndexingStrategy.ts +72 -2
  68. package/database/PreparedStatementCache.ts +20 -5
  69. package/database/cancellable.ts +35 -0
  70. package/database/index.ts +15 -3
  71. package/database/instrumentedDb.ts +141 -0
  72. package/endpoints/archetypes.ts +2 -8
  73. package/endpoints/tables.ts +6 -1
  74. package/gql/index.ts +1 -1
  75. package/gql/visitors/ResolverGeneratorVisitor.ts +25 -4
  76. package/package.json +22 -1
  77. package/query/CTENode.ts +5 -3
  78. package/query/ComponentInclusionNode.ts +240 -13
  79. package/query/OrNode.ts +6 -5
  80. package/query/Query.ts +203 -59
  81. package/query/QueryContext.ts +6 -0
  82. package/query/QueryDAG.ts +7 -2
  83. package/query/membershipSource.ts +66 -0
  84. package/storage/LocalStorageProvider.ts +8 -3
  85. package/studio/dist/assets/index-BMZ67Npg.js +254 -0
  86. package/studio/dist/assets/index-BpbuYz9g.css +1 -0
  87. package/studio/{index.html → dist/index.html} +3 -2
  88. package/swagger/generator.ts +11 -1
  89. package/upload/UploadManager.ts +8 -6
  90. package/utils/uuid.ts +40 -10
  91. package/.claude/settings.local.json +0 -47
  92. package/.prettierrc +0 -4
  93. package/.serena/memories/architectural-decision-no-dependency-injection.md +0 -76
  94. package/.serena/memories/architecture.md +0 -154
  95. package/.serena/memories/cache-interface-refactoring-2026-01-24.md +0 -165
  96. package/.serena/memories/code_style_and_conventions.md +0 -76
  97. package/.serena/memories/project_overview.md +0 -43
  98. package/.serena/memories/schema-dsl-plan.md +0 -107
  99. package/.serena/memories/suggested_commands.md +0 -80
  100. package/.serena/memories/typescript-compilation-status.md +0 -54
  101. package/.serena/project.yml +0 -114
  102. package/BunSane.jpg +0 -0
  103. package/CLAUDE.md +0 -198
  104. package/TODO.md +0 -2
  105. package/bun.lock +0 -302
  106. package/bunfig.toml +0 -10
  107. package/docs/SCALABILITY_PLAN.md +0 -175
  108. package/studio/bun.lock +0 -482
  109. package/studio/package.json +0 -39
  110. package/studio/postcss.config.js +0 -6
  111. package/studio/src/components/DataTable.tsx +0 -211
  112. package/studio/src/components/Layout.tsx +0 -13
  113. package/studio/src/components/PageContainer.tsx +0 -9
  114. package/studio/src/components/PageHeader.tsx +0 -13
  115. package/studio/src/components/SearchBar.tsx +0 -57
  116. package/studio/src/components/Sidebar.tsx +0 -294
  117. package/studio/src/components/ui/button.tsx +0 -56
  118. package/studio/src/components/ui/checkbox.tsx +0 -26
  119. package/studio/src/components/ui/input.tsx +0 -25
  120. package/studio/src/hooks/useDataTable.ts +0 -131
  121. package/studio/src/index.css +0 -36
  122. package/studio/src/lib/api.ts +0 -186
  123. package/studio/src/lib/utils.ts +0 -13
  124. package/studio/src/main.tsx +0 -17
  125. package/studio/src/pages/ArcheType.tsx +0 -239
  126. package/studio/src/pages/Components.tsx +0 -124
  127. package/studio/src/pages/EntityInspector.tsx +0 -302
  128. package/studio/src/pages/QueryRunner.tsx +0 -246
  129. package/studio/src/pages/Table.tsx +0 -94
  130. package/studio/src/pages/Welcome.tsx +0 -241
  131. package/studio/src/routes.tsx +0 -45
  132. package/studio/src/store/archeTypeSettings.ts +0 -30
  133. package/studio/src/store/studio.ts +0 -65
  134. package/studio/src/utils/columnHelpers.tsx +0 -114
  135. package/studio/studio-instructions.md +0 -81
  136. package/studio/tailwind.config.js +0 -77
  137. package/studio/utils.ts +0 -54
  138. package/studio/vite.config.js +0 -19
  139. package/tests/benchmark/BENCHMARK_DATABASES_PLAN.md +0 -338
  140. package/tests/benchmark/bunfig.toml +0 -9
  141. package/tests/benchmark/fixtures/EcommerceComponents.ts +0 -283
  142. package/tests/benchmark/fixtures/EcommerceDataGenerators.ts +0 -301
  143. package/tests/benchmark/fixtures/RelationTracker.ts +0 -159
  144. package/tests/benchmark/fixtures/index.ts +0 -6
  145. package/tests/benchmark/index.ts +0 -22
  146. package/tests/benchmark/noop-preload.ts +0 -3
  147. package/tests/benchmark/query-lateral-benchmark.test.ts +0 -372
  148. package/tests/benchmark/runners/BenchmarkLoader.ts +0 -132
  149. package/tests/benchmark/runners/index.ts +0 -4
  150. package/tests/benchmark/scenarios/query-benchmarks.test.ts +0 -465
  151. package/tests/benchmark/scripts/generate-db.ts +0 -344
  152. package/tests/benchmark/scripts/run-benchmarks.ts +0 -97
  153. package/tests/e2e/http.test.ts +0 -130
  154. package/tests/fixtures/archetypes/TestUserArchetype.ts +0 -21
  155. package/tests/fixtures/components/TestOrder.ts +0 -23
  156. package/tests/fixtures/components/TestProduct.ts +0 -23
  157. package/tests/fixtures/components/TestUser.ts +0 -20
  158. package/tests/fixtures/components/index.ts +0 -6
  159. package/tests/graphql/SchemaGeneration.test.ts +0 -90
  160. package/tests/graphql/builders/ResolverBuilder.test.ts +0 -223
  161. package/tests/graphql/builders/TypeDefBuilder.test.ts +0 -153
  162. package/tests/helpers/MockRedisClient.ts +0 -113
  163. package/tests/helpers/MockRedisStreamServer.ts +0 -448
  164. package/tests/integration/archetype/ArcheType.persistence.test.ts +0 -241
  165. package/tests/integration/cache/CacheInvalidation.test.ts +0 -259
  166. package/tests/integration/entity/Entity.persistence.test.ts +0 -333
  167. package/tests/integration/entity/Entity.saveTimeout.test.ts +0 -110
  168. package/tests/integration/query/Query.complexAnalysis.test.ts +0 -557
  169. package/tests/integration/query/Query.edgeCases.test.ts +0 -595
  170. package/tests/integration/query/Query.exec.test.ts +0 -576
  171. package/tests/integration/query/Query.explainAnalyze.test.ts +0 -233
  172. package/tests/integration/query/Query.jsonbArray.test.ts +0 -214
  173. package/tests/integration/remote/dlq.test.ts +0 -175
  174. package/tests/integration/remote/event-dispatch.test.ts +0 -114
  175. package/tests/integration/remote/outbox.test.ts +0 -130
  176. package/tests/integration/remote/rpc.test.ts +0 -177
  177. package/tests/pglite-setup.ts +0 -62
  178. package/tests/setup.ts +0 -164
  179. package/tests/stress/BenchmarkRunner.ts +0 -203
  180. package/tests/stress/DataSeeder.ts +0 -190
  181. package/tests/stress/StressTestReporter.ts +0 -229
  182. package/tests/stress/cursor-perf-test.ts +0 -171
  183. package/tests/stress/fixtures/RealisticComponents.ts +0 -235
  184. package/tests/stress/fixtures/StressTestComponents.ts +0 -58
  185. package/tests/stress/index.ts +0 -7
  186. package/tests/stress/scenarios/query-benchmarks.test.ts +0 -285
  187. package/tests/stress/scenarios/realistic-scenarios.test.ts +0 -1081
  188. package/tests/stress/scenarios/timeout-investigation.test.ts +0 -522
  189. package/tests/unit/BatchLoader.test.ts +0 -196
  190. package/tests/unit/archetype/ArcheType.test.ts +0 -107
  191. package/tests/unit/cache/CacheManager.test.ts +0 -367
  192. package/tests/unit/cache/MemoryCache.test.ts +0 -260
  193. package/tests/unit/cache/RedisCache.test.ts +0 -411
  194. package/tests/unit/entity/Entity.components.test.ts +0 -317
  195. package/tests/unit/entity/Entity.drainSideEffects.test.ts +0 -51
  196. package/tests/unit/entity/Entity.reload.test.ts +0 -63
  197. package/tests/unit/entity/Entity.requireComponents.test.ts +0 -72
  198. package/tests/unit/entity/Entity.test.ts +0 -345
  199. package/tests/unit/gql/depthLimit.test.ts +0 -203
  200. package/tests/unit/gql/operationMiddleware.test.ts +0 -293
  201. package/tests/unit/health/Health.test.ts +0 -129
  202. package/tests/unit/middleware/AccessLog.test.ts +0 -37
  203. package/tests/unit/middleware/Middleware.test.ts +0 -98
  204. package/tests/unit/middleware/RequestId.test.ts +0 -54
  205. package/tests/unit/middleware/SecurityHeaders.test.ts +0 -66
  206. package/tests/unit/query/FilterBuilder.test.ts +0 -111
  207. package/tests/unit/query/JsonbArrayBuilder.test.ts +0 -178
  208. package/tests/unit/query/Query.emptyString.test.ts +0 -69
  209. package/tests/unit/query/Query.test.ts +0 -310
  210. package/tests/unit/remote/CircuitBreaker.test.ts +0 -159
  211. package/tests/unit/remote/RemoteError.test.ts +0 -55
  212. package/tests/unit/remote/decorators.test.ts +0 -195
  213. package/tests/unit/remote/metrics.test.ts +0 -115
  214. package/tests/unit/remote/mockRedisStreamServer.test.ts +0 -104
  215. package/tests/unit/scheduler/DistributedLock.test.ts +0 -274
  216. package/tests/unit/scheduler/SchedulerManager.timeBased.test.ts +0 -95
  217. package/tests/unit/schema/schema-integration.test.ts +0 -426
  218. package/tests/unit/schema/schema.test.ts +0 -580
  219. package/tests/unit/storage/S3StorageProvider.test.ts +0 -567
  220. package/tests/unit/upload/RestUpload.test.ts +0 -267
  221. package/tests/unit/validateEnv.test.ts +0 -82
  222. package/tests/utils/entity-tracker.ts +0 -57
  223. package/tests/utils/index.ts +0 -13
  224. package/tests/utils/test-context.ts +0 -149
@@ -1,77 +0,0 @@
1
- /** @type {import('tailwindcss').Config} */
2
- export default {
3
- darkMode: ["class"],
4
- content: [
5
- './pages/**/*.{ts,tsx}',
6
- './components/**/*.{ts,tsx}',
7
- './app/**/*.{ts,tsx}',
8
- './src/**/*.{ts,tsx}',
9
- ],
10
- prefix: "",
11
- theme: {
12
- container: {
13
- center: true,
14
- padding: "2rem",
15
- screens: {
16
- "2xl": "1400px",
17
- },
18
- },
19
- extend: {
20
- colors: {
21
- border: "hsl(var(--border))",
22
- input: "hsl(var(--input))",
23
- ring: "hsl(var(--ring))",
24
- background: "hsl(var(--background))",
25
- foreground: "hsl(var(--foreground))",
26
- primary: {
27
- DEFAULT: "hsl(var(--primary))",
28
- foreground: "hsl(var(--primary-foreground))",
29
- },
30
- secondary: {
31
- DEFAULT: "hsl(var(--secondary))",
32
- foreground: "hsl(var(--secondary-foreground))",
33
- },
34
- destructive: {
35
- DEFAULT: "hsl(var(--destructive))",
36
- foreground: "hsl(var(--destructive-foreground))",
37
- },
38
- muted: {
39
- DEFAULT: "hsl(var(--muted))",
40
- foreground: "hsl(var(--muted-foreground))",
41
- },
42
- accent: {
43
- DEFAULT: "hsl(var(--accent))",
44
- foreground: "hsl(var(--accent-foreground))",
45
- },
46
- popover: {
47
- DEFAULT: "hsl(var(--popover))",
48
- foreground: "hsl(var(--popover-foreground))",
49
- },
50
- card: {
51
- DEFAULT: "hsl(var(--card))",
52
- foreground: "hsl(var(--card-foreground))",
53
- },
54
- },
55
- borderRadius: {
56
- lg: "var(--radius)",
57
- md: "calc(var(--radius) - 2px)",
58
- sm: "calc(var(--radius) - 4px)",
59
- },
60
- keyframes: {
61
- "accordion-down": {
62
- from: { height: "0" },
63
- to: { height: "var(--radix-accordion-content-height)" },
64
- },
65
- "accordion-up": {
66
- from: { height: "var(--radix-accordion-content-height)" },
67
- to: { height: "0" },
68
- },
69
- },
70
- animation: {
71
- "accordion-down": "accordion-down 0.2s ease-out",
72
- "accordion-up": "accordion-up 0.2s ease-out",
73
- },
74
- },
75
- },
76
- plugins: [require("tailwindcss-animate")],
77
- }
package/studio/utils.ts DELETED
@@ -1,54 +0,0 @@
1
- /**
2
- * Finds the indicator component name from an archetype's field list.
3
- * The indicator is used to identify entities of this archetype type.
4
- *
5
- * Priority order:
6
- * 1. {ArcheTypeName}Tag (e.g., UserTag)
7
- * 2. {ArcheTypeName}Id (e.g., UserId)
8
- * 3. Any field starting with {ArcheTypeName}
9
- * 4. Any field containing {ArcheTypeName}
10
- * 5. Fallback to first component
11
- */
12
- export function findIndicatorComponentName(
13
- archeTypeName: string,
14
- fields: Array<{ componentName: string; fieldName: string }>
15
- ): string | null {
16
- if (fields.length === 0) {
17
- return null;
18
- }
19
-
20
- const archeTypeNameLower = archeTypeName.toLowerCase();
21
- const componentNames = fields.map(field => field.componentName);
22
-
23
- const tagComponentName = `${archeTypeName}Tag`;
24
- const tagMatch = componentNames.find(
25
- name => name.toLowerCase() === tagComponentName.toLowerCase()
26
- );
27
- if (tagMatch) {
28
- return tagMatch;
29
- }
30
-
31
- const idComponentName = `${archeTypeName}Id`;
32
- const idMatch = componentNames.find(
33
- name => name.toLowerCase() === idComponentName.toLowerCase()
34
- );
35
- if (idMatch) {
36
- return idMatch;
37
- }
38
-
39
- const startsWithMatch = componentNames.find(
40
- name => name.toLowerCase().startsWith(archeTypeNameLower)
41
- );
42
- if (startsWithMatch) {
43
- return startsWithMatch;
44
- }
45
-
46
- const containsMatch = componentNames.find(
47
- name => name.toLowerCase().includes(archeTypeNameLower)
48
- );
49
- if (containsMatch) {
50
- return containsMatch;
51
- }
52
-
53
- return componentNames[0] ?? null;
54
- }
@@ -1,19 +0,0 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react'
3
-
4
- export default defineConfig({
5
- base: '/studio/',
6
- plugins: [react()],
7
- build: {
8
- outDir: 'dist',
9
- rollupOptions: {
10
- output: {
11
- manualChunks: undefined,
12
- }
13
- }
14
- },
15
- server: {
16
- port: 5173,
17
- host: true
18
- }
19
- })
@@ -1,338 +0,0 @@
1
- # PGlite Persistent Benchmark Databases Plan
2
-
3
- ## Overview
4
-
5
- Create pre-populated PGlite databases at various scale tiers for consistent, reproducible query benchmarks without re-seeding overhead.
6
-
7
- ## Database Tiers
8
-
9
- | Tier | Entities | Products | Orders | Users | Reviews | Est. Size |
10
- |------|----------|----------|--------|-------|---------|-----------|
11
- | xs | 10,000 | 5,000 | 3,000 | 1,000 | 1,000 | ~50 MB |
12
- | sm | 50,000 | 25,000 | 15,000 | 5,000 | 5,000 | ~250 MB |
13
- | md | 100,000 | 50,000 | 30,000 | 10,000| 10,000 | ~500 MB |
14
- | lg | 500,000 | 250,000 | 150,000| 50,000| 50,000 | ~2.5 GB |
15
- | xl | 1,000,000| 500,000 | 300,000| 100,000| 100,000| ~5 GB |
16
-
17
- ## Directory Structure
18
-
19
- ```
20
- tests/benchmark/
21
- ├── BENCHMARK_DATABASES_PLAN.md # This plan
22
- ├── databases/ # Persistent PGlite databases (gitignored)
23
- │ ├── bench-xs/ # 10k entities
24
- │ ├── bench-sm/ # 50k entities
25
- │ ├── bench-md/ # 100k entities
26
- │ ├── bench-lg/ # 500k entities
27
- │ └── bench-xl/ # 1M entities
28
- ├── fixtures/
29
- │ └── BenchmarkComponents.ts # Reusable components for benchmarks
30
- ├── generators/
31
- │ ├── index.ts # Main generator entry point
32
- │ ├── DataGenerator.ts # Realistic data generation utilities
33
- │ ├── EntitySeeder.ts # Batch entity creation with relations
34
- │ └── ProgressReporter.ts # CLI progress reporting
35
- ├── runners/
36
- │ ├── QueryBenchmark.ts # Query benchmark runner
37
- │ └── RelationBenchmark.ts # BelongsTo/HasMany benchmark
38
- └── generate-databases.ts # CLI script to generate all tiers
39
- ```
40
-
41
- ## Data Model (E-commerce Scenario)
42
-
43
- ### Components (from RealisticComponents.ts)
44
-
45
- 1. **Product** - Core product data (name, SKU, category, status, rating)
46
- 2. **Inventory** - Stock tracking (quantity, warehouse, stock status)
47
- 3. **Pricing** - Price info (base, sale, cost, discount, currency)
48
- 4. **Vendor** - Supplier info (name, region, rating, tier)
49
- 5. **ProductMetrics** - Analytics (views, purchases, conversion)
50
-
51
- ### Additional Components for Relations
52
-
53
- 6. **User** - Customer data (name, email, tier, region)
54
- 7. **Order** - Order data (userId, status, total, itemCount)
55
- 8. **OrderItem** - Line items (orderId, productId, quantity, price)
56
- 9. **Review** - Product reviews (userId, productId, rating, text)
57
- 10. **Wishlist** - User wishlists (userId, productIds[])
58
-
59
- ### Relation Structure
60
-
61
- ```
62
- User (1) ──HasMany──> Order (N)
63
- User (1) ──HasMany──> Review (N)
64
- User (1) ──HasMany──> Wishlist (1)
65
-
66
- Order (1) ──HasMany──> OrderItem (N)
67
- Order (N) ──BelongsTo──> User (1)
68
-
69
- OrderItem (N) ──BelongsTo──> Order (1)
70
- OrderItem (N) ──BelongsTo──> Product (1)
71
-
72
- Review (N) ──BelongsTo──> User (1)
73
- Review (N) ──BelongsTo──> Product (1)
74
-
75
- Product (1) ──HasMany──> Review (N)
76
- Product (1) ──HasMany──> OrderItem (N)
77
- Product (N) ──BelongsTo──> Vendor (1)
78
- ```
79
-
80
- ## Implementation Steps
81
-
82
- ### Phase 1: Infrastructure Setup
83
-
84
- 1. **Create directory structure**
85
- - Create `tests/benchmark/` directories
86
- - Add `databases/` to `.gitignore`
87
-
88
- 2. **Create BenchmarkComponents.ts**
89
- - Define User, Order, OrderItem, Review, Wishlist components
90
- - Define BenchmarkArchetypes with proper relations
91
-
92
- 3. **Create DataGenerator.ts**
93
- - Faker-like utilities for realistic data (names, emails, addresses)
94
- - Deterministic seeding with configurable seed for reproducibility
95
- - Batch generation for memory efficiency
96
-
97
- ### Phase 2: Seeding System
98
-
99
- 4. **Create EntitySeeder.ts**
100
- ```typescript
101
- interface SeederConfig {
102
- tier: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
103
- seed?: number; // For reproducibility
104
- batchSize?: number; // Default 1000
105
- showProgress?: boolean; // CLI progress bar
106
- }
107
-
108
- class EntitySeeder {
109
- async seedProducts(count: number): Promise<string[]>;
110
- async seedUsers(count: number): Promise<string[]>;
111
- async seedOrders(userIds: string[], productIds: string[]): Promise<void>;
112
- async seedReviews(userIds: string[], productIds: string[]): Promise<void>;
113
- async createIndexes(): Promise<void>;
114
- async vacuum(): Promise<void>;
115
- }
116
- ```
117
-
118
- 5. **Create ProgressReporter.ts**
119
- - CLI progress bars for long-running operations
120
- - ETA calculation
121
- - Memory usage monitoring
122
-
123
- ### Phase 3: Generator Script
124
-
125
- 6. **Create generate-databases.ts**
126
- ```bash
127
- # Generate all tiers
128
- bun tests/benchmark/generate-databases.ts --all
129
-
130
- # Generate specific tier
131
- bun tests/benchmark/generate-databases.ts --tier=md
132
-
133
- # Regenerate (delete existing + recreate)
134
- bun tests/benchmark/generate-databases.ts --tier=sm --force
135
-
136
- # Custom seed for reproducibility
137
- bun tests/benchmark/generate-databases.ts --tier=xs --seed=42
138
- ```
139
-
140
- 7. **Generation Process**
141
- ```
142
- For each tier:
143
- 1. Check if database directory exists (skip if exists, unless --force)
144
- 2. Create PGlite with dataDir
145
- 3. Run database migrations (PrepareDatabase)
146
- 4. Register components
147
- 5. Seed entities in batches with progress
148
- 6. Create relation foreign keys
149
- 7. Create indexes (CreateRelationIndexes)
150
- 8. Run VACUUM ANALYZE
151
- 9. Report final stats (entity count, db size, time taken)
152
- ```
153
-
154
- ### Phase 4: Benchmark Runner
155
-
156
- 8. **Create benchmark loading utility**
157
- ```typescript
158
- // tests/benchmark/runners/loadBenchmarkDb.ts
159
- export async function loadBenchmarkDatabase(
160
- tier: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
161
- ): Promise<{ pg: PGlite; server: PGLiteSocketServer; cleanup: () => Promise<void> }>;
162
- ```
163
-
164
- 9. **Create QueryBenchmark.ts**
165
- ```typescript
166
- interface BenchmarkResult {
167
- name: string;
168
- tier: string;
169
- entityCount: number;
170
- queryTimeMs: number;
171
- rowsReturned: number;
172
- memoryUsedMB: number;
173
- }
174
-
175
- // Benchmark scenarios
176
- - Simple filter (single component, indexed field)
177
- - Multi-component filter (2-3 components with AND)
178
- - Complex query (multi-component + sort + limit)
179
- - BelongsTo resolution (N users with their orders)
180
- - HasMany resolution (N products with their reviews)
181
- - Deep nesting (Order -> User -> Reviews -> Products)
182
- ```
183
-
184
- ### Phase 5: npm Scripts
185
-
186
- 10. **Add to package.json**
187
- ```json
188
- {
189
- "scripts": {
190
- "bench:generate": "bun tests/benchmark/generate-databases.ts --all",
191
- "bench:generate:xs": "bun tests/benchmark/generate-databases.ts --tier=xs",
192
- "bench:generate:sm": "bun tests/benchmark/generate-databases.ts --tier=sm",
193
- "bench:generate:md": "bun tests/benchmark/generate-databases.ts --tier=md",
194
- "bench:generate:lg": "bun tests/benchmark/generate-databases.ts --tier=lg",
195
- "bench:generate:xl": "bun tests/benchmark/generate-databases.ts --tier=xl",
196
- "bench:query": "bun tests/benchmark/runners/QueryBenchmark.ts",
197
- "bench:relations": "bun tests/benchmark/runners/RelationBenchmark.ts"
198
- }
199
- }
200
- ```
201
-
202
- ## Data Generation Details
203
-
204
- ### Realistic Distribution
205
-
206
- ```typescript
207
- // Product categories follow power-law distribution
208
- // ~40% in top 3 categories, ~60% in remaining 7
209
- const categoryWeights = {
210
- 'Electronics': 0.20,
211
- 'Clothing': 0.12,
212
- 'Home & Garden': 0.08,
213
- // ... rest evenly distributed
214
- };
215
-
216
- // Order counts per user follow exponential distribution
217
- // Most users: 1-5 orders, some power users: 50+ orders
218
- function getOrderCountForUser(): number {
219
- const r = Math.random();
220
- if (r < 0.7) return randomInt(1, 5);
221
- if (r < 0.9) return randomInt(6, 20);
222
- return randomInt(21, 100);
223
- }
224
-
225
- // Reviews are skewed toward extreme ratings (1, 4, 5 stars)
226
- function getReviewRating(): number {
227
- const r = Math.random();
228
- if (r < 0.05) return 1; // 5% - 1 star
229
- if (r < 0.10) return 2; // 5% - 2 stars
230
- if (r < 0.20) return 3; // 10% - 3 stars
231
- if (r < 0.50) return 4; // 30% - 4 stars
232
- return 5; // 50% - 5 stars
233
- }
234
- ```
235
-
236
- ### Batch Insertion Strategy
237
-
238
- ```typescript
239
- // Avoid memory issues with large datasets
240
- const BATCH_SIZE = 1000;
241
-
242
- async function seedInBatches<T>(
243
- total: number,
244
- generator: (batchIndex: number, batchSize: number) => Promise<T[]>,
245
- inserter: (items: T[]) => Promise<void>
246
- ) {
247
- const batches = Math.ceil(total / BATCH_SIZE);
248
- for (let i = 0; i < batches; i++) {
249
- const items = await generator(i, Math.min(BATCH_SIZE, total - i * BATCH_SIZE));
250
- await inserter(items);
251
- // Allow GC between batches
252
- if (i % 10 === 0) await Bun.sleep(1);
253
- }
254
- }
255
- ```
256
-
257
- ## Benchmark Scenarios
258
-
259
- ### Query Performance Matrix
260
-
261
- | Scenario | Description | Expected Behavior |
262
- |----------|-------------|-------------------|
263
- | Q1 | Filter by indexed field | O(log n), <50ms at 1M |
264
- | Q2 | Filter by non-indexed field | O(n), slower |
265
- | Q3 | Multi-component AND | Uses INTERSECT optimization |
266
- | Q4 | Multi-component + Sort | Uses scalar subquery sort |
267
- | Q5 | BelongsTo single | DataLoader batched |
268
- | Q6 | HasMany collection | Single filtered query |
269
- | Q7 | Nested relations 3-deep | DataLoader + batching |
270
- | Q8 | Pagination (offset) | Cursor recommended at scale |
271
- | Q9 | Count aggregation | Fast with proper indexes |
272
- | Q10 | Full table scan | Baseline comparison |
273
-
274
- ### Expected Performance Targets
275
-
276
- | Tier | Q1 (indexed) | Q3 (multi) | Q5 (BelongsTo) | Q7 (nested) |
277
- |------|--------------|------------|----------------|-------------|
278
- | xs | <10ms | <20ms | <30ms | <50ms |
279
- | sm | <15ms | <40ms | <50ms | <100ms |
280
- | md | <20ms | <60ms | <80ms | <150ms |
281
- | lg | <30ms | <100ms | <150ms | <300ms |
282
- | xl | <50ms | <150ms | <250ms | <500ms |
283
-
284
- ## Files to Create
285
-
286
- 1. `tests/benchmark/fixtures/BenchmarkComponents.ts`
287
- 2. `tests/benchmark/fixtures/BenchmarkArchetypes.ts`
288
- 3. `tests/benchmark/generators/DataGenerator.ts`
289
- 4. `tests/benchmark/generators/EntitySeeder.ts`
290
- 5. `tests/benchmark/generators/ProgressReporter.ts`
291
- 6. `tests/benchmark/generators/index.ts`
292
- 7. `tests/benchmark/generate-databases.ts`
293
- 8. `tests/benchmark/runners/loadBenchmarkDb.ts`
294
- 9. `tests/benchmark/runners/QueryBenchmark.ts`
295
- 10. `tests/benchmark/runners/RelationBenchmark.ts`
296
-
297
- ## Gitignore Addition
298
-
299
- ```gitignore
300
- # Benchmark databases (large, generated locally)
301
- tests/benchmark/databases/
302
- ```
303
-
304
- ## Usage Example
305
-
306
- ```bash
307
- # First time: Generate benchmark databases
308
- bun run bench:generate:xs # Quick: ~30s
309
- bun run bench:generate:md # Medium: ~5min
310
- bun run bench:generate:xl # Large: ~30min
311
-
312
- # Run benchmarks (uses pre-generated databases)
313
- bun run bench:query --tier=md
314
- bun run bench:relations --tier=lg
315
-
316
- # Results output
317
- # ┌─────────────────────────────────────────────────────────┐
318
- # │ Query Benchmark Results - Tier: md (100,000 entities) │
319
- # ├──────────────────────┬─────────┬──────────┬────────────┤
320
- # │ Scenario │ Time │ Rows │ Memory │
321
- # ├──────────────────────┼─────────┼──────────┼────────────┤
322
- # │ Q1: Indexed filter │ 18ms │ 1,234 │ 2.3 MB │
323
- # │ Q3: Multi-component │ 52ms │ 456 │ 4.1 MB │
324
- # │ Q5: BelongsTo batch │ 71ms │ 100 │ 5.8 MB │
325
- # │ Q7: Nested 3-deep │ 142ms │ 50 │ 12.4 MB │
326
- # └──────────────────────┴─────────┴──────────┴────────────┘
327
- ```
328
-
329
- ## Next Steps
330
-
331
- 1. Review and approve this plan
332
- 2. Create the directory structure
333
- 3. Implement Phase 1-2 (components + seeder)
334
- 4. Implement Phase 3 (generator script)
335
- 5. Generate xs/sm tiers for initial testing
336
- 6. Implement Phase 4 (benchmark runners)
337
- 7. Generate remaining tiers
338
- 8. Document results and establish baselines
@@ -1,9 +0,0 @@
1
- [test]
2
- # No preload for benchmark tests - we manage the database connection ourselves
3
- preload = []
4
-
5
- # Longer timeout for benchmarks
6
- timeout = 300000
7
-
8
- # Single-threaded to avoid connection conflicts
9
- smol = true