@metriport/fhir-sdk 1.2.6 → 1.3.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 (84) hide show
  1. package/README.md +207 -0
  2. package/dist/__tests__/date-range-performance.test.d.ts +2 -0
  3. package/dist/__tests__/date-range-performance.test.d.ts.map +1 -0
  4. package/dist/__tests__/date-range-performance.test.js +218 -0
  5. package/dist/__tests__/date-range-performance.test.js.map +1 -0
  6. package/dist/__tests__/date-range-search.test.d.ts +2 -0
  7. package/dist/__tests__/date-range-search.test.d.ts.map +1 -0
  8. package/dist/__tests__/date-range-search.test.js +215 -0
  9. package/dist/__tests__/date-range-search.test.js.map +1 -0
  10. package/dist/__tests__/fhir-bundle-sdk.test.js +467 -0
  11. package/dist/__tests__/fhir-bundle-sdk.test.js.map +1 -1
  12. package/dist/__tests__/reverse-references.test.d.ts +2 -0
  13. package/dist/__tests__/reverse-references.test.d.ts.map +1 -0
  14. package/dist/__tests__/reverse-references.test.js +241 -0
  15. package/dist/__tests__/reverse-references.test.js.map +1 -0
  16. package/dist/demo-reverse-references.d.ts +7 -0
  17. package/dist/demo-reverse-references.d.ts.map +1 -0
  18. package/dist/demo-reverse-references.js +207 -0
  19. package/dist/demo-reverse-references.js.map +1 -0
  20. package/dist/fhir-bundle-sdk.d.ts +222 -0
  21. package/dist/fhir-bundle-sdk.d.ts.map +1 -0
  22. package/dist/fhir-bundle-sdk.js +527 -0
  23. package/dist/fhir-bundle-sdk.js.map +1 -0
  24. package/dist/index.d.ts +2 -242
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -677
  27. package/dist/index.js.map +1 -1
  28. package/dist/internal/bundle-operations.d.ts +14 -0
  29. package/dist/internal/bundle-operations.d.ts.map +1 -0
  30. package/dist/internal/bundle-operations.js +55 -0
  31. package/dist/internal/bundle-operations.js.map +1 -0
  32. package/dist/internal/date-extraction.d.ts +12 -0
  33. package/dist/internal/date-extraction.d.ts.map +1 -0
  34. package/dist/internal/date-extraction.js +206 -0
  35. package/dist/internal/date-extraction.js.map +1 -0
  36. package/dist/internal/graph-traversal.d.ts +13 -0
  37. package/dist/internal/graph-traversal.d.ts.map +1 -0
  38. package/dist/internal/graph-traversal.js +89 -0
  39. package/dist/internal/graph-traversal.js.map +1 -0
  40. package/dist/internal/indexing.d.ts +17 -0
  41. package/dist/internal/indexing.d.ts.map +1 -0
  42. package/dist/internal/indexing.js +118 -0
  43. package/dist/internal/indexing.js.map +1 -0
  44. package/dist/internal/llm-context.d.ts +39 -0
  45. package/dist/internal/llm-context.d.ts.map +1 -0
  46. package/dist/internal/llm-context.js +188 -0
  47. package/dist/internal/llm-context.js.map +1 -0
  48. package/dist/internal/reference-resolution.d.ts +25 -0
  49. package/dist/internal/reference-resolution.d.ts.map +1 -0
  50. package/dist/internal/reference-resolution.js +133 -0
  51. package/dist/internal/reference-resolution.js.map +1 -0
  52. package/dist/internal/reference-utils.d.ts +26 -0
  53. package/dist/internal/reference-utils.d.ts.map +1 -0
  54. package/dist/internal/reference-utils.js +89 -0
  55. package/dist/internal/reference-utils.js.map +1 -0
  56. package/dist/internal/validation.d.ts +16 -0
  57. package/dist/internal/validation.d.ts.map +1 -0
  58. package/dist/internal/validation.js +45 -0
  59. package/dist/internal/validation.js.map +1 -0
  60. package/dist/types/sdk-types.d.ts +107 -0
  61. package/dist/types/sdk-types.d.ts.map +1 -0
  62. package/dist/types/sdk-types.js +17 -0
  63. package/dist/types/sdk-types.js.map +1 -0
  64. package/dist/types/smart-resources.d.ts +97 -4
  65. package/dist/types/smart-resources.d.ts.map +1 -1
  66. package/dist/types/smart-resources.js +82 -5
  67. package/dist/types/smart-resources.js.map +1 -1
  68. package/dist/utils/interval-tree/index.d.ts +87 -0
  69. package/dist/utils/interval-tree/index.d.ts.map +1 -0
  70. package/dist/utils/interval-tree/index.js +774 -0
  71. package/dist/utils/interval-tree/index.js.map +1 -0
  72. package/dist/utils/interval-tree/shallowequal/arrays.d.ts +3 -0
  73. package/dist/utils/interval-tree/shallowequal/arrays.d.ts.map +1 -0
  74. package/dist/utils/interval-tree/shallowequal/arrays.js +25 -0
  75. package/dist/utils/interval-tree/shallowequal/arrays.js.map +1 -0
  76. package/dist/utils/interval-tree/shallowequal/index.d.ts +6 -0
  77. package/dist/utils/interval-tree/shallowequal/index.d.ts.map +1 -0
  78. package/dist/utils/interval-tree/shallowequal/index.js +28 -0
  79. package/dist/utils/interval-tree/shallowequal/index.js.map +1 -0
  80. package/dist/utils/interval-tree/shallowequal/objects.d.ts +3 -0
  81. package/dist/utils/interval-tree/shallowequal/objects.d.ts.map +1 -0
  82. package/dist/utils/interval-tree/shallowequal/objects.js +28 -0
  83. package/dist/utils/interval-tree/shallowequal/objects.js.map +1 -0
  84. package/package.json +2 -3
package/README.md CHANGED
@@ -67,6 +67,170 @@ console.log(result.hasBrokenReferences); // true if at least one broken referenc
67
67
  console.log(result.brokenReferences); // All broken references in bundle
68
68
  ```
69
69
 
70
+ ### 5. Reverse Reference Lookup
71
+
72
+ Find all resources that reference a given resource (reverse lookup). This is useful for discovering what refers to a specific resource.
73
+
74
+ ```typescript
75
+ const patient = sdk.getPatientById("patient-123");
76
+
77
+ // Find all resources that reference this patient
78
+ const referencingResources = sdk.getResourcesReferencingId("patient-123");
79
+ console.log(referencingResources); // [Observation, Encounter, DiagnosticReport, ...]
80
+
81
+ // Filter by resource type
82
+ const observations = sdk.getResourcesReferencingId("patient-123", {
83
+ resourceType: "Observation",
84
+ });
85
+
86
+ // Filter by reference field
87
+ const subjectReferences = sdk.getResourcesReferencingId("patient-123", {
88
+ referenceField: "subject",
89
+ });
90
+
91
+ // Use smart resource method
92
+ const backRefs = patient.getReferencingResources();
93
+ const encounteredObs = patient.getReferencingResources({
94
+ resourceType: "Observation",
95
+ referenceField: "subject",
96
+ });
97
+ ```
98
+
99
+ **Key Features:**
100
+
101
+ - **O(1) lookup** - constant time performance
102
+ - **Flexible filtering** - by resource type and/or reference field
103
+ - **Smart resources** - returns fully functional Smart resources
104
+ - **Bi-directional** - complements forward reference navigation
105
+
106
+ ### 6. Date Range Search
107
+
108
+ Search for resources by date range using an interval tree index. This is useful for filtering resources by clinical dates efficiently.
109
+
110
+ ```typescript
111
+ const sdk = await FhirBundleSdk.create(bundle);
112
+
113
+ // Basic date range search
114
+ const results = sdk.searchByDateRange({
115
+ dateFrom: "2024-01-01",
116
+ dateTo: "2024-01-31",
117
+ });
118
+
119
+ // Filter by resource type
120
+ const observations = sdk.searchByDateRange({
121
+ dateFrom: "2024-01-01",
122
+ dateTo: "2024-12-31",
123
+ resourceTypes: ["Observation", "Condition"],
124
+ });
125
+
126
+ // Filter by specific date field
127
+ const recordedConditions = sdk.searchByDateRange({
128
+ dateFrom: "2024-01-01",
129
+ dateTo: "2024-12-31",
130
+ dateFields: ["recordedDate"],
131
+ });
132
+
133
+ // Use Date objects
134
+ const recentResources = sdk.searchByDateRange({
135
+ dateFrom: new Date("2024-01-01"),
136
+ dateTo: new Date(),
137
+ });
138
+ ```
139
+
140
+ **Key Features:**
141
+
142
+ - **O(log n + k) search** - efficient interval tree-based search where k is the number of matching resources
143
+ - **Multiple date fields** - indexes primary clinical dates (effectiveDateTime, onset, performed) and recorded dates
144
+ - **Flexible filtering** - by resource type and/or specific date fields
145
+ - **Smart resources** - returns fully functional Smart resources
146
+ - **Period support** - handles both single date fields and date periods/ranges
147
+
148
+ **Indexed Resource Types:**
149
+
150
+ The following resource types and date fields are automatically indexed:
151
+
152
+ - **Observation**: effectiveDateTime, effectivePeriod, effectiveInstant, issued
153
+ - **Condition**: onsetDateTime, onsetPeriod, abatementDateTime, abatementPeriod, recordedDate
154
+ - **Encounter**: period
155
+ - **Procedure**: performedDateTime, performedPeriod
156
+ - **Immunization**: occurrenceDateTime, recorded
157
+ - **DiagnosticReport**: effectiveDateTime, effectivePeriod, issued
158
+ - **MedicationRequest**: authoredOn
159
+ - **MedicationAdministration**: effectiveDateTime, effectivePeriod
160
+ - **MedicationStatement**: effectiveDateTime, effectivePeriod
161
+ - **MedicationDispense**: whenHandedOver, whenPrepared
162
+ - **DocumentReference**: date, context.period
163
+ - **Composition**: date
164
+ - **Coverage**: period
165
+ - **AllergyIntolerance**: onsetDateTime, onsetPeriod, lastOccurrence, recordedDate
166
+
167
+ ### 7. Reference Walking (BFS Traversal)
168
+
169
+ Walk the reference graph starting from any resource using breadth-first search (BFS). This is useful for discovering all resources connected to a specific resource.
170
+
171
+ ```typescript
172
+ const observation = sdk.getObservationById("obs-123");
173
+
174
+ // Walk all reachable resources
175
+ const result = sdk.walkReferences(observation);
176
+ console.log(result.allResources); // All resources reachable from observation
177
+ console.log(result.resourcesByDepth); // Resources organized by depth level
178
+ console.log(result.depthReached); // Maximum depth traversed
179
+
180
+ // Limit traversal depth
181
+ const limitedResult = sdk.walkReferences(observation, { maxDepth: 2 });
182
+
183
+ // Exclude the start resource from results
184
+ const withoutStart = sdk.walkReferences(observation, { includeStartResource: false });
185
+ ```
186
+
187
+ ### 7. LLM Context Generation
188
+
189
+ Generate comprehensive, LLM-friendly context from a resource and its related resources. This automatically performs BFS traversal, strips non-clinical metadata, and formats the output for optimal LLM consumption.
190
+
191
+ ```typescript
192
+ const observation = sdk.getObservationById("obs-123");
193
+
194
+ // Generate structured text context (default, best for LLMs)
195
+ const llmContext = sdk.generateLLMContext(observation, {
196
+ maxDepth: 2, // Default: 2
197
+ format: "structured-text", // Default: 'structured-text'
198
+ });
199
+
200
+ // Send to your LLM
201
+ await llm.chat({
202
+ messages: [
203
+ { role: "system", content: "You are a medical data analyst." },
204
+ { role: "user", content: `Analyze this patient data:\n\n${llmContext}` },
205
+ ],
206
+ });
207
+
208
+ // Alternative: JSON format
209
+ const jsonContext = sdk.generateLLMContext(observation, {
210
+ format: "json",
211
+ });
212
+ ```
213
+
214
+ **Features:**
215
+
216
+ - Automatically discovers all related resources via BFS traversal
217
+ - Strips non-clinical metadata (`meta`, `extension`, `text`) to reduce tokens by ~30-40%
218
+ - Organizes resources hierarchically (primary → directly referenced → indirectly referenced)
219
+ - Groups resources by type within each depth level
220
+ - Logs resource counts for debugging (not included in output)
221
+
222
+ **Static Helper:**
223
+
224
+ You can also strip non-clinical data from any resource independently:
225
+
226
+ ```typescript
227
+ import { FhirBundleSdk } from "@metriport/fhir-sdk";
228
+
229
+ const cleanedPatient = FhirBundleSdk.stripNonClinicalData(patient);
230
+ // Removes: meta, extension, modifierExtension, text
231
+ // Returns immutable copy
232
+ ```
233
+
70
234
  ## Example Use Cases
71
235
 
72
236
  ### Patient Summary
@@ -91,6 +255,28 @@ const buildPatientSummary = (patientId: string) => {
91
255
  const orgName = sdk.getPatients()[0]?.getManagingOrganization()?.name;
92
256
  ```
93
257
 
258
+ ### Extract Related Resources
259
+
260
+ ```typescript
261
+ // Get all resources related to a specific observation
262
+ const extractRelatedResources = (observationId: string) => {
263
+ const observation = sdk.getObservationById(observationId);
264
+ if (!observation) return null;
265
+
266
+ // Walk the graph to find all related resources up to 2 levels deep
267
+ const result = sdk.walkReferences(observation, { maxDepth: 2 });
268
+
269
+ return {
270
+ observation,
271
+ relatedResourceCount: result.allResources.length,
272
+ resourcesByType: result.allResources.reduce((acc, resource) => {
273
+ acc[resource.resourceType] = (acc[resource.resourceType] || 0) + 1;
274
+ return acc;
275
+ }, {} as Record<string, number>),
276
+ };
277
+ };
278
+ ```
279
+
94
280
  ### Example Use Case: Processing a bundle
95
281
 
96
282
  ```typescript
@@ -122,3 +308,24 @@ const processBundle = async (bundle: Bundle) => {
122
308
  - **getById**: O(1) lookup
123
309
  - **getByType**: O(n) where n = resources of that type
124
310
  - **Reference resolution**: O(1) traversal
311
+ - **Reverse reference lookup**: O(1) lookup
312
+
313
+ ## Demo
314
+
315
+ To see reverse reference functionality in action, run:
316
+
317
+ ```bash
318
+ # From the utils package
319
+ cd packages/utils
320
+ npx ts-node src/fhir-sdk/demo-reverse-references.ts --bundle-path /path/to/your/bundle.json
321
+ ```
322
+
323
+ The demo will:
324
+
325
+ - Automatically find the first patient in your bundle
326
+ - Showcase all reverse reference capabilities:
327
+ - Finding all resources that reference a specific resource
328
+ - Filtering by resource type and reference field
329
+ - Using smart resource methods
330
+ - Bi-directional navigation
331
+ - Performance characteristics
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=date-range-performance.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-range-performance.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/date-range-performance.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const index_1 = require("../index");
5
+ // Skip these tests by default as its a performance test that is slow and will slow down CI.
6
+ describe.skip("Date Range Search - Large Scale Performance", () => {
7
+ const ONE_MILLION = 1000000;
8
+ describe("1 Million Resources", () => {
9
+ let largeBundle;
10
+ let sdk;
11
+ beforeAll(() => {
12
+ console.log(`\n🔨 Building bundle with ${ONE_MILLION.toLocaleString()} resources...`);
13
+ const startBuild = performance.now();
14
+ largeBundle = {
15
+ resourceType: "Bundle",
16
+ type: "searchset",
17
+ entry: [],
18
+ };
19
+ // Generate 1 million observations spread over 2024
20
+ // Each observation has a date somewhere in the year
21
+ const startDate = new Date("2024-01-01").getTime();
22
+ const endDate = new Date("2024-12-31").getTime();
23
+ const dateRange = endDate - startDate;
24
+ for (let i = 0; i < ONE_MILLION; i++) {
25
+ // Distribute dates across the year
26
+ const randomOffset = (i / ONE_MILLION) * dateRange;
27
+ const date = new Date(startDate + randomOffset).toISOString();
28
+ largeBundle.entry.push({
29
+ resource: {
30
+ resourceType: "Observation",
31
+ id: `obs-${i}`,
32
+ status: "final",
33
+ code: { text: `Test ${i % 100}` },
34
+ effectiveDateTime: date,
35
+ },
36
+ });
37
+ // Log progress every 100k resources
38
+ if ((i + 1) % 100000 === 0) {
39
+ console.log(` ✓ Generated ${(i + 1).toLocaleString()} resources`);
40
+ }
41
+ }
42
+ const endBuild = performance.now();
43
+ console.log(`✅ Bundle built in ${((endBuild - startBuild) / 1000).toFixed(2)}s\n`);
44
+ });
45
+ it("should index 1 million resources efficiently", () => {
46
+ console.log("📊 Indexing 1 million resources...");
47
+ const start = performance.now();
48
+ sdk = index_1.FhirBundleSdk.createSync(largeBundle);
49
+ const end = performance.now();
50
+ const duration = end - start;
51
+ const durationSeconds = duration / 1000;
52
+ const resourcesPerSecond = ONE_MILLION / durationSeconds;
53
+ console.log(`\n⏱️ Indexing Performance:`);
54
+ console.log(` • Total time: ${durationSeconds.toFixed(2)}s`);
55
+ console.log(` • Resources/second: ${Math.round(resourcesPerSecond).toLocaleString()}`);
56
+ console.log(` • Average time per resource: ${(duration / ONE_MILLION).toFixed(3)}ms\n`);
57
+ expect(sdk).toBeDefined();
58
+ // Should index at least 10,000 resources per second
59
+ expect(resourcesPerSecond).toBeGreaterThan(10000);
60
+ });
61
+ describe("Search Performance", () => {
62
+ it("should search 1 month range efficiently", () => {
63
+ console.log("🔍 Searching 1-month range...");
64
+ const start = performance.now();
65
+ const results = sdk.searchByDateRange({
66
+ dateFrom: "2024-06-01",
67
+ dateTo: "2024-06-30",
68
+ });
69
+ const end = performance.now();
70
+ const duration = end - start;
71
+ console.log(`\n⏱️ 1-Month Search:`);
72
+ console.log(` • Time: ${duration.toFixed(2)}ms`);
73
+ console.log(` • Results: ${results.length.toLocaleString()}`);
74
+ console.log(` • Time per result: ${(duration / results.length).toFixed(3)}ms\n`);
75
+ expect(results.length).toBeGreaterThan(0);
76
+ // Should complete in under 100ms
77
+ expect(duration).toBeLessThan(100);
78
+ });
79
+ it("should search 1 week range efficiently", () => {
80
+ console.log("🔍 Searching 1-week range...");
81
+ const start = performance.now();
82
+ const results = sdk.searchByDateRange({
83
+ dateFrom: "2024-06-01",
84
+ dateTo: "2024-06-07",
85
+ });
86
+ const end = performance.now();
87
+ const duration = end - start;
88
+ console.log(`\n⏱️ 1-Week Search:`);
89
+ console.log(` • Time: ${duration.toFixed(2)}ms`);
90
+ console.log(` • Results: ${results.length.toLocaleString()}`);
91
+ console.log(` • Time per result: ${(duration / results.length).toFixed(3)}ms\n`);
92
+ expect(results.length).toBeGreaterThan(0);
93
+ // Should complete in under 50ms
94
+ expect(duration).toBeLessThan(50);
95
+ });
96
+ it("should search 1 day range efficiently", () => {
97
+ console.log("🔍 Searching 1-day range...");
98
+ const start = performance.now();
99
+ const results = sdk.searchByDateRange({
100
+ dateFrom: "2024-06-15",
101
+ dateTo: "2024-06-15",
102
+ });
103
+ const end = performance.now();
104
+ const duration = end - start;
105
+ console.log(`\n⏱️ 1-Day Search:`);
106
+ console.log(` • Time: ${duration.toFixed(2)}ms`);
107
+ console.log(` • Results: ${results.length.toLocaleString()}`);
108
+ if (results.length > 0) {
109
+ console.log(` • Time per result: ${(duration / results.length).toFixed(3)}ms`);
110
+ }
111
+ console.log();
112
+ // Should complete very quickly even if no results
113
+ expect(duration).toBeLessThan(20);
114
+ });
115
+ it("should search full year range efficiently", () => {
116
+ console.log("🔍 Searching full year range...");
117
+ const start = performance.now();
118
+ const results = sdk.searchByDateRange({
119
+ dateFrom: "2024-01-01",
120
+ dateTo: "2024-12-31",
121
+ });
122
+ const end = performance.now();
123
+ const duration = end - start;
124
+ const durationSeconds = duration / 1000;
125
+ console.log(`\n⏱️ Full Year Search:`);
126
+ console.log(` • Time: ${durationSeconds.toFixed(2)}s`);
127
+ console.log(` • Results: ${results.length.toLocaleString()}`);
128
+ console.log(` • Time per result: ${(duration / results.length).toFixed(3)}ms\n`);
129
+ expect(results.length).toBe(ONE_MILLION);
130
+ // Should complete in under 5 seconds even for all results
131
+ expect(duration).toBeLessThan(5000);
132
+ });
133
+ it("should handle multiple consecutive searches efficiently", () => {
134
+ console.log("🔍 Running 100 consecutive searches...");
135
+ const searches = 100;
136
+ const start = performance.now();
137
+ for (let i = 0; i < searches; i++) {
138
+ // Search different months
139
+ const month = (i % 12) + 1;
140
+ const monthStr = month.toString().padStart(2, "0");
141
+ sdk.searchByDateRange({
142
+ dateFrom: `2024-${monthStr}-01`,
143
+ dateTo: `2024-${monthStr}-28`,
144
+ });
145
+ }
146
+ const end = performance.now();
147
+ const duration = end - start;
148
+ const avgDuration = duration / searches;
149
+ console.log(`\n⏱️ 100 Consecutive Searches:`);
150
+ console.log(` • Total time: ${duration.toFixed(2)}ms`);
151
+ console.log(` • Average per search: ${avgDuration.toFixed(2)}ms`);
152
+ console.log(` • Searches per second: ${Math.round(1000 / avgDuration)}\n`);
153
+ // Average should be under 50ms per search
154
+ expect(avgDuration).toBeLessThan(50);
155
+ });
156
+ });
157
+ describe("Comparison with Linear Search", () => {
158
+ function linearSearchByDate(bundle, dateFrom, dateTo) {
159
+ const fromMs = new Date(dateFrom).getTime();
160
+ const toMs = new Date(dateTo).getTime();
161
+ let count = 0;
162
+ for (const entry of bundle.entry ?? []) {
163
+ if (entry.resource?.resourceType === "Observation") {
164
+ const obs = entry.resource;
165
+ if (obs.effectiveDateTime) {
166
+ const dateMs = new Date(obs.effectiveDateTime).getTime();
167
+ if (dateMs >= fromMs && dateMs <= toMs) {
168
+ count++;
169
+ }
170
+ }
171
+ }
172
+ }
173
+ return count;
174
+ }
175
+ it("should be significantly faster than linear search", () => {
176
+ console.log("⚖️ Comparing interval tree vs linear search...");
177
+ // Test with 1-month range
178
+ const dateFrom = "2024-06-01";
179
+ const dateTo = "2024-06-30";
180
+ // Interval tree search
181
+ console.log("\n Testing interval tree...");
182
+ const treeStart = performance.now();
183
+ const treeResults = sdk.searchByDateRange({ dateFrom, dateTo });
184
+ const treeEnd = performance.now();
185
+ const treeDuration = treeEnd - treeStart;
186
+ // Linear search
187
+ console.log(" Testing linear search...");
188
+ const linearStart = performance.now();
189
+ const linearCount = linearSearchByDate(largeBundle, dateFrom, dateTo);
190
+ const linearEnd = performance.now();
191
+ const linearDuration = linearEnd - linearStart;
192
+ const speedup = linearDuration / treeDuration;
193
+ console.log(`\n📊 Performance Comparison (1-month search):`);
194
+ console.log(` • Interval Tree: ${treeDuration.toFixed(2)}ms`);
195
+ console.log(` • Linear Search: ${linearDuration.toFixed(2)}ms`);
196
+ console.log(` • Speedup: ${speedup.toFixed(1)}x faster`);
197
+ console.log(` • Results matched: ${treeResults.length === linearCount}\n`);
198
+ expect(treeResults.length).toBe(linearCount);
199
+ // Interval tree should be significantly faster (at least 5x)
200
+ expect(speedup).toBeGreaterThan(5);
201
+ });
202
+ });
203
+ describe("Memory Efficiency", () => {
204
+ it("should report memory usage", () => {
205
+ if (typeof process !== "undefined" && process.memoryUsage) {
206
+ const memUsage = process.memoryUsage();
207
+ console.log(`\n💾 Memory Usage:`);
208
+ console.log(` • Heap Used: ${(memUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`);
209
+ console.log(` • Heap Total: ${(memUsage.heapTotal / 1024 / 1024).toFixed(2)} MB`);
210
+ console.log(` • External: ${(memUsage.external / 1024 / 1024).toFixed(2)} MB`);
211
+ console.log(` • Per resource: ${((memUsage.heapUsed / ONE_MILLION) * 1024).toFixed(2)} bytes\n`);
212
+ }
213
+ expect(true).toBe(true);
214
+ });
215
+ });
216
+ });
217
+ });
218
+ //# sourceMappingURL=date-range-performance.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-range-performance.test.js","sourceRoot":"","sources":["../../src/__tests__/date-range-performance.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=date-range-search.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-range-search.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/date-range-search.test.ts"],"names":[],"mappings":""}