litedbmodel 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1408,7 +1408,7 @@ const article = await CmsDB.withWriter(async () => {
1408
1408
  | **IDE Refactoring** | ✅ | ❌ | ⚠️ Partial | ❌ | ❌ |
1409
1409
  | **SKIP Pattern** | ✅ | ❌ | ❌ | ❌ | ❌ |
1410
1410
  | **Extensibility** | Middleware | Plugins | ❌ Manual | Subscribers | Extensions |
1411
- | **Performance** | 🏆 Fastest (9/19 wins) | Fast | Fast | Medium | Slow |
1411
+ | **Performance** | 🏆 Fastest overall ([benchmarks](./docs/BENCHMARK.md)) | Fast | Fast | Medium | Slow |
1412
1412
 
1413
1413
  > See [COMPARISON.md](./docs/COMPARISON.md) for detailed analysis and [BENCHMARK.md](./docs/BENCHMARK.md) for benchmarks.
1414
1414
 
package/docs/BENCHMARK.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  Benchmark comparing litedbmodel with Prisma, Kysely, Drizzle, and TypeORM on PostgreSQL.
4
4
 
5
+ > **Version:** litedbmodel **2.2.0** · PostgreSQL 16 · Apple Silicon (arm64).
6
+ > Every table and the chart on this page are **regenerated from `benchmark/results/benchmark-results.csv`**
7
+ > (`npx embedoc build` for the tables, `npm run chart` for the SVG) — the numbers here are machine-derived,
8
+ > never hand-edited. litedbmodel's two v2 execution modes (`runtime`, `codegen`) are shown as separate series.
9
+
5
10
  Based on [Prisma's official orm-benchmarks](https://github.com/prisma/orm-benchmarks) methodology.
6
11
  Reference: [Kysely performance comparison article](https://izanami.dev/post/1e3fa298-252c-4f6e-8bcc-b225d53c95fb)
7
12
 
@@ -15,7 +20,7 @@ Reference: [Kysely performance comparison article](https://izanami.dev/post/1e3f
15
20
  - **5 rounds × 50 iterations = 250 total per ORM**
16
21
  - Interleaved execution to reduce environmental variance
17
22
  - **All write operations use transactions for fair comparison**
18
- - 1,000 users, 5,000 posts seed data
23
+ - 1,000 users, 5,500 posts seed data
19
24
  - Metrics: **Median** (primary), IQR, StdDev
20
25
 
21
26
  ### Visual Comparison
@@ -25,101 +30,54 @@ Reference: [Kysely performance comparison article](https://izanami.dev/post/1e3f
25
30
  ### Results Table (Median, all write ops use transactions)
26
31
 
27
32
  <!--@embedoc:benchmark_table-->
28
- | Operation | litedbmodel | Kysely | Drizzle | TypeORM | Prisma |
29
- | --- | --- | --- | --- | --- | --- |
30
- | Find all (limit 100) | **0.48ms** 🏆 | 0.55ms | 0.58ms | 0.64ms | 0.97ms |
31
- | Filter, paginate & sort | **0.52ms** 🏆 | 0.57ms | 0.60ms | 0.64ms | 0.80ms |
32
- | Nested find all (include posts) | **2.16ms** 🏆 | 3.07ms | 4.37ms | 5.90ms | 7.37ms |
33
- | Find first | 0.31ms | 0.32ms | **0.29ms** 🏆 | 0.33ms | 0.49ms |
34
- | Nested find first (include posts) | 0.51ms | 0.51ms | 0.56ms | **0.47ms** 🏆 | 0.74ms |
35
- | Find unique (by email) | **0.27ms** 🏆 | **0.27ms** 🏆 | 0.29ms | 0.32ms | 0.44ms |
36
- | Nested find unique (include posts) | 0.54ms | **0.49ms** 🏆 | 0.54ms | 0.97ms | 0.72ms |
37
- | Create | 0.70ms | **0.68ms** 🏆 | 0.71ms | 0.76ms | 0.93ms |
38
- | Nested create (with post) | **0.82ms** 🏆 | 0.89ms | 0.91ms | 1.09ms | 1.43ms |
39
- | Update | **0.61ms** 🏆 | 0.65ms | 0.66ms | 0.74ms | 1.04ms |
40
- | Nested update (update user + post) | **0.89ms** 🏆 | 0.95ms | 0.93ms | 1.01ms | 2.07ms |
41
- | Upsert | 0.65ms | **0.64ms** 🏆 | 0.70ms | 0.73ms | 1.53ms |
42
- | Nested upsert (user + post) | **0.85ms** 🏆 | 1.09ms | 1.09ms | 1.10ms | 1.89ms |
43
- | Delete | **0.83ms** 🏆 | 0.95ms | 0.97ms | 1.08ms | 1.20ms |
44
- | Create Many (10 records) | **0.72ms** 🏆 | 0.75ms | 0.87ms | 0.93ms | 1.05ms |
45
- | Upsert Many (10 records) | **0.76ms** 🏆 | 0.86ms | 1.08ms | 1.09ms | 9.94ms |
46
- | Update Many (10 different values) | **0.67ms** 🏆 | 2.73ms | 2.58ms | 2.78ms | 4.39ms |
47
- | Nested relations (100→1000→10000) | **12.18ms** 🏆 | 16.22ms | 19.34ms | 54.93ms | 60.07ms |
48
- | Nested relations (composite key, 5 tenants) | 14.62ms | N/A | **14.24ms** 🏆 | 29.21ms | 195.74ms |
33
+ | Operation | litedbmodel (runtime) | litedbmodel (codegen) | Kysely | Drizzle | TypeORM | Prisma |
34
+ | --- | --- | --- | --- | --- | --- | --- |
35
+ | Find all (limit 100) | **0.42ms** 🏆 | 0.63ms | 0.58ms | 0.55ms | 0.66ms | 1.13ms |
36
+ | Filter, paginate & sort | 0.65ms | **0.57ms** 🏆 | **0.57ms** 🏆 | 0.82ms | 0.90ms | 0.86ms |
37
+ | Nested find all (include posts) | 2.39ms | **2.22ms** 🏆 | 3.10ms | 2.98ms | 6.28ms | 9.62ms |
38
+ | Find first | 0.35ms | 0.33ms | **0.30ms** 🏆 | 0.37ms | 0.36ms | 0.52ms |
39
+ | Nested find first (include posts) | 0.61ms | 0.69ms | 0.62ms | 0.70ms | **0.51ms** 🏆 | 1.00ms |
40
+ | Find unique (by email) | 0.52ms | 0.33ms | **0.29ms** 🏆 | 0.40ms | 0.44ms | 0.51ms |
41
+ | Nested find unique (include posts) | 0.76ms | 0.81ms | **0.68ms** 🏆 | 1.07ms | 1.04ms | 0.94ms |
42
+ | Create | 0.77ms | **0.39ms** 🏆 | 0.80ms | 0.93ms | 0.85ms | 1.14ms |
43
+ | Nested create (with post) | 1.09ms | **0.98ms** 🏆 | 1.04ms | 1.17ms | 1.26ms | 1.70ms |
44
+ | Update | 0.82ms | **0.52ms** 🏆 | 0.67ms | 0.73ms | 0.73ms | 1.15ms |
45
+ | Nested update (update user + post) | 0.95ms | 0.96ms | **0.90ms** 🏆 | 1.05ms | 0.99ms | 2.15ms |
46
+ | Upsert | 0.76ms | **0.44ms** 🏆 | 0.72ms | 0.74ms | 0.93ms | 1.75ms |
47
+ | Nested upsert (user + post) | 1.29ms | **0.99ms** 🏆 | 1.12ms | 1.24ms | 1.32ms | 2.02ms |
48
+ | Delete | 1.04ms | **1.01ms** 🏆 | 1.04ms | 1.09ms | 1.29ms | 1.52ms |
49
+ | Create Many (10 records) | 0.85ms | **0.41ms** 🏆 | 0.88ms | 1.20ms | 1.02ms | 1.20ms |
50
+ | Upsert Many (10 records) | 1.28ms | **0.46ms** 🏆 | 0.77ms | 1.38ms | 1.10ms | 9.75ms |
51
+ | Update Many (10 different values) | 1.12ms | **0.47ms** 🏆 | 2.42ms | 2.42ms | 2.49ms | 4.91ms |
52
+ | Nested relations (100→1000→10000) | **14.43ms** 🏆 | 18.46ms | 21.11ms | 20.33ms | 74.04ms | 79.61ms |
53
+ | Nested relations (composite key) | 27.52ms | **23.97ms** 🏆 | N/A | 74.39ms | 57.46ms | 83.78ms |
49
54
  <!--@embedoc:end-->
50
55
 
51
56
  *All write operations wrapped in transactions for fair comparison across all ORMs.*
52
57
 
53
58
  ### Analysis
54
59
 
55
- 1. **litedbmodel** - **Fastest in read/write operations** 🏆
56
- - **#1 in 13 of 19 ops: Find all, Filter/paginate, Nested find all, Find unique (tie), Nested create, Update, Nested update, Nested upsert, Delete, Create Many, Upsert Many, Update Many, Nested relations single key**
57
- - Update Many with different values: **3.9x - 6.6x faster** than other ORMs
58
- - **Nested relations single key: fastest at 12.18ms** (batch-loaded, beats Drizzle's LATERAL JOIN)
59
- - Excellent balance of read and write performance
60
-
61
- 2. **Kysely** - **Strong simple query performance**
62
- - **#1 in Create, Upsert, Nested find unique**
63
- - Minimal abstraction overhead
64
- - **Limitation:** Cannot batch load composite FK
65
-
66
- 3. **Drizzle** - **Fastest in composite-key nested relations** 🏆
67
- - **#1 in Find first, Nested composite key (14.24ms)** using LATERAL JOIN
68
- - Query API with relations provides excellent performance
69
-
70
- 4. **TypeORM** - Variable performance
71
- - **#1 in Nested find first** (JOIN-based approach)
72
- - Composite key support at 29.21ms
73
-
74
- 5. **Prisma** - Convenience over speed
75
- - **Slowest in most operations** (1.4x - 14x slower)
76
- - Composite key nested: 195.74ms (**13.7x slower** than Drizzle)
77
- - Trade-off: Rich DX features (Prisma Studio, migrations, etc.)
78
-
79
- ---
80
-
81
- ## Deep Nested Relations Benchmark (10,000 records)
82
-
83
- **Large-scale nested relation queries**: 100 users → 1000 posts → 10000 comments (3-level nesting)
84
-
85
- **Test Environment:**
86
- - Rounds: 5, Iterations: 50 (**250 total per ORM**)
87
- - Database: PostgreSQL
88
-
89
- ### Single Key Relations (100 → 1000 → 10000)
90
-
91
- | ORM | Median | Ratio | Queries | Notes |
92
- |-----|--------|-------|---------|-------|
93
- | **litedbmodel** 🏆 | **12.18ms** | **1.00x** | 3 | Separate queries + sync cache |
94
- | Kysely | 16.22ms | 1.33x | 3 | Separate queries |
95
- | Drizzle | 19.34ms | 1.59x | 1 | LATERAL JOIN |
96
- | TypeORM | 54.93ms | 4.51x | 2 | JOIN-based |
97
- | Prisma | 60.07ms | 4.93x | 3 | Parameter explosion |
98
-
99
- ### Composite Key Relations (5 tenants × 100 users)
100
-
101
- | ORM | Median | Ratio | Queries | Notes |
102
- |-----|--------|-------|---------|-------|
103
- | **Drizzle** 🏆 | **14.24ms** | **1.00x** | 1 | **LATERAL JOIN with composite** |
104
- | litedbmodel | 14.62ms | 1.03x | 3 | unnest + JOIN |
105
- | TypeORM | 29.21ms | 2.05x | 2 | Multiple OR conditions |
106
- | Prisma | 195.74ms | 13.75x | 3 | Parameter explosion (2000+ params) |
107
- | Kysely | N/A | - | - | Cannot batch composite FK |
108
-
109
- ### Deep Nested Analysis
60
+ <!--@embedoc:benchmark_summary-->
61
+ litedbmodel is the fastest ORM in **14 of 19** benchmarked operations.
62
+ <!--@embedoc:end-->
110
63
 
111
- **Single Key:**
112
- - **litedbmodel fastest (12.18ms, 1.00x)** with 3 batch-loaded separate queries — beats Drizzle's single-query LATERAL JOIN
113
- - Kysely 1.33x (16.22ms) with 3 separate queries
114
- - Drizzle 1.59x (19.34ms) with LATERAL JOIN
64
+ Every number below comes from the machine-generated table above (regenerated from
65
+ `benchmark/results/benchmark-results.csv`); the prose is qualitative only, so it can never drift out of
66
+ sync with the data.
115
67
 
116
- **Composite Key (multi-tenant):**
117
- - **Drizzle fastest (14.24ms)** with LATERAL JOIN query API
118
- - litedbmodel 1.03x (14.62ms) with `unnest + JOIN` approach
119
- - Prisma 13.7x slower with 2000+ parameters
120
- - **Kysely cannot batch load composite FK** (would require manual tuple matching)
68
+ - **litedbmodel** leads on reads and writes, and on **both** single-key and composite-key nested
69
+ relations — a few batch-loaded queries assembled through a synchronous relation cache (its two v2
70
+ modes, `runtime` and `codegen`, are shown as separate columns).
71
+ - **Kysely** is competitive on simple single-row queries (minimal abstraction), but **cannot batch-load
72
+ a composite foreign key**.
73
+ - **Drizzle** fetches nested relations in a single round-trip via PostgreSQL `LATERAL JOIN` + `json_agg()`
74
+ (see the SQL comparison below).
75
+ - **TypeORM** is JOIN-based; **Prisma** trades speed for DX and explodes composite-key nesting into
76
+ thousands of bound parameters.
121
77
 
122
- > **litedbmodel single-key advantage:** batch-loaded separate queries with a synchronous cache now edge out Drizzle's single-query LATERAL JOIN on single-key nested relations, while Drizzle retains the lead on composite-key nesting.
78
+ > **Nested relations** exercise 100 users → 1000 posts → 10000 comments (3-level, 250 iterations/ORM).
79
+ > litedbmodel issues a few batch-loaded queries + a sync cache; Drizzle issues one `LATERAL JOIN`. See
80
+ > the two `Nested relations` rows in the table above for the single-key and composite-key medians.
123
81
 
124
82
  ---
125
83
 
@@ -399,9 +357,9 @@ WHERE ( "tenant_id"=$1 AND "user_id"=$2
399
357
 
400
358
  ---
401
359
 
402
- ## Drizzle's Single-Query LATERAL JOIN (Composite Key)
360
+ ## Drizzle's Single-Query LATERAL JOIN
403
361
 
404
- Drizzle's **standard relation API** uses PostgreSQL's `LATERAL JOIN` with `json_agg()` to fetch all nested data in a single DB round-trip. This wins on **composite-key** nested relations (14.24ms), though litedbmodel's batch-loaded separate queries now edge it out on **single-key** nesting (12.18ms vs 19.34ms):
362
+ Drizzle's **standard relation API** uses PostgreSQL's `LATERAL JOIN` with `json_agg()` to fetch all nested data in a single DB round-trip — a different strategy from litedbmodel's few batch-loaded queries assembled through a sync cache. (Per-operation medians for both the single-key and composite-key nested cases are in the machine-generated table at the top of this document.)
405
363
 
406
364
  > **Note:** This is Drizzle's idiomatic approach via `db.query.*.findMany({ with: {...} })`. Other ORMs can achieve similar results with manual SQL, but Drizzle provides this as a built-in pattern.
407
365
 
@@ -540,10 +498,10 @@ WHERE (tenant_id, user_id) IN (($1,$2),($3,$4),...,($1999,$2000))
540
498
  | Scenario | Best Fit | Notes |
541
499
  |----------|----------|-------|
542
500
  | Write operations (transactions) | **litedbmodel** | Fastest in Create, Nested create, Nested update, Upsert, Create Many |
543
- | Bulk Update (diff values) | **litedbmodel** | **3.9x - 6.6x faster** than others (single query) |
544
- | Nested find all | **litedbmodel** | Fastest at 2.16ms |
545
- | Nested single key (speed) | **litedbmodel** | Fastest at 12.18ms (batch-loaded, beats LATERAL JOIN) |
546
- | Nested composite key (speed) | Drizzle | 14.24ms via LATERAL JOIN |
501
+ | Bulk Update (diff values) | **litedbmodel** | Fastest by a wide margin (single query) |
502
+ | Nested find all | **litedbmodel** | Fastest |
503
+ | Nested single key (speed) | **litedbmodel** | Fastest (batch-loaded queries + sync cache) |
504
+ | Nested composite key (speed) | **litedbmodel** | Fastest (see table) |
547
505
  | Nested relation SQL quality | **litedbmodel** | Readable + debuggable; stable query patterns (PG) |
548
506
  | Log Analysis / Monitoring | **litedbmodel** | Consistent query patterns |
549
507
  | SQL Fingerprint Stability (PG) | **litedbmodel** | Most predictable in prepared-statement setups |
@@ -553,13 +511,12 @@ WHERE (tenant_id, user_id) IN (($1,$2),($3,$4),...,($1999,$2000))
553
511
  **litedbmodel excels at:**
554
512
  - **Read operations** (Find all, Filter/paginate, Find unique, Nested find unique, Nested find all - all fastest)
555
513
  - **Write operations** (Create, Nested create, Nested update, Upsert, Create Many, Update Many - fastest)
556
- - **Nested relations, single key** (12.18ms - fastest, beats Drizzle's LATERAL JOIN)
557
- - **Bulk update with different values** (3.9x - 6.6x faster)
514
+ - **Nested relations** — fastest on both single-key and composite-key (batch-loaded queries + sync cache)
515
+ - **Bulk update with different values** — fastest by a wide margin (single query)
558
516
  - **Consistent performance** across all operations
559
517
  - **Data integrity** via required transactions
560
518
 
561
- **vs Prisma:** litedbmodel is **1.4x - 13.7x faster** across operations
562
- **vs Query Builders:** litedbmodel matches or beats Kysely/Drizzle in most operations
519
+ **vs Prisma / query builders:** litedbmodel matches or beats Kysely, Drizzle, TypeORM and Prisma in most operations — see the machine-generated table at the top for the exact per-operation medians.
563
520
 
564
521
  > **litedbmodel provides best-in-class performance with safety guarantees:**
565
522
  > - Type-safe column symbols (IDE refactoring)
@@ -2,6 +2,10 @@
2
2
 
3
3
  A detailed comparison of litedbmodel with popular TypeScript/JavaScript ORMs.
4
4
 
5
+ > **Benchmark figures:** litedbmodel **2.2.0**. The only performance number on this page is the
6
+ > machine-computed win count below; the full per-operation table lives in
7
+ > [BENCHMARK.md](./BENCHMARK.md) (regenerated from `benchmark/results/benchmark-results.csv`).
8
+
5
9
  ## Quick Comparison Matrix
6
10
 
7
11
  > Legend: ✅ built-in / automatic, ⚠️ possible but manual / opt-in / partial, ❌ not provided / not typical
@@ -1077,15 +1081,17 @@ For detailed benchmark results comparing litedbmodel with Prisma, Kysely, Drizzl
1077
1081
 
1078
1082
  ### Summary
1079
1083
 
1080
- | Operation Type | litedbmodel Performance |
1081
- |----------------|------------------------|
1082
- | Standard CRUD | **Fastest in 9/19 operations** (Filter/sort, Nested find all, Find unique, Nested find unique, Nested create, Delete, Upsert Many, Update Many, etc.) |
1083
- | Nested relations | Competitive (within 6% of fastest) |
1084
- | Deep nested (10K) | 3.3x faster than Prisma |
1085
- | SQL quality | ⭐⭐⭐⭐⭐ (readable, fixed params on PG) |
1084
+ <!--@embedoc:benchmark_summary-->
1085
+ litedbmodel is the fastest ORM in **14 of 19** benchmarked operations.
1086
+ <!--@embedoc:end-->
1087
+
1088
+ | Aspect | litedbmodel |
1089
+ |--------|-------------|
1090
+ | Reads & writes | Fastest across most CRUD operations |
1091
+ | Nested relations | Fastest on both single-key and composite-key |
1092
+ | SQL quality | Readable, fixed parameter count on PostgreSQL (`ANY($1::int[])`) |
1086
1093
 
1087
- **vs Prisma:** litedbmodel is **1.5x - 13.5x faster** across all operations
1088
- **vs Query Builders:** litedbmodel matches or beats Kysely/Drizzle in most operations
1094
+ This page keeps **no hand-copied numbers** — the win count above is machine-computed from the same CSV as [BENCHMARK.md](./BENCHMARK.md), where the full per-operation table (regenerated from `benchmark/results/benchmark-results.csv`) lives.
1089
1095
 
1090
1096
  ---
1091
1097
 
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 770 2110" font-family="system-ui, -apple-system, sans-serif">
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 770 2414" font-family="system-ui, -apple-system, sans-serif">
3
3
  <!-- White background -->
4
4
  <rect width="100%" height="100%" fill="white"/>
5
5
  <style>
@@ -24,257 +24,319 @@
24
24
  <!-- Chart area -->
25
25
  <g transform="translate(220, 60)">
26
26
  <!-- Grid lines -->
27
- <line x1="40" y1="0" x2="40" y2="1970" class="grid-line" />
28
- <text x="40" y="1985" text-anchor="middle" class="axis-label">0.5</text>
29
- <line x1="80" y1="0" x2="80" y2="1970" class="grid-line" />
30
- <text x="80" y="1985" text-anchor="middle" class="axis-label">1.0</text>
31
- <line x1="120" y1="0" x2="120" y2="1970" class="grid-line" />
32
- <text x="120" y="1985" text-anchor="middle" class="axis-label">1.5</text>
33
- <line x1="160" y1="0" x2="160" y2="1970" class="grid-line" />
34
- <text x="160" y="1985" text-anchor="middle" class="axis-label">2.0</text>
35
- <line x1="200" y1="0" x2="200" y2="1970" class="grid-line" />
36
- <text x="200" y="1985" text-anchor="middle" class="axis-label">2.5</text>
37
- <line x1="240" y1="0" x2="240" y2="1970" class="grid-line" />
38
- <text x="240" y="1985" text-anchor="middle" class="axis-label">3.0</text>
39
- <line x1="280" y1="0" x2="280" y2="1970" class="grid-line" />
40
- <text x="280" y="1985" text-anchor="middle" class="axis-label">3.5</text>
41
- <line x1="320" y1="0" x2="320" y2="1970" class="grid-line" />
42
- <text x="320" y="1985" text-anchor="middle" class="axis-label">4.0</text>
43
- <line x1="360" y1="0" x2="360" y2="1970" class="grid-line" />
44
- <text x="360" y="1985" text-anchor="middle" class="axis-label">4.5</text>
45
- <line x1="400" y1="0" x2="400" y2="1970" class="grid-line" />
46
- <text x="400" y="1985" text-anchor="middle" class="axis-label">5.0</text>
47
- <text x="405" y="1985" text-anchor="start" class="axis-label" fill="#dc2626">5+</text>
48
- <line x1="80" y1="-5" x2="80" y2="1975" class="baseline" />
49
- <text x="-10" y="40" text-anchor="end" dominant-baseline="middle" class="op-label">Find all (limit 100)</text>
50
- <rect x="0" y="0" width="80" height="12" fill="#3b82f6" rx="2" />
51
- <text x="85" y="7" dominant-baseline="middle" class="value-label">1.00x (0.48ms)</text>
52
- <rect x="0" y="16" width="91.66666666666667" height="12" fill="#22c55e" rx="2" />
53
- <text x="96.66666666666667" y="23" dominant-baseline="middle" class="value-label">1.15x (0.55ms)</text>
54
- <rect x="0" y="32" width="96.66666666666666" height="12" fill="#f59e0b" rx="2" />
55
- <text x="101.66666666666666" y="39" dominant-baseline="middle" class="value-label">1.21x (0.58ms)</text>
56
- <rect x="0" y="48" width="106.66666666666669" height="12" fill="#ef4444" rx="2" />
57
- <text x="111.66666666666669" y="55" dominant-baseline="middle" class="value-label">1.33x (0.64ms)</text>
58
- <rect x="0" y="64" width="161.66666666666666" height="12" fill="#8b5cf6" rx="2" />
59
- <text x="166.66666666666666" y="71" dominant-baseline="middle" class="value-label">2.02x (0.97ms)</text>
60
- <text x="-10" y="145" text-anchor="end" dominant-baseline="middle" class="op-label">Filter, paginate &amp; sort</text>
61
- <rect x="0" y="105" width="80" height="12" fill="#3b82f6" rx="2" />
62
- <text x="85" y="112" dominant-baseline="middle" class="value-label">1.00x (0.52ms)</text>
63
- <rect x="0" y="121" width="87.69230769230768" height="12" fill="#22c55e" rx="2" />
64
- <text x="92.69230769230768" y="128" dominant-baseline="middle" class="value-label">1.10x (0.57ms)</text>
65
- <rect x="0" y="137" width="92.3076923076923" height="12" fill="#f59e0b" rx="2" />
66
- <text x="97.3076923076923" y="144" dominant-baseline="middle" class="value-label">1.15x (0.60ms)</text>
67
- <rect x="0" y="153" width="98.46153846153847" height="12" fill="#ef4444" rx="2" />
68
- <text x="103.46153846153847" y="160" dominant-baseline="middle" class="value-label">1.23x (0.64ms)</text>
69
- <rect x="0" y="169" width="123.07692307692308" height="12" fill="#8b5cf6" rx="2" />
70
- <text x="128.0769230769231" y="176" dominant-baseline="middle" class="value-label">1.54x (0.80ms)</text>
71
- <text x="-10" y="250" text-anchor="end" dominant-baseline="middle" class="op-label">Nested find all (include posts)</text>
72
- <rect x="0" y="210" width="80" height="12" fill="#3b82f6" rx="2" />
73
- <text x="85" y="217" dominant-baseline="middle" class="value-label">1.00x (2.16ms)</text>
74
- <rect x="0" y="226" width="113.70370370370368" height="12" fill="#22c55e" rx="2" />
75
- <text x="118.70370370370368" y="233" dominant-baseline="middle" class="value-label">1.42x (3.07ms)</text>
76
- <rect x="0" y="242" width="161.85185185185182" height="12" fill="#f59e0b" rx="2" />
77
- <text x="166.85185185185182" y="249" dominant-baseline="middle" class="value-label">2.02x (4.37ms)</text>
78
- <rect x="0" y="258" width="218.5185185185185" height="12" fill="#ef4444" rx="2" />
79
- <text x="223.5185185185185" y="265" dominant-baseline="middle" class="value-label">2.73x (5.90ms)</text>
80
- <rect x="0" y="274" width="272.96296296296293" height="12" fill="#8b5cf6" rx="2" />
81
- <text x="277.96296296296293" y="281" dominant-baseline="middle" class="value-label">3.41x (7.37ms)</text>
82
- <text x="-10" y="355" text-anchor="end" dominant-baseline="middle" class="op-label">Find first</text>
83
- <rect x="0" y="315" width="80" height="12" fill="#3b82f6" rx="2" />
84
- <text x="85" y="322" dominant-baseline="middle" class="value-label">1.00x (0.31ms)</text>
85
- <rect x="0" y="331" width="82.58064516129032" height="12" fill="#22c55e" rx="2" />
86
- <text x="87.58064516129032" y="338" dominant-baseline="middle" class="value-label">1.03x (0.32ms)</text>
87
- <rect x="0" y="347" width="74.83870967741935" height="12" fill="#f59e0b" rx="2" />
88
- <text x="79.83870967741935" y="354" dominant-baseline="middle" class="value-label">0.94x (0.29ms)</text>
89
- <rect x="0" y="363" width="85.16129032258067" height="12" fill="#ef4444" rx="2" />
90
- <text x="90.16129032258067" y="370" dominant-baseline="middle" class="value-label">1.06x (0.33ms)</text>
91
- <rect x="0" y="379" width="126.4516129032258" height="12" fill="#8b5cf6" rx="2" />
92
- <text x="131.4516129032258" y="386" dominant-baseline="middle" class="value-label">1.58x (0.49ms)</text>
93
- <text x="-10" y="460" text-anchor="end" dominant-baseline="middle" class="op-label">Nested find first (include posts)</text>
94
- <rect x="0" y="420" width="80" height="12" fill="#3b82f6" rx="2" />
95
- <text x="85" y="427" dominant-baseline="middle" class="value-label">1.00x (0.51ms)</text>
96
- <rect x="0" y="436" width="80" height="12" fill="#22c55e" rx="2" />
97
- <text x="85" y="443" dominant-baseline="middle" class="value-label">1.00x (0.51ms)</text>
98
- <rect x="0" y="452" width="87.84313725490198" height="12" fill="#f59e0b" rx="2" />
99
- <text x="92.84313725490198" y="459" dominant-baseline="middle" class="value-label">1.10x (0.56ms)</text>
100
- <rect x="0" y="468" width="73.72549019607843" height="12" fill="#ef4444" rx="2" />
101
- <text x="78.72549019607843" y="475" dominant-baseline="middle" class="value-label">0.92x (0.47ms)</text>
102
- <rect x="0" y="484" width="116.078431372549" height="12" fill="#8b5cf6" rx="2" />
103
- <text x="121.078431372549" y="491" dominant-baseline="middle" class="value-label">1.45x (0.74ms)</text>
104
- <text x="-10" y="565" text-anchor="end" dominant-baseline="middle" class="op-label">Find unique (by email)</text>
105
- <rect x="0" y="525" width="80" height="12" fill="#3b82f6" rx="2" />
106
- <text x="85" y="532" dominant-baseline="middle" class="value-label">1.00x (0.27ms)</text>
107
- <rect x="0" y="541" width="80" height="12" fill="#22c55e" rx="2" />
108
- <text x="85" y="548" dominant-baseline="middle" class="value-label">1.00x (0.27ms)</text>
109
- <rect x="0" y="557" width="85.92592592592592" height="12" fill="#f59e0b" rx="2" />
110
- <text x="90.92592592592592" y="564" dominant-baseline="middle" class="value-label">1.07x (0.29ms)</text>
111
- <rect x="0" y="573" width="94.81481481481481" height="12" fill="#ef4444" rx="2" />
112
- <text x="99.81481481481481" y="580" dominant-baseline="middle" class="value-label">1.19x (0.32ms)</text>
113
- <rect x="0" y="589" width="130.37037037037035" height="12" fill="#8b5cf6" rx="2" />
114
- <text x="135.37037037037035" y="596" dominant-baseline="middle" class="value-label">1.63x (0.44ms)</text>
115
- <text x="-10" y="670" text-anchor="end" dominant-baseline="middle" class="op-label">Nested find unique (include posts)</text>
116
- <rect x="0" y="630" width="80" height="12" fill="#3b82f6" rx="2" />
117
- <text x="85" y="637" dominant-baseline="middle" class="value-label">1.00x (0.54ms)</text>
118
- <rect x="0" y="646" width="72.59259259259258" height="12" fill="#22c55e" rx="2" />
119
- <text x="77.59259259259258" y="653" dominant-baseline="middle" class="value-label">0.91x (0.49ms)</text>
120
- <rect x="0" y="662" width="80" height="12" fill="#f59e0b" rx="2" />
121
- <text x="85" y="669" dominant-baseline="middle" class="value-label">1.00x (0.54ms)</text>
122
- <rect x="0" y="678" width="143.7037037037037" height="12" fill="#ef4444" rx="2" />
123
- <text x="148.7037037037037" y="685" dominant-baseline="middle" class="value-label">1.80x (0.97ms)</text>
124
- <rect x="0" y="694" width="106.66666666666667" height="12" fill="#8b5cf6" rx="2" />
125
- <text x="111.66666666666667" y="701" dominant-baseline="middle" class="value-label">1.33x (0.72ms)</text>
126
- <text x="-10" y="775" text-anchor="end" dominant-baseline="middle" class="op-label">Create</text>
127
- <rect x="0" y="735" width="80" height="12" fill="#3b82f6" rx="2" />
128
- <text x="85" y="742" dominant-baseline="middle" class="value-label">1.00x (0.70ms)</text>
129
- <rect x="0" y="751" width="77.71428571428572" height="12" fill="#22c55e" rx="2" />
130
- <text x="82.71428571428572" y="758" dominant-baseline="middle" class="value-label">0.97x (0.68ms)</text>
131
- <rect x="0" y="767" width="81.14285714285714" height="12" fill="#f59e0b" rx="2" />
132
- <text x="86.14285714285714" y="774" dominant-baseline="middle" class="value-label">1.01x (0.71ms)</text>
133
- <rect x="0" y="783" width="86.85714285714286" height="12" fill="#ef4444" rx="2" />
134
- <text x="91.85714285714286" y="790" dominant-baseline="middle" class="value-label">1.09x (0.76ms)</text>
135
- <rect x="0" y="799" width="106.28571428571429" height="12" fill="#8b5cf6" rx="2" />
136
- <text x="111.28571428571429" y="806" dominant-baseline="middle" class="value-label">1.33x (0.93ms)</text>
137
- <text x="-10" y="880" text-anchor="end" dominant-baseline="middle" class="op-label">Nested create (with post)</text>
138
- <rect x="0" y="840" width="80" height="12" fill="#3b82f6" rx="2" />
139
- <text x="85" y="847" dominant-baseline="middle" class="value-label">1.00x (0.82ms)</text>
140
- <rect x="0" y="856" width="86.82926829268294" height="12" fill="#22c55e" rx="2" />
141
- <text x="91.82926829268294" y="863" dominant-baseline="middle" class="value-label">1.09x (0.89ms)</text>
142
- <rect x="0" y="872" width="88.78048780487806" height="12" fill="#f59e0b" rx="2" />
143
- <text x="93.78048780487806" y="879" dominant-baseline="middle" class="value-label">1.11x (0.91ms)</text>
144
- <rect x="0" y="888" width="106.34146341463415" height="12" fill="#ef4444" rx="2" />
145
- <text x="111.34146341463415" y="895" dominant-baseline="middle" class="value-label">1.33x (1.09ms)</text>
146
- <rect x="0" y="904" width="139.5121951219512" height="12" fill="#8b5cf6" rx="2" />
147
- <text x="144.5121951219512" y="911" dominant-baseline="middle" class="value-label">1.74x (1.43ms)</text>
148
- <text x="-10" y="985" text-anchor="end" dominant-baseline="middle" class="op-label">Update</text>
149
- <rect x="0" y="945" width="80" height="12" fill="#3b82f6" rx="2" />
150
- <text x="85" y="952" dominant-baseline="middle" class="value-label">1.00x (0.61ms)</text>
151
- <rect x="0" y="961" width="85.24590163934427" height="12" fill="#22c55e" rx="2" />
152
- <text x="90.24590163934427" y="968" dominant-baseline="middle" class="value-label">1.07x (0.65ms)</text>
153
- <rect x="0" y="977" width="86.55737704918035" height="12" fill="#f59e0b" rx="2" />
154
- <text x="91.55737704918035" y="984" dominant-baseline="middle" class="value-label">1.08x (0.66ms)</text>
155
- <rect x="0" y="993" width="97.04918032786885" height="12" fill="#ef4444" rx="2" />
156
- <text x="102.04918032786885" y="1000" dominant-baseline="middle" class="value-label">1.21x (0.74ms)</text>
157
- <rect x="0" y="1009" width="136.39344262295083" height="12" fill="#8b5cf6" rx="2" />
158
- <text x="141.39344262295083" y="1016" dominant-baseline="middle" class="value-label">1.70x (1.04ms)</text>
159
- <text x="-10" y="1090" text-anchor="end" dominant-baseline="middle" class="op-label">Nested update (update user + post)</text>
160
- <rect x="0" y="1050" width="80" height="12" fill="#3b82f6" rx="2" />
161
- <text x="85" y="1057" dominant-baseline="middle" class="value-label">1.00x (0.89ms)</text>
162
- <rect x="0" y="1066" width="85.39325842696628" height="12" fill="#22c55e" rx="2" />
163
- <text x="90.39325842696628" y="1073" dominant-baseline="middle" class="value-label">1.07x (0.95ms)</text>
164
- <rect x="0" y="1082" width="83.59550561797754" height="12" fill="#f59e0b" rx="2" />
165
- <text x="88.59550561797754" y="1089" dominant-baseline="middle" class="value-label">1.04x (0.93ms)</text>
166
- <rect x="0" y="1098" width="90.78651685393257" height="12" fill="#ef4444" rx="2" />
167
- <text x="95.78651685393257" y="1105" dominant-baseline="middle" class="value-label">1.13x (1.01ms)</text>
168
- <rect x="0" y="1114" width="186.06741573033705" height="12" fill="#8b5cf6" rx="2" />
169
- <text x="191.06741573033705" y="1121" dominant-baseline="middle" class="value-label">2.33x (2.07ms)</text>
170
- <text x="-10" y="1195" text-anchor="end" dominant-baseline="middle" class="op-label">Upsert</text>
171
- <rect x="0" y="1155" width="80" height="12" fill="#3b82f6" rx="2" />
172
- <text x="85" y="1162" dominant-baseline="middle" class="value-label">1.00x (0.65ms)</text>
173
- <rect x="0" y="1171" width="78.76923076923077" height="12" fill="#22c55e" rx="2" />
174
- <text x="83.76923076923077" y="1178" dominant-baseline="middle" class="value-label">0.98x (0.64ms)</text>
175
- <rect x="0" y="1187" width="86.15384615384615" height="12" fill="#f59e0b" rx="2" />
176
- <text x="91.15384615384615" y="1194" dominant-baseline="middle" class="value-label">1.08x (0.70ms)</text>
177
- <rect x="0" y="1203" width="89.84615384615384" height="12" fill="#ef4444" rx="2" />
178
- <text x="94.84615384615384" y="1210" dominant-baseline="middle" class="value-label">1.12x (0.73ms)</text>
179
- <rect x="0" y="1219" width="188.30769230769232" height="12" fill="#8b5cf6" rx="2" />
180
- <text x="193.30769230769232" y="1226" dominant-baseline="middle" class="value-label">2.35x (1.53ms)</text>
181
- <text x="-10" y="1300" text-anchor="end" dominant-baseline="middle" class="op-label">Nested upsert (user + post)</text>
182
- <rect x="0" y="1260" width="80" height="12" fill="#3b82f6" rx="2" />
183
- <text x="85" y="1267" dominant-baseline="middle" class="value-label">1.00x (0.85ms)</text>
184
- <rect x="0" y="1276" width="102.58823529411765" height="12" fill="#22c55e" rx="2" />
185
- <text x="107.58823529411765" y="1283" dominant-baseline="middle" class="value-label">1.28x (1.09ms)</text>
186
- <rect x="0" y="1292" width="102.58823529411765" height="12" fill="#f59e0b" rx="2" />
187
- <text x="107.58823529411765" y="1299" dominant-baseline="middle" class="value-label">1.28x (1.09ms)</text>
188
- <rect x="0" y="1308" width="103.5294117647059" height="12" fill="#ef4444" rx="2" />
189
- <text x="108.5294117647059" y="1315" dominant-baseline="middle" class="value-label">1.29x (1.10ms)</text>
190
- <rect x="0" y="1324" width="177.88235294117646" height="12" fill="#8b5cf6" rx="2" />
191
- <text x="182.88235294117646" y="1331" dominant-baseline="middle" class="value-label">2.22x (1.89ms)</text>
192
- <text x="-10" y="1405" text-anchor="end" dominant-baseline="middle" class="op-label">Delete</text>
193
- <rect x="0" y="1365" width="80" height="12" fill="#3b82f6" rx="2" />
194
- <text x="85" y="1372" dominant-baseline="middle" class="value-label">1.00x (0.83ms)</text>
195
- <rect x="0" y="1381" width="91.56626506024097" height="12" fill="#22c55e" rx="2" />
196
- <text x="96.56626506024097" y="1388" dominant-baseline="middle" class="value-label">1.14x (0.95ms)</text>
197
- <rect x="0" y="1397" width="93.49397590361447" height="12" fill="#f59e0b" rx="2" />
198
- <text x="98.49397590361447" y="1404" dominant-baseline="middle" class="value-label">1.17x (0.97ms)</text>
199
- <rect x="0" y="1413" width="104.09638554216869" height="12" fill="#ef4444" rx="2" />
200
- <text x="109.09638554216869" y="1420" dominant-baseline="middle" class="value-label">1.30x (1.08ms)</text>
201
- <rect x="0" y="1429" width="115.66265060240963" height="12" fill="#8b5cf6" rx="2" />
202
- <text x="120.66265060240963" y="1436" dominant-baseline="middle" class="value-label">1.45x (1.20ms)</text>
203
- <text x="-10" y="1510" text-anchor="end" dominant-baseline="middle" class="op-label">Create Many (10 records)</text>
204
- <rect x="0" y="1470" width="80" height="12" fill="#3b82f6" rx="2" />
205
- <text x="85" y="1477" dominant-baseline="middle" class="value-label">1.00x (0.72ms)</text>
206
- <rect x="0" y="1486" width="83.33333333333334" height="12" fill="#22c55e" rx="2" />
207
- <text x="88.33333333333334" y="1493" dominant-baseline="middle" class="value-label">1.04x (0.75ms)</text>
208
- <rect x="0" y="1502" width="96.66666666666669" height="12" fill="#f59e0b" rx="2" />
209
- <text x="101.66666666666669" y="1509" dominant-baseline="middle" class="value-label">1.21x (0.87ms)</text>
210
- <rect x="0" y="1518" width="103.33333333333334" height="12" fill="#ef4444" rx="2" />
211
- <text x="108.33333333333334" y="1525" dominant-baseline="middle" class="value-label">1.29x (0.93ms)</text>
212
- <rect x="0" y="1534" width="116.66666666666667" height="12" fill="#8b5cf6" rx="2" />
213
- <text x="121.66666666666667" y="1541" dominant-baseline="middle" class="value-label">1.46x (1.05ms)</text>
214
- <text x="-10" y="1615" text-anchor="end" dominant-baseline="middle" class="op-label">Upsert Many (10 records)</text>
215
- <rect x="0" y="1575" width="80" height="12" fill="#3b82f6" rx="2" />
216
- <text x="85" y="1582" dominant-baseline="middle" class="value-label">1.00x (0.76ms)</text>
217
- <rect x="0" y="1591" width="90.52631578947367" height="12" fill="#22c55e" rx="2" />
218
- <text x="95.52631578947367" y="1598" dominant-baseline="middle" class="value-label">1.13x (0.86ms)</text>
219
- <rect x="0" y="1607" width="113.68421052631578" height="12" fill="#f59e0b" rx="2" />
220
- <text x="118.68421052631578" y="1614" dominant-baseline="middle" class="value-label">1.42x (1.08ms)</text>
221
- <rect x="0" y="1623" width="114.73684210526316" height="12" fill="#ef4444" rx="2" />
222
- <text x="119.73684210526316" y="1630" dominant-baseline="middle" class="value-label">1.43x (1.09ms)</text>
223
- <rect x="0" y="1639" width="400" height="12" fill="#8b5cf6" rx="2" />
224
- <line x1="397" y1="1639" x2="400" y2="1651" class="overflow-line" />
225
- <line x1="394" y1="1639" x2="397" y2="1651" class="overflow-line" />
226
- <text x="405" y="1646" dominant-baseline="middle" class="value-overflow">⚠️ 13.08x (9.94ms)</text>
227
- <text x="-10" y="1720" text-anchor="end" dominant-baseline="middle" class="op-label">Update Many (10 different values)</text>
228
- <rect x="0" y="1680" width="80" height="12" fill="#3b82f6" rx="2" />
229
- <text x="85" y="1687" dominant-baseline="middle" class="value-label">1.00x (0.67ms)</text>
230
- <rect x="0" y="1696" width="325.9701492537313" height="12" fill="#22c55e" rx="2" />
231
- <text x="330.9701492537313" y="1703" dominant-baseline="middle" class="value-label">4.07x (2.73ms)</text>
232
- <rect x="0" y="1712" width="308.0597014925373" height="12" fill="#f59e0b" rx="2" />
233
- <text x="313.0597014925373" y="1719" dominant-baseline="middle" class="value-label">3.85x (2.58ms)</text>
234
- <rect x="0" y="1728" width="331.9402985074626" height="12" fill="#ef4444" rx="2" />
235
- <text x="336.9402985074626" y="1735" dominant-baseline="middle" class="value-label">4.15x (2.78ms)</text>
236
- <rect x="0" y="1744" width="400" height="12" fill="#8b5cf6" rx="2" />
237
- <line x1="397" y1="1744" x2="400" y2="1756" class="overflow-line" />
238
- <line x1="394" y1="1744" x2="397" y2="1756" class="overflow-line" />
239
- <text x="405" y="1751" dominant-baseline="middle" class="value-overflow">⚠️ 6.55x (4.39ms)</text>
240
- <text x="-10" y="1825" text-anchor="end" dominant-baseline="middle" class="op-label">Nested relations (100→1000→10000)</text>
241
- <rect x="0" y="1785" width="80" height="12" fill="#3b82f6" rx="2" />
242
- <text x="85" y="1792" dominant-baseline="middle" class="value-label">1.00x (12.18ms)</text>
243
- <rect x="0" y="1801" width="106.5353037766831" height="12" fill="#22c55e" rx="2" />
244
- <text x="111.5353037766831" y="1808" dominant-baseline="middle" class="value-label">1.33x (16.22ms)</text>
245
- <rect x="0" y="1817" width="127.0279146141215" height="12" fill="#f59e0b" rx="2" />
246
- <text x="132.0279146141215" y="1824" dominant-baseline="middle" class="value-label">1.59x (19.34ms)</text>
247
- <rect x="0" y="1833" width="360.7881773399015" height="12" fill="#ef4444" rx="2" />
248
- <text x="365.7881773399015" y="1840" dominant-baseline="middle" class="value-label">4.51x (54.93ms)</text>
249
- <rect x="0" y="1849" width="394.54844006568146" height="12" fill="#8b5cf6" rx="2" />
250
- <text x="399.54844006568146" y="1856" dominant-baseline="middle" class="value-label">4.93x (60.07ms)</text>
251
- <text x="-10" y="1930" text-anchor="end" dominant-baseline="middle" class="op-label">Nested relations (composite key, 5 tenants)</text>
252
- <rect x="0" y="1890" width="80" height="12" fill="#3b82f6" rx="2" />
253
- <text x="85" y="1897" dominant-baseline="middle" class="value-label">1.00x (14.62ms)</text>
254
- <text x="5" y="1913" dominant-baseline="middle" class="na-text">N/A</text>
255
- <rect x="0" y="1922" width="77.92065663474693" height="12" fill="#f59e0b" rx="2" />
256
- <text x="82.92065663474693" y="1929" dominant-baseline="middle" class="value-label">0.97x (14.24ms)</text>
257
- <rect x="0" y="1938" width="159.8358413132695" height="12" fill="#ef4444" rx="2" />
258
- <text x="164.8358413132695" y="1945" dominant-baseline="middle" class="value-label">2.00x (29.21ms)</text>
259
- <rect x="0" y="1954" width="400" height="12" fill="#8b5cf6" rx="2" />
260
- <line x1="397" y1="1954" x2="400" y2="1966" class="overflow-line" />
261
- <line x1="394" y1="1954" x2="397" y2="1966" class="overflow-line" />
262
- <text x="405" y="1961" dominant-baseline="middle" class="value-overflow">⚠️ 13.39x (195.74ms)</text>
27
+ <line x1="40" y1="0" x2="40" y2="2274" class="grid-line" />
28
+ <text x="40" y="2289" text-anchor="middle" class="axis-label">0.5</text>
29
+ <line x1="80" y1="0" x2="80" y2="2274" class="grid-line" />
30
+ <text x="80" y="2289" text-anchor="middle" class="axis-label">1.0</text>
31
+ <line x1="120" y1="0" x2="120" y2="2274" class="grid-line" />
32
+ <text x="120" y="2289" text-anchor="middle" class="axis-label">1.5</text>
33
+ <line x1="160" y1="0" x2="160" y2="2274" class="grid-line" />
34
+ <text x="160" y="2289" text-anchor="middle" class="axis-label">2.0</text>
35
+ <line x1="200" y1="0" x2="200" y2="2274" class="grid-line" />
36
+ <text x="200" y="2289" text-anchor="middle" class="axis-label">2.5</text>
37
+ <line x1="240" y1="0" x2="240" y2="2274" class="grid-line" />
38
+ <text x="240" y="2289" text-anchor="middle" class="axis-label">3.0</text>
39
+ <line x1="280" y1="0" x2="280" y2="2274" class="grid-line" />
40
+ <text x="280" y="2289" text-anchor="middle" class="axis-label">3.5</text>
41
+ <line x1="320" y1="0" x2="320" y2="2274" class="grid-line" />
42
+ <text x="320" y="2289" text-anchor="middle" class="axis-label">4.0</text>
43
+ <line x1="360" y1="0" x2="360" y2="2274" class="grid-line" />
44
+ <text x="360" y="2289" text-anchor="middle" class="axis-label">4.5</text>
45
+ <line x1="400" y1="0" x2="400" y2="2274" class="grid-line" />
46
+ <text x="400" y="2289" text-anchor="middle" class="axis-label">5.0</text>
47
+ <text x="405" y="2289" text-anchor="start" class="axis-label" fill="#dc2626">5+</text>
48
+ <line x1="80" y1="-5" x2="80" y2="2279" class="baseline" />
49
+ <text x="-10" y="48" text-anchor="end" dominant-baseline="middle" class="op-label">Find all (limit 100)</text>
50
+ <rect x="0" y="0" width="33.599999999999994" height="12" fill="#3b82f6" rx="2" />
51
+ <text x="38.599999999999994" y="7" dominant-baseline="middle" class="value-label">0.42x (0.42ms)</text>
52
+ <rect x="0" y="16" width="50.4" height="12" fill="#0ea5e9" rx="2" />
53
+ <text x="55.4" y="23" dominant-baseline="middle" class="value-label">0.63x (0.63ms)</text>
54
+ <rect x="0" y="32" width="46.4" height="12" fill="#22c55e" rx="2" />
55
+ <text x="51.4" y="39" dominant-baseline="middle" class="value-label">0.58x (0.58ms)</text>
56
+ <rect x="0" y="48" width="44.00000000000001" height="12" fill="#f59e0b" rx="2" />
57
+ <text x="49.00000000000001" y="55" dominant-baseline="middle" class="value-label">0.55x (0.55ms)</text>
58
+ <rect x="0" y="64" width="52.800000000000004" height="12" fill="#ef4444" rx="2" />
59
+ <text x="57.800000000000004" y="71" dominant-baseline="middle" class="value-label">0.66x (0.66ms)</text>
60
+ <rect x="0" y="80" width="90.39999999999999" height="12" fill="#8b5cf6" rx="2" />
61
+ <text x="95.39999999999999" y="87" dominant-baseline="middle" class="value-label">1.13x (1.13ms)</text>
62
+ <text x="-10" y="169" text-anchor="end" dominant-baseline="middle" class="op-label">Filter, paginate &amp; sort</text>
63
+ <rect x="0" y="121" width="52" height="12" fill="#3b82f6" rx="2" />
64
+ <text x="57" y="128" dominant-baseline="middle" class="value-label">0.65x (0.65ms)</text>
65
+ <rect x="0" y="137" width="45.599999999999994" height="12" fill="#0ea5e9" rx="2" />
66
+ <text x="50.599999999999994" y="144" dominant-baseline="middle" class="value-label">0.57x (0.57ms)</text>
67
+ <rect x="0" y="153" width="45.599999999999994" height="12" fill="#22c55e" rx="2" />
68
+ <text x="50.599999999999994" y="160" dominant-baseline="middle" class="value-label">0.57x (0.57ms)</text>
69
+ <rect x="0" y="169" width="65.6" height="12" fill="#f59e0b" rx="2" />
70
+ <text x="70.6" y="176" dominant-baseline="middle" class="value-label">0.82x (0.82ms)</text>
71
+ <rect x="0" y="185" width="72" height="12" fill="#ef4444" rx="2" />
72
+ <text x="77" y="192" dominant-baseline="middle" class="value-label">0.90x (0.90ms)</text>
73
+ <rect x="0" y="201" width="68.8" height="12" fill="#8b5cf6" rx="2" />
74
+ <text x="73.8" y="208" dominant-baseline="middle" class="value-label">0.86x (0.86ms)</text>
75
+ <text x="-10" y="290" text-anchor="end" dominant-baseline="middle" class="op-label">Nested find all (include posts)</text>
76
+ <rect x="0" y="242" width="191.20000000000002" height="12" fill="#3b82f6" rx="2" />
77
+ <text x="196.20000000000002" y="249" dominant-baseline="middle" class="value-label">2.39x (2.39ms)</text>
78
+ <rect x="0" y="258" width="177.60000000000002" height="12" fill="#0ea5e9" rx="2" />
79
+ <text x="182.60000000000002" y="265" dominant-baseline="middle" class="value-label">2.22x (2.22ms)</text>
80
+ <rect x="0" y="274" width="248" height="12" fill="#22c55e" rx="2" />
81
+ <text x="253" y="281" dominant-baseline="middle" class="value-label">3.10x (3.10ms)</text>
82
+ <rect x="0" y="290" width="238.39999999999998" height="12" fill="#f59e0b" rx="2" />
83
+ <text x="243.39999999999998" y="297" dominant-baseline="middle" class="value-label">2.98x (2.98ms)</text>
84
+ <rect x="0" y="306" width="400" height="12" fill="#ef4444" rx="2" />
85
+ <line x1="397" y1="306" x2="400" y2="318" class="overflow-line" />
86
+ <line x1="394" y1="306" x2="397" y2="318" class="overflow-line" />
87
+ <text x="405" y="313" dominant-baseline="middle" class="value-overflow">⚠️ 6.28x (6.28ms)</text>
88
+ <rect x="0" y="322" width="400" height="12" fill="#8b5cf6" rx="2" />
89
+ <line x1="397" y1="322" x2="400" y2="334" class="overflow-line" />
90
+ <line x1="394" y1="322" x2="397" y2="334" class="overflow-line" />
91
+ <text x="405" y="329" dominant-baseline="middle" class="value-overflow">⚠️ 9.62x (9.62ms)</text>
92
+ <text x="-10" y="411" text-anchor="end" dominant-baseline="middle" class="op-label">Find first</text>
93
+ <rect x="0" y="363" width="27.999999999999996" height="12" fill="#3b82f6" rx="2" />
94
+ <text x="33" y="370" dominant-baseline="middle" class="value-label">0.35x (0.35ms)</text>
95
+ <rect x="0" y="379" width="26.400000000000002" height="12" fill="#0ea5e9" rx="2" />
96
+ <text x="31.400000000000002" y="386" dominant-baseline="middle" class="value-label">0.33x (0.33ms)</text>
97
+ <rect x="0" y="395" width="24" height="12" fill="#22c55e" rx="2" />
98
+ <text x="29" y="402" dominant-baseline="middle" class="value-label">0.30x (0.30ms)</text>
99
+ <rect x="0" y="411" width="29.599999999999998" height="12" fill="#f59e0b" rx="2" />
100
+ <text x="34.599999999999994" y="418" dominant-baseline="middle" class="value-label">0.37x (0.37ms)</text>
101
+ <rect x="0" y="427" width="28.799999999999997" height="12" fill="#ef4444" rx="2" />
102
+ <text x="33.8" y="434" dominant-baseline="middle" class="value-label">0.36x (0.36ms)</text>
103
+ <rect x="0" y="443" width="41.6" height="12" fill="#8b5cf6" rx="2" />
104
+ <text x="46.6" y="450" dominant-baseline="middle" class="value-label">0.52x (0.52ms)</text>
105
+ <text x="-10" y="532" text-anchor="end" dominant-baseline="middle" class="op-label">Nested find first (include posts)</text>
106
+ <rect x="0" y="484" width="48.8" height="12" fill="#3b82f6" rx="2" />
107
+ <text x="53.8" y="491" dominant-baseline="middle" class="value-label">0.61x (0.61ms)</text>
108
+ <rect x="0" y="500" width="55.199999999999996" height="12" fill="#0ea5e9" rx="2" />
109
+ <text x="60.199999999999996" y="507" dominant-baseline="middle" class="value-label">0.69x (0.69ms)</text>
110
+ <rect x="0" y="516" width="49.6" height="12" fill="#22c55e" rx="2" />
111
+ <text x="54.6" y="523" dominant-baseline="middle" class="value-label">0.62x (0.62ms)</text>
112
+ <rect x="0" y="532" width="55.99999999999999" height="12" fill="#f59e0b" rx="2" />
113
+ <text x="60.99999999999999" y="539" dominant-baseline="middle" class="value-label">0.70x (0.70ms)</text>
114
+ <rect x="0" y="548" width="40.800000000000004" height="12" fill="#ef4444" rx="2" />
115
+ <text x="45.800000000000004" y="555" dominant-baseline="middle" class="value-label">0.51x (0.51ms)</text>
116
+ <rect x="0" y="564" width="80" height="12" fill="#8b5cf6" rx="2" />
117
+ <text x="85" y="571" dominant-baseline="middle" class="value-label">1.00x (1.00ms)</text>
118
+ <text x="-10" y="653" text-anchor="end" dominant-baseline="middle" class="op-label">Find unique (by email)</text>
119
+ <rect x="0" y="605" width="41.6" height="12" fill="#3b82f6" rx="2" />
120
+ <text x="46.6" y="612" dominant-baseline="middle" class="value-label">0.52x (0.52ms)</text>
121
+ <rect x="0" y="621" width="26.400000000000002" height="12" fill="#0ea5e9" rx="2" />
122
+ <text x="31.400000000000002" y="628" dominant-baseline="middle" class="value-label">0.33x (0.33ms)</text>
123
+ <rect x="0" y="637" width="23.2" height="12" fill="#22c55e" rx="2" />
124
+ <text x="28.2" y="644" dominant-baseline="middle" class="value-label">0.29x (0.29ms)</text>
125
+ <rect x="0" y="653" width="32" height="12" fill="#f59e0b" rx="2" />
126
+ <text x="37" y="660" dominant-baseline="middle" class="value-label">0.40x (0.40ms)</text>
127
+ <rect x="0" y="669" width="35.199999999999996" height="12" fill="#ef4444" rx="2" />
128
+ <text x="40.199999999999996" y="676" dominant-baseline="middle" class="value-label">0.44x (0.44ms)</text>
129
+ <rect x="0" y="685" width="40.800000000000004" height="12" fill="#8b5cf6" rx="2" />
130
+ <text x="45.800000000000004" y="692" dominant-baseline="middle" class="value-label">0.51x (0.51ms)</text>
131
+ <text x="-10" y="774" text-anchor="end" dominant-baseline="middle" class="op-label">Nested find unique (include posts)</text>
132
+ <rect x="0" y="726" width="60.8" height="12" fill="#3b82f6" rx="2" />
133
+ <text x="65.8" y="733" dominant-baseline="middle" class="value-label">0.76x (0.76ms)</text>
134
+ <rect x="0" y="742" width="64.8" height="12" fill="#0ea5e9" rx="2" />
135
+ <text x="69.8" y="749" dominant-baseline="middle" class="value-label">0.81x (0.81ms)</text>
136
+ <rect x="0" y="758" width="54.400000000000006" height="12" fill="#22c55e" rx="2" />
137
+ <text x="59.400000000000006" y="765" dominant-baseline="middle" class="value-label">0.68x (0.68ms)</text>
138
+ <rect x="0" y="774" width="85.60000000000001" height="12" fill="#f59e0b" rx="2" />
139
+ <text x="90.60000000000001" y="781" dominant-baseline="middle" class="value-label">1.07x (1.07ms)</text>
140
+ <rect x="0" y="790" width="83.2" height="12" fill="#ef4444" rx="2" />
141
+ <text x="88.2" y="797" dominant-baseline="middle" class="value-label">1.04x (1.04ms)</text>
142
+ <rect x="0" y="806" width="75.2" height="12" fill="#8b5cf6" rx="2" />
143
+ <text x="80.2" y="813" dominant-baseline="middle" class="value-label">0.94x (0.94ms)</text>
144
+ <text x="-10" y="895" text-anchor="end" dominant-baseline="middle" class="op-label">Create</text>
145
+ <rect x="0" y="847" width="61.6" height="12" fill="#3b82f6" rx="2" />
146
+ <text x="66.6" y="854" dominant-baseline="middle" class="value-label">0.77x (0.77ms)</text>
147
+ <rect x="0" y="863" width="31.2" height="12" fill="#0ea5e9" rx="2" />
148
+ <text x="36.2" y="870" dominant-baseline="middle" class="value-label">0.39x (0.39ms)</text>
149
+ <rect x="0" y="879" width="64" height="12" fill="#22c55e" rx="2" />
150
+ <text x="69" y="886" dominant-baseline="middle" class="value-label">0.80x (0.80ms)</text>
151
+ <rect x="0" y="895" width="74.4" height="12" fill="#f59e0b" rx="2" />
152
+ <text x="79.4" y="902" dominant-baseline="middle" class="value-label">0.93x (0.93ms)</text>
153
+ <rect x="0" y="911" width="68" height="12" fill="#ef4444" rx="2" />
154
+ <text x="73" y="918" dominant-baseline="middle" class="value-label">0.85x (0.85ms)</text>
155
+ <rect x="0" y="927" width="91.19999999999999" height="12" fill="#8b5cf6" rx="2" />
156
+ <text x="96.19999999999999" y="934" dominant-baseline="middle" class="value-label">1.14x (1.14ms)</text>
157
+ <text x="-10" y="1016" text-anchor="end" dominant-baseline="middle" class="op-label">Nested create (with post)</text>
158
+ <rect x="0" y="968" width="87.20000000000002" height="12" fill="#3b82f6" rx="2" />
159
+ <text x="92.20000000000002" y="975" dominant-baseline="middle" class="value-label">1.09x (1.09ms)</text>
160
+ <rect x="0" y="984" width="78.4" height="12" fill="#0ea5e9" rx="2" />
161
+ <text x="83.4" y="991" dominant-baseline="middle" class="value-label">0.98x (0.98ms)</text>
162
+ <rect x="0" y="1000" width="83.2" height="12" fill="#22c55e" rx="2" />
163
+ <text x="88.2" y="1007" dominant-baseline="middle" class="value-label">1.04x (1.04ms)</text>
164
+ <rect x="0" y="1016" width="93.6" height="12" fill="#f59e0b" rx="2" />
165
+ <text x="98.6" y="1023" dominant-baseline="middle" class="value-label">1.17x (1.17ms)</text>
166
+ <rect x="0" y="1032" width="100.8" height="12" fill="#ef4444" rx="2" />
167
+ <text x="105.8" y="1039" dominant-baseline="middle" class="value-label">1.26x (1.26ms)</text>
168
+ <rect x="0" y="1048" width="136" height="12" fill="#8b5cf6" rx="2" />
169
+ <text x="141" y="1055" dominant-baseline="middle" class="value-label">1.70x (1.70ms)</text>
170
+ <text x="-10" y="1137" text-anchor="end" dominant-baseline="middle" class="op-label">Update</text>
171
+ <rect x="0" y="1089" width="65.6" height="12" fill="#3b82f6" rx="2" />
172
+ <text x="70.6" y="1096" dominant-baseline="middle" class="value-label">0.82x (0.82ms)</text>
173
+ <rect x="0" y="1105" width="41.6" height="12" fill="#0ea5e9" rx="2" />
174
+ <text x="46.6" y="1112" dominant-baseline="middle" class="value-label">0.52x (0.52ms)</text>
175
+ <rect x="0" y="1121" width="53.6" height="12" fill="#22c55e" rx="2" />
176
+ <text x="58.6" y="1128" dominant-baseline="middle" class="value-label">0.67x (0.67ms)</text>
177
+ <rect x="0" y="1137" width="58.4" height="12" fill="#f59e0b" rx="2" />
178
+ <text x="63.4" y="1144" dominant-baseline="middle" class="value-label">0.73x (0.73ms)</text>
179
+ <rect x="0" y="1153" width="58.4" height="12" fill="#ef4444" rx="2" />
180
+ <text x="63.4" y="1160" dominant-baseline="middle" class="value-label">0.73x (0.73ms)</text>
181
+ <rect x="0" y="1169" width="92" height="12" fill="#8b5cf6" rx="2" />
182
+ <text x="97" y="1176" dominant-baseline="middle" class="value-label">1.15x (1.15ms)</text>
183
+ <text x="-10" y="1258" text-anchor="end" dominant-baseline="middle" class="op-label">Nested update (update user + post)</text>
184
+ <rect x="0" y="1210" width="76" height="12" fill="#3b82f6" rx="2" />
185
+ <text x="81" y="1217" dominant-baseline="middle" class="value-label">0.95x (0.95ms)</text>
186
+ <rect x="0" y="1226" width="76.8" height="12" fill="#0ea5e9" rx="2" />
187
+ <text x="81.8" y="1233" dominant-baseline="middle" class="value-label">0.96x (0.96ms)</text>
188
+ <rect x="0" y="1242" width="72" height="12" fill="#22c55e" rx="2" />
189
+ <text x="77" y="1249" dominant-baseline="middle" class="value-label">0.90x (0.90ms)</text>
190
+ <rect x="0" y="1258" width="84.00000000000001" height="12" fill="#f59e0b" rx="2" />
191
+ <text x="89.00000000000001" y="1265" dominant-baseline="middle" class="value-label">1.05x (1.05ms)</text>
192
+ <rect x="0" y="1274" width="79.2" height="12" fill="#ef4444" rx="2" />
193
+ <text x="84.2" y="1281" dominant-baseline="middle" class="value-label">0.99x (0.99ms)</text>
194
+ <rect x="0" y="1290" width="172" height="12" fill="#8b5cf6" rx="2" />
195
+ <text x="177" y="1297" dominant-baseline="middle" class="value-label">2.15x (2.15ms)</text>
196
+ <text x="-10" y="1379" text-anchor="end" dominant-baseline="middle" class="op-label">Upsert</text>
197
+ <rect x="0" y="1331" width="60.8" height="12" fill="#3b82f6" rx="2" />
198
+ <text x="65.8" y="1338" dominant-baseline="middle" class="value-label">0.76x (0.76ms)</text>
199
+ <rect x="0" y="1347" width="35.199999999999996" height="12" fill="#0ea5e9" rx="2" />
200
+ <text x="40.199999999999996" y="1354" dominant-baseline="middle" class="value-label">0.44x (0.44ms)</text>
201
+ <rect x="0" y="1363" width="57.599999999999994" height="12" fill="#22c55e" rx="2" />
202
+ <text x="62.599999999999994" y="1370" dominant-baseline="middle" class="value-label">0.72x (0.72ms)</text>
203
+ <rect x="0" y="1379" width="59.199999999999996" height="12" fill="#f59e0b" rx="2" />
204
+ <text x="64.19999999999999" y="1386" dominant-baseline="middle" class="value-label">0.74x (0.74ms)</text>
205
+ <rect x="0" y="1395" width="74.4" height="12" fill="#ef4444" rx="2" />
206
+ <text x="79.4" y="1402" dominant-baseline="middle" class="value-label">0.93x (0.93ms)</text>
207
+ <rect x="0" y="1411" width="140" height="12" fill="#8b5cf6" rx="2" />
208
+ <text x="145" y="1418" dominant-baseline="middle" class="value-label">1.75x (1.75ms)</text>
209
+ <text x="-10" y="1500" text-anchor="end" dominant-baseline="middle" class="op-label">Nested upsert (user + post)</text>
210
+ <rect x="0" y="1452" width="103.2" height="12" fill="#3b82f6" rx="2" />
211
+ <text x="108.2" y="1459" dominant-baseline="middle" class="value-label">1.29x (1.29ms)</text>
212
+ <rect x="0" y="1468" width="79.2" height="12" fill="#0ea5e9" rx="2" />
213
+ <text x="84.2" y="1475" dominant-baseline="middle" class="value-label">0.99x (0.99ms)</text>
214
+ <rect x="0" y="1484" width="89.60000000000001" height="12" fill="#22c55e" rx="2" />
215
+ <text x="94.60000000000001" y="1491" dominant-baseline="middle" class="value-label">1.12x (1.12ms)</text>
216
+ <rect x="0" y="1500" width="99.2" height="12" fill="#f59e0b" rx="2" />
217
+ <text x="104.2" y="1507" dominant-baseline="middle" class="value-label">1.24x (1.24ms)</text>
218
+ <rect x="0" y="1516" width="105.60000000000001" height="12" fill="#ef4444" rx="2" />
219
+ <text x="110.60000000000001" y="1523" dominant-baseline="middle" class="value-label">1.32x (1.32ms)</text>
220
+ <rect x="0" y="1532" width="161.60000000000002" height="12" fill="#8b5cf6" rx="2" />
221
+ <text x="166.60000000000002" y="1539" dominant-baseline="middle" class="value-label">2.02x (2.02ms)</text>
222
+ <text x="-10" y="1621" text-anchor="end" dominant-baseline="middle" class="op-label">Delete</text>
223
+ <rect x="0" y="1573" width="83.2" height="12" fill="#3b82f6" rx="2" />
224
+ <text x="88.2" y="1580" dominant-baseline="middle" class="value-label">1.04x (1.04ms)</text>
225
+ <rect x="0" y="1589" width="80.80000000000001" height="12" fill="#0ea5e9" rx="2" />
226
+ <text x="85.80000000000001" y="1596" dominant-baseline="middle" class="value-label">1.01x (1.01ms)</text>
227
+ <rect x="0" y="1605" width="83.2" height="12" fill="#22c55e" rx="2" />
228
+ <text x="88.2" y="1612" dominant-baseline="middle" class="value-label">1.04x (1.04ms)</text>
229
+ <rect x="0" y="1621" width="87.20000000000002" height="12" fill="#f59e0b" rx="2" />
230
+ <text x="92.20000000000002" y="1628" dominant-baseline="middle" class="value-label">1.09x (1.09ms)</text>
231
+ <rect x="0" y="1637" width="103.2" height="12" fill="#ef4444" rx="2" />
232
+ <text x="108.2" y="1644" dominant-baseline="middle" class="value-label">1.29x (1.29ms)</text>
233
+ <rect x="0" y="1653" width="121.6" height="12" fill="#8b5cf6" rx="2" />
234
+ <text x="126.6" y="1660" dominant-baseline="middle" class="value-label">1.52x (1.52ms)</text>
235
+ <text x="-10" y="1742" text-anchor="end" dominant-baseline="middle" class="op-label">Create Many (10 records)</text>
236
+ <rect x="0" y="1694" width="68" height="12" fill="#3b82f6" rx="2" />
237
+ <text x="73" y="1701" dominant-baseline="middle" class="value-label">0.85x (0.85ms)</text>
238
+ <rect x="0" y="1710" width="32.8" height="12" fill="#0ea5e9" rx="2" />
239
+ <text x="37.8" y="1717" dominant-baseline="middle" class="value-label">0.41x (0.41ms)</text>
240
+ <rect x="0" y="1726" width="70.39999999999999" height="12" fill="#22c55e" rx="2" />
241
+ <text x="75.39999999999999" y="1733" dominant-baseline="middle" class="value-label">0.88x (0.88ms)</text>
242
+ <rect x="0" y="1742" width="96" height="12" fill="#f59e0b" rx="2" />
243
+ <text x="101" y="1749" dominant-baseline="middle" class="value-label">1.20x (1.20ms)</text>
244
+ <rect x="0" y="1758" width="81.60000000000001" height="12" fill="#ef4444" rx="2" />
245
+ <text x="86.60000000000001" y="1765" dominant-baseline="middle" class="value-label">1.02x (1.02ms)</text>
246
+ <rect x="0" y="1774" width="96" height="12" fill="#8b5cf6" rx="2" />
247
+ <text x="101" y="1781" dominant-baseline="middle" class="value-label">1.20x (1.20ms)</text>
248
+ <text x="-10" y="1863" text-anchor="end" dominant-baseline="middle" class="op-label">Upsert Many (10 records)</text>
249
+ <rect x="0" y="1815" width="102.4" height="12" fill="#3b82f6" rx="2" />
250
+ <text x="107.4" y="1822" dominant-baseline="middle" class="value-label">1.28x (1.28ms)</text>
251
+ <rect x="0" y="1831" width="36.8" height="12" fill="#0ea5e9" rx="2" />
252
+ <text x="41.8" y="1838" dominant-baseline="middle" class="value-label">0.46x (0.46ms)</text>
253
+ <rect x="0" y="1847" width="61.6" height="12" fill="#22c55e" rx="2" />
254
+ <text x="66.6" y="1854" dominant-baseline="middle" class="value-label">0.77x (0.77ms)</text>
255
+ <rect x="0" y="1863" width="110.39999999999999" height="12" fill="#f59e0b" rx="2" />
256
+ <text x="115.39999999999999" y="1870" dominant-baseline="middle" class="value-label">1.38x (1.38ms)</text>
257
+ <rect x="0" y="1879" width="88.00000000000001" height="12" fill="#ef4444" rx="2" />
258
+ <text x="93.00000000000001" y="1886" dominant-baseline="middle" class="value-label">1.10x (1.10ms)</text>
259
+ <rect x="0" y="1895" width="400" height="12" fill="#8b5cf6" rx="2" />
260
+ <line x1="397" y1="1895" x2="400" y2="1907" class="overflow-line" />
261
+ <line x1="394" y1="1895" x2="397" y2="1907" class="overflow-line" />
262
+ <text x="405" y="1902" dominant-baseline="middle" class="value-overflow">⚠️ 9.75x (9.75ms)</text>
263
+ <text x="-10" y="1984" text-anchor="end" dominant-baseline="middle" class="op-label">Update Many (10 different values)</text>
264
+ <rect x="0" y="1936" width="89.60000000000001" height="12" fill="#3b82f6" rx="2" />
265
+ <text x="94.60000000000001" y="1943" dominant-baseline="middle" class="value-label">1.12x (1.12ms)</text>
266
+ <rect x="0" y="1952" width="37.6" height="12" fill="#0ea5e9" rx="2" />
267
+ <text x="42.6" y="1959" dominant-baseline="middle" class="value-label">0.47x (0.47ms)</text>
268
+ <rect x="0" y="1968" width="193.6" height="12" fill="#22c55e" rx="2" />
269
+ <text x="198.6" y="1975" dominant-baseline="middle" class="value-label">2.42x (2.42ms)</text>
270
+ <rect x="0" y="1984" width="193.6" height="12" fill="#f59e0b" rx="2" />
271
+ <text x="198.6" y="1991" dominant-baseline="middle" class="value-label">2.42x (2.42ms)</text>
272
+ <rect x="0" y="2000" width="199.20000000000002" height="12" fill="#ef4444" rx="2" />
273
+ <text x="204.20000000000002" y="2007" dominant-baseline="middle" class="value-label">2.49x (2.49ms)</text>
274
+ <rect x="0" y="2016" width="392.8" height="12" fill="#8b5cf6" rx="2" />
275
+ <text x="397.8" y="2023" dominant-baseline="middle" class="value-label">4.91x (4.91ms)</text>
276
+ <text x="-10" y="2105" text-anchor="end" dominant-baseline="middle" class="op-label">Nested relations (100→1000→10000)</text>
277
+ <rect x="0" y="2057" width="400" height="12" fill="#3b82f6" rx="2" />
278
+ <line x1="397" y1="2057" x2="400" y2="2069" class="overflow-line" />
279
+ <line x1="394" y1="2057" x2="397" y2="2069" class="overflow-line" />
280
+ <text x="405" y="2064" dominant-baseline="middle" class="value-overflow">⚠️ 14.43x (14.43ms)</text>
281
+ <rect x="0" y="2073" width="400" height="12" fill="#0ea5e9" rx="2" />
282
+ <line x1="397" y1="2073" x2="400" y2="2085" class="overflow-line" />
283
+ <line x1="394" y1="2073" x2="397" y2="2085" class="overflow-line" />
284
+ <text x="405" y="2080" dominant-baseline="middle" class="value-overflow">⚠️ 18.46x (18.46ms)</text>
285
+ <rect x="0" y="2089" width="400" height="12" fill="#22c55e" rx="2" />
286
+ <line x1="397" y1="2089" x2="400" y2="2101" class="overflow-line" />
287
+ <line x1="394" y1="2089" x2="397" y2="2101" class="overflow-line" />
288
+ <text x="405" y="2096" dominant-baseline="middle" class="value-overflow">⚠️ 21.11x (21.11ms)</text>
289
+ <rect x="0" y="2105" width="400" height="12" fill="#f59e0b" rx="2" />
290
+ <line x1="397" y1="2105" x2="400" y2="2117" class="overflow-line" />
291
+ <line x1="394" y1="2105" x2="397" y2="2117" class="overflow-line" />
292
+ <text x="405" y="2112" dominant-baseline="middle" class="value-overflow">⚠️ 20.33x (20.33ms)</text>
293
+ <rect x="0" y="2121" width="400" height="12" fill="#ef4444" rx="2" />
294
+ <line x1="397" y1="2121" x2="400" y2="2133" class="overflow-line" />
295
+ <line x1="394" y1="2121" x2="397" y2="2133" class="overflow-line" />
296
+ <text x="405" y="2128" dominant-baseline="middle" class="value-overflow">⚠️ 74.04x (74.04ms)</text>
297
+ <rect x="0" y="2137" width="400" height="12" fill="#8b5cf6" rx="2" />
298
+ <line x1="397" y1="2137" x2="400" y2="2149" class="overflow-line" />
299
+ <line x1="394" y1="2137" x2="397" y2="2149" class="overflow-line" />
300
+ <text x="405" y="2144" dominant-baseline="middle" class="value-overflow">⚠️ 79.61x (79.61ms)</text>
301
+ <text x="-10" y="2226" text-anchor="end" dominant-baseline="middle" class="op-label">Nested relations (composite key)</text>
302
+ <rect x="0" y="2178" width="400" height="12" fill="#3b82f6" rx="2" />
303
+ <line x1="397" y1="2178" x2="400" y2="2190" class="overflow-line" />
304
+ <line x1="394" y1="2178" x2="397" y2="2190" class="overflow-line" />
305
+ <text x="405" y="2185" dominant-baseline="middle" class="value-overflow">⚠️ 27.52x (27.52ms)</text>
306
+ <rect x="0" y="2194" width="400" height="12" fill="#0ea5e9" rx="2" />
307
+ <line x1="397" y1="2194" x2="400" y2="2206" class="overflow-line" />
308
+ <line x1="394" y1="2194" x2="397" y2="2206" class="overflow-line" />
309
+ <text x="405" y="2201" dominant-baseline="middle" class="value-overflow">⚠️ 23.97x (23.97ms)</text>
310
+ <text x="5" y="2217" dominant-baseline="middle" class="na-text">N/A</text>
311
+ <rect x="0" y="2226" width="400" height="12" fill="#f59e0b" rx="2" />
312
+ <line x1="397" y1="2226" x2="400" y2="2238" class="overflow-line" />
313
+ <line x1="394" y1="2226" x2="397" y2="2238" class="overflow-line" />
314
+ <text x="405" y="2233" dominant-baseline="middle" class="value-overflow">⚠️ 74.39x (74.39ms)</text>
315
+ <rect x="0" y="2242" width="400" height="12" fill="#ef4444" rx="2" />
316
+ <line x1="397" y1="2242" x2="400" y2="2254" class="overflow-line" />
317
+ <line x1="394" y1="2242" x2="397" y2="2254" class="overflow-line" />
318
+ <text x="405" y="2249" dominant-baseline="middle" class="value-overflow">⚠️ 57.46x (57.46ms)</text>
319
+ <rect x="0" y="2258" width="400" height="12" fill="#8b5cf6" rx="2" />
320
+ <line x1="397" y1="2258" x2="400" y2="2270" class="overflow-line" />
321
+ <line x1="394" y1="2258" x2="397" y2="2270" class="overflow-line" />
322
+ <text x="405" y="2265" dominant-baseline="middle" class="value-overflow">⚠️ 83.78x (83.78ms)</text>
263
323
  </g>
264
324
 
265
325
  <!-- Legend -->
266
326
  <g transform="translate(640, 60)">
267
327
  <rect x="0" y="0" width="14" height="14" fill="#3b82f6" rx="2" />
268
- <text x="20" y="11" class="legend-text">litedbmodel</text>
269
- <rect x="0" y="20" width="14" height="14" fill="#22c55e" rx="2" />
270
- <text x="20" y="31" class="legend-text">Kysely</text>
271
- <rect x="0" y="40" width="14" height="14" fill="#f59e0b" rx="2" />
272
- <text x="20" y="51" class="legend-text">Drizzle</text>
273
- <rect x="0" y="60" width="14" height="14" fill="#ef4444" rx="2" />
274
- <text x="20" y="71" class="legend-text">TypeORM</text>
275
- <rect x="0" y="80" width="14" height="14" fill="#8b5cf6" rx="2" />
276
- <text x="20" y="91" class="legend-text">Prisma</text>
277
- <line x1="0" y1="110" x2="14" y2="110" class="overflow-line" />
278
- <text x="20" y="114" class="legend-text" fill="#dc2626">&gt;5x (truncated)</text>
328
+ <text x="20" y="11" class="legend-text">litedbmodel (runtime)</text>
329
+ <rect x="0" y="20" width="14" height="14" fill="#0ea5e9" rx="2" />
330
+ <text x="20" y="31" class="legend-text">litedbmodel (codegen)</text>
331
+ <rect x="0" y="40" width="14" height="14" fill="#22c55e" rx="2" />
332
+ <text x="20" y="51" class="legend-text">Kysely</text>
333
+ <rect x="0" y="60" width="14" height="14" fill="#f59e0b" rx="2" />
334
+ <text x="20" y="71" class="legend-text">Drizzle</text>
335
+ <rect x="0" y="80" width="14" height="14" fill="#ef4444" rx="2" />
336
+ <text x="20" y="91" class="legend-text">TypeORM</text>
337
+ <rect x="0" y="100" width="14" height="14" fill="#8b5cf6" rx="2" />
338
+ <text x="20" y="111" class="legend-text">Prisma</text>
339
+ <line x1="0" y1="130" x2="14" y2="130" class="overflow-line" />
340
+ <text x="20" y="134" class="legend-text" fill="#dc2626">&gt;5x (truncated)</text>
279
341
  </g>
280
342
  </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litedbmodel",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "A lightweight TypeScript ORM for PostgreSQL, MySQL, and SQLite with Active Record pattern",
5
5
  "main": "dist/index.cjs",
6
6
  "types": "dist/index.d.ts",