@unrdf/dark-matter 5.0.1 → 26.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -7
- package/src/dark-matter/query-analyzer.mjs +1 -1
- package/README.md +0 -81
- package/src/dark-matter/critical-path.mjs +0 -367
- package/src/dark-matter/index-advisor.mjs +0 -242
- package/src/dark-matter/index.mjs +0 -244
- package/src/dark-matter/optimizer.mjs +0 -426
- package/src/dark-matter/performance-metrics.mjs +0 -242
- package/src/dark-matter/query-optimizer.mjs +0 -283
- package/src/dark-matter-core.mjs +0 -743
- package/src/index.mjs +0 -60
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unrdf/dark-matter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "26.4.3",
|
|
4
4
|
"description": "UNRDF Dark Matter - Query Optimization and Performance Analysis (Optional Extension)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.mjs",
|
|
@@ -24,8 +24,9 @@
|
|
|
24
24
|
"80-20"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"
|
|
28
|
-
"@unrdf/
|
|
27
|
+
"@unrdf/core": "26.4.3",
|
|
28
|
+
"@unrdf/oxigraph": "26.4.3",
|
|
29
|
+
"typhonjs-escomplex": "^0.1.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@types/node": "^24.10.1",
|
|
@@ -52,10 +53,10 @@
|
|
|
52
53
|
"test:fast": "vitest run --coverage",
|
|
53
54
|
"test:watch": "vitest --coverage",
|
|
54
55
|
"build": "node build.config.mjs",
|
|
55
|
-
"lint": "eslint src/
|
|
56
|
-
"lint:fix": "eslint src/
|
|
57
|
-
"format": "prettier --write src/
|
|
58
|
-
"format:check": "prettier --check src/
|
|
56
|
+
"lint": "eslint src/ --max-warnings=0",
|
|
57
|
+
"lint:fix": "eslint src/ --fix",
|
|
58
|
+
"format": "prettier --write src/",
|
|
59
|
+
"format:check": "prettier --check src/",
|
|
59
60
|
"clean": "rm -rf dist/ .nyc_output/ coverage/",
|
|
60
61
|
"dev": "echo 'Development mode for @unrdf/dark-matter'"
|
|
61
62
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* and identify expensive operations for 80/20 optimization.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { analyzeSPARQLQuery, extractVariables } from '
|
|
10
|
+
import { analyzeSPARQLQuery, extractVariables } from '@unrdf/core/utils/sparql-utils';
|
|
11
11
|
import { z } from 'zod';
|
|
12
12
|
|
|
13
13
|
/**
|
package/README.md
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# @unrdf/dark-matter
|
|
2
|
-
|
|
3
|
-
 
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
**Query Optimization and Performance Analysis** *(Optional Extension)*
|
|
7
|
-
|
|
8
|
-
Optimize SPARQL queries and analyze RDF graph performance. Implements the 80/20 principle for query optimization.
|
|
9
|
-
|
|
10
|
-
## Installation
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
pnpm add @unrdf/dark-matter
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## 📚 Examples
|
|
17
|
-
|
|
18
|
-
See these examples that demonstrate @unrdf/dark-matter:
|
|
19
|
-
|
|
20
|
-
- **[dark-matter-80-20.mjs](../../examples/dark-matter-80-20.mjs)** - Query optimization basics (30 min, 5-10x speedup)
|
|
21
|
-
- **[dark-matter-query-optimization.mjs](../../examples/dark-matter-query-optimization.mjs)** - Advanced optimization strategies
|
|
22
|
-
- **[profiling-example.mjs](../../examples/profiling-example.mjs)** - Performance profiling and analysis
|
|
23
|
-
- **[lockchain-dark-matter-test.mjs](../../examples/lockchain-dark-matter-test.mjs)** - Combined optimization + audit
|
|
24
|
-
|
|
25
|
-
**Need faster queries?** Start with [dark-matter-80-20.mjs](../../examples/dark-matter-80-20.mjs).
|
|
26
|
-
|
|
27
|
-
## Quick Start
|
|
28
|
-
|
|
29
|
-
```javascript
|
|
30
|
-
import { optimizeQuery, analyzePerformance } from '@unrdf/dark-matter'
|
|
31
|
-
|
|
32
|
-
// Optimize a SPARQL query
|
|
33
|
-
const optimized = optimizeQuery(
|
|
34
|
-
'SELECT ?name WHERE { ?s foaf:name ?name. ?s foaf:age ?age }'
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
// Analyze graph performance
|
|
38
|
-
const metrics = await analyzePerformance(store)
|
|
39
|
-
console.log('Query execution time:', metrics.queryTime)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Features
|
|
43
|
-
|
|
44
|
-
- ✅ SPARQL query optimization
|
|
45
|
-
- ✅ Critical path analysis
|
|
46
|
-
- ✅ Performance metrics collection
|
|
47
|
-
- ✅ Query plan analysis
|
|
48
|
-
- ✅ Index recommendations
|
|
49
|
-
- ✅ Bottleneck identification
|
|
50
|
-
|
|
51
|
-
## Use Cases
|
|
52
|
-
|
|
53
|
-
- **Performance tuning**: Optimize slow queries
|
|
54
|
-
- **Capacity planning**: Understand resource usage
|
|
55
|
-
- **Monitoring**: Track graph performance
|
|
56
|
-
- **Optimization**: Find and fix bottlenecks
|
|
57
|
-
- **Benchmarking**: Compare query strategies
|
|
58
|
-
|
|
59
|
-
## Documentation
|
|
60
|
-
|
|
61
|
-
- **[API Reference](./docs/API.md)** - Complete API documentation
|
|
62
|
-
- **[User Guide](./docs/GUIDE.md)** - Optimization guide
|
|
63
|
-
- **[Examples](./examples/)** - Code examples
|
|
64
|
-
- **[Contributing](./docs/CONTRIBUTING.md)** - How to contribute
|
|
65
|
-
|
|
66
|
-
## Status
|
|
67
|
-
|
|
68
|
-
**Optional Extension** - Use only if you need query optimization.
|
|
69
|
-
Most applications don't need this.
|
|
70
|
-
|
|
71
|
-
## Depends On
|
|
72
|
-
|
|
73
|
-
- `@unrdf/core` - RDF substrate
|
|
74
|
-
|
|
75
|
-
## VOC Usage
|
|
76
|
-
|
|
77
|
-
- Performance-critical applications
|
|
78
|
-
|
|
79
|
-
## License
|
|
80
|
-
|
|
81
|
-
MIT
|
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Dark Matter 80/20 Critical Path Identification
|
|
3
|
-
* @module dark-matter/critical-path
|
|
4
|
-
*
|
|
5
|
-
* @description
|
|
6
|
-
* Implements the 80/20 algorithm to identify the top 20% slowest queries
|
|
7
|
-
* that account for 80% of performance impact.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { z } from 'zod';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Schema for query execution log
|
|
14
|
-
*/
|
|
15
|
-
const QueryExecutionLogSchema = z.object({
|
|
16
|
-
queryId: z.string(),
|
|
17
|
-
query: z.string(),
|
|
18
|
-
executionTime: z.number(),
|
|
19
|
-
timestamp: z.number(),
|
|
20
|
-
metadata: z.object({}).passthrough().optional(),
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Schema for critical path result
|
|
25
|
-
*/
|
|
26
|
-
const CriticalPathResultSchema = z.object({
|
|
27
|
-
criticalQueries: z.array(
|
|
28
|
-
z.object({
|
|
29
|
-
queryId: z.string(),
|
|
30
|
-
query: z.string(),
|
|
31
|
-
executionTime: z.number(),
|
|
32
|
-
occurrences: z.number(),
|
|
33
|
-
totalTime: z.number(),
|
|
34
|
-
percentageOfTotal: z.number(),
|
|
35
|
-
rank: z.number(),
|
|
36
|
-
})
|
|
37
|
-
),
|
|
38
|
-
metrics: z.object({
|
|
39
|
-
totalQueries: z.number(),
|
|
40
|
-
criticalQueryCount: z.number(),
|
|
41
|
-
criticalQueryPercentage: z.number(),
|
|
42
|
-
totalExecutionTime: z.number(),
|
|
43
|
-
criticalExecutionTime: z.number(),
|
|
44
|
-
impactRatio: z.number(),
|
|
45
|
-
avgExecutionTime: z.number(),
|
|
46
|
-
p50: z.number(),
|
|
47
|
-
p90: z.number(),
|
|
48
|
-
p99: z.number(),
|
|
49
|
-
}),
|
|
50
|
-
timestamp: z.number(),
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Critical Path Identifier for Dark Matter 80/20
|
|
55
|
-
*/
|
|
56
|
-
export class CriticalPathIdentifier {
|
|
57
|
-
/**
|
|
58
|
-
* Create a new critical path identifier
|
|
59
|
-
* @param {Object} [config] - Configuration
|
|
60
|
-
*/
|
|
61
|
-
constructor(config = {}) {
|
|
62
|
-
this.config = {
|
|
63
|
-
targetImpactRatio: config.targetImpactRatio || 0.8, // 80% of impact
|
|
64
|
-
targetQueryRatio: config.targetQueryRatio || 0.2, // from 20% of queries
|
|
65
|
-
minSampleSize: config.minSampleSize || 10,
|
|
66
|
-
windowSize: config.windowSize || 1000, // Keep last 1000 queries
|
|
67
|
-
...config,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
this.executionLogs = [];
|
|
71
|
-
this.cache = new Map();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Log a query execution
|
|
76
|
-
* @param {string} queryId - Query identifier
|
|
77
|
-
* @param {string} query - Query string
|
|
78
|
-
* @param {number} executionTime - Execution time in ms
|
|
79
|
-
* @param {Object} [metadata] - Optional metadata
|
|
80
|
-
*/
|
|
81
|
-
logExecution(queryId, query, executionTime, metadata = {}) {
|
|
82
|
-
const log = {
|
|
83
|
-
queryId,
|
|
84
|
-
query,
|
|
85
|
-
executionTime,
|
|
86
|
-
timestamp: Date.now(),
|
|
87
|
-
metadata,
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
this.executionLogs.push(QueryExecutionLogSchema.parse(log));
|
|
91
|
-
|
|
92
|
-
// Keep window size
|
|
93
|
-
if (this.executionLogs.length > this.config.windowSize) {
|
|
94
|
-
this.executionLogs.shift();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Invalidate cache
|
|
98
|
-
this.cache.clear();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Analyze and identify critical path
|
|
103
|
-
* @returns {Object} Critical path analysis
|
|
104
|
-
*/
|
|
105
|
-
identify() {
|
|
106
|
-
if (this.executionLogs.length < this.config.minSampleSize) {
|
|
107
|
-
throw new Error(
|
|
108
|
-
`Insufficient data: ${this.executionLogs.length} queries logged, ` +
|
|
109
|
-
`minimum ${this.config.minSampleSize} required`
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Check cache
|
|
114
|
-
const cacheKey = 'critical-path';
|
|
115
|
-
if (this.cache.has(cacheKey)) {
|
|
116
|
-
return this.cache.get(cacheKey);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Group queries by queryId and calculate statistics
|
|
120
|
-
const queryStats = this._aggregateQueryStats();
|
|
121
|
-
|
|
122
|
-
// Sort by total execution time (descending)
|
|
123
|
-
const sortedQueries = Array.from(queryStats.values()).sort((a, b) => b.totalTime - a.totalTime);
|
|
124
|
-
|
|
125
|
-
// Calculate total execution time
|
|
126
|
-
const totalExecutionTime = sortedQueries.reduce((sum, q) => sum + q.totalTime, 0);
|
|
127
|
-
|
|
128
|
-
// Find critical queries (top 20% that account for 80% of time)
|
|
129
|
-
const criticalQueries = this._findCriticalQueries(sortedQueries, totalExecutionTime);
|
|
130
|
-
|
|
131
|
-
// Calculate metrics
|
|
132
|
-
const metrics = this._calculateMetrics(sortedQueries, criticalQueries, totalExecutionTime);
|
|
133
|
-
|
|
134
|
-
const result = {
|
|
135
|
-
criticalQueries: criticalQueries.map((q, index) => ({
|
|
136
|
-
...q,
|
|
137
|
-
rank: index + 1,
|
|
138
|
-
})),
|
|
139
|
-
metrics,
|
|
140
|
-
timestamp: Date.now(),
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const validated = CriticalPathResultSchema.parse(result);
|
|
144
|
-
|
|
145
|
-
// Cache result
|
|
146
|
-
this.cache.set(cacheKey, validated);
|
|
147
|
-
|
|
148
|
-
return validated;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Aggregate query statistics
|
|
153
|
-
* @returns {Map} Query statistics
|
|
154
|
-
* @private
|
|
155
|
-
*/
|
|
156
|
-
_aggregateQueryStats() {
|
|
157
|
-
const stats = new Map();
|
|
158
|
-
|
|
159
|
-
for (const log of this.executionLogs) {
|
|
160
|
-
if (!stats.has(log.queryId)) {
|
|
161
|
-
stats.set(log.queryId, {
|
|
162
|
-
queryId: log.queryId,
|
|
163
|
-
query: log.query,
|
|
164
|
-
executionTime: 0,
|
|
165
|
-
occurrences: 0,
|
|
166
|
-
totalTime: 0,
|
|
167
|
-
percentageOfTotal: 0,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const stat = stats.get(log.queryId);
|
|
172
|
-
stat.occurrences++;
|
|
173
|
-
stat.totalTime += log.executionTime;
|
|
174
|
-
stat.executionTime = stat.totalTime / stat.occurrences; // Average
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return stats;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Find critical queries using 80/20 algorithm
|
|
182
|
-
* @param {Array} sortedQueries - Queries sorted by total time
|
|
183
|
-
* @param {number} totalExecutionTime - Total execution time
|
|
184
|
-
* @returns {Array} Critical queries
|
|
185
|
-
* @private
|
|
186
|
-
*/
|
|
187
|
-
_findCriticalQueries(sortedQueries, totalExecutionTime) {
|
|
188
|
-
const critical = [];
|
|
189
|
-
let cumulativeTime = 0;
|
|
190
|
-
let cumulativePercentage = 0;
|
|
191
|
-
|
|
192
|
-
// Find queries that contribute to target impact ratio (80%)
|
|
193
|
-
for (const query of sortedQueries) {
|
|
194
|
-
cumulativeTime += query.totalTime;
|
|
195
|
-
cumulativePercentage = cumulativeTime / totalExecutionTime;
|
|
196
|
-
|
|
197
|
-
query.percentageOfTotal = (query.totalTime / totalExecutionTime) * 100;
|
|
198
|
-
critical.push(query);
|
|
199
|
-
|
|
200
|
-
// Stop when we reach the target impact ratio
|
|
201
|
-
if (cumulativePercentage >= this.config.targetImpactRatio) {
|
|
202
|
-
break;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Ensure we don't exceed target query ratio (20%)
|
|
207
|
-
const maxCriticalQueries = Math.ceil(sortedQueries.length * this.config.targetQueryRatio);
|
|
208
|
-
|
|
209
|
-
// Return either the queries that hit 80% impact or top 20%, whichever is smaller
|
|
210
|
-
return critical.slice(0, Math.min(critical.length, maxCriticalQueries));
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Calculate performance metrics
|
|
215
|
-
* @param {Array} allQueries - All queries
|
|
216
|
-
* @param {Array} criticalQueries - Critical queries
|
|
217
|
-
* @param {number} totalExecutionTime - Total execution time
|
|
218
|
-
* @returns {Object} Metrics
|
|
219
|
-
* @private
|
|
220
|
-
*/
|
|
221
|
-
_calculateMetrics(allQueries, criticalQueries, totalExecutionTime) {
|
|
222
|
-
const criticalExecutionTime = criticalQueries.reduce((sum, q) => sum + q.totalTime, 0);
|
|
223
|
-
|
|
224
|
-
// Calculate percentiles
|
|
225
|
-
const executionTimes = this.executionLogs.map(log => log.executionTime).sort((a, b) => a - b);
|
|
226
|
-
|
|
227
|
-
const p50 = this._percentile(executionTimes, 0.5);
|
|
228
|
-
const p90 = this._percentile(executionTimes, 0.9);
|
|
229
|
-
const p99 = this._percentile(executionTimes, 0.99);
|
|
230
|
-
|
|
231
|
-
return {
|
|
232
|
-
totalQueries: allQueries.length,
|
|
233
|
-
criticalQueryCount: criticalQueries.length,
|
|
234
|
-
criticalQueryPercentage: (criticalQueries.length / allQueries.length) * 100,
|
|
235
|
-
totalExecutionTime,
|
|
236
|
-
criticalExecutionTime,
|
|
237
|
-
impactRatio: criticalExecutionTime / totalExecutionTime,
|
|
238
|
-
avgExecutionTime: totalExecutionTime / this.executionLogs.length,
|
|
239
|
-
p50,
|
|
240
|
-
p90,
|
|
241
|
-
p99,
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Calculate percentile
|
|
247
|
-
* @param {Array} sortedValues - Sorted array of values
|
|
248
|
-
* @param {number} percentile - Percentile (0-1)
|
|
249
|
-
* @returns {number} Percentile value
|
|
250
|
-
* @private
|
|
251
|
-
*/
|
|
252
|
-
_percentile(sortedValues, percentile) {
|
|
253
|
-
if (sortedValues.length === 0) return 0;
|
|
254
|
-
|
|
255
|
-
const index = Math.ceil(sortedValues.length * percentile) - 1;
|
|
256
|
-
return sortedValues[Math.max(0, index)];
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Get report in markdown format
|
|
261
|
-
* @returns {string} Markdown report
|
|
262
|
-
*/
|
|
263
|
-
getReport() {
|
|
264
|
-
const analysis = this.identify();
|
|
265
|
-
|
|
266
|
-
let report = '# Dark Matter 80/20 Critical Path Report\n\n';
|
|
267
|
-
|
|
268
|
-
// Summary
|
|
269
|
-
report += '## Summary\n\n';
|
|
270
|
-
report += `- **Total Queries Analyzed**: ${analysis.metrics.totalQueries}\n`;
|
|
271
|
-
report += `- **Critical Queries (Top ${(this.config.targetQueryRatio * 100).toFixed(0)}%)**: ${analysis.metrics.criticalQueryCount}\n`;
|
|
272
|
-
report += `- **Impact Ratio**: ${(analysis.metrics.impactRatio * 100).toFixed(1)}% of total execution time\n`;
|
|
273
|
-
report += `- **Average Execution Time**: ${analysis.metrics.avgExecutionTime.toFixed(2)}ms\n`;
|
|
274
|
-
report += `- **P50 Latency**: ${analysis.metrics.p50.toFixed(2)}ms\n`;
|
|
275
|
-
report += `- **P90 Latency**: ${analysis.metrics.p90.toFixed(2)}ms\n`;
|
|
276
|
-
report += `- **P99 Latency**: ${analysis.metrics.p99.toFixed(2)}ms\n\n`;
|
|
277
|
-
|
|
278
|
-
// Critical queries
|
|
279
|
-
report += '## Critical Queries\n\n';
|
|
280
|
-
report += '| Rank | Query ID | Occurrences | Avg Time | Total Time | % of Total |\n';
|
|
281
|
-
report += '|------|----------|-------------|----------|------------|------------|\n';
|
|
282
|
-
|
|
283
|
-
for (const query of analysis.criticalQueries) {
|
|
284
|
-
report += `| ${query.rank} | ${query.queryId} | ${query.occurrences} | ${query.executionTime.toFixed(2)}ms | ${query.totalTime.toFixed(2)}ms | ${query.percentageOfTotal.toFixed(1)}% |\n`;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
report += '\n## Recommendations\n\n';
|
|
288
|
-
report +=
|
|
289
|
-
'Focus optimization efforts on the queries listed above. These represent the critical path:\n\n';
|
|
290
|
-
report += `- Optimizing the top ${analysis.metrics.criticalQueryCount} queries will improve ${(analysis.metrics.impactRatio * 100).toFixed(1)}% of query performance\n`;
|
|
291
|
-
report +=
|
|
292
|
-
'- Consider adding indexes, rewriting queries, or caching results for critical queries\n';
|
|
293
|
-
report += '- Monitor P99 latency to catch performance regressions\n';
|
|
294
|
-
|
|
295
|
-
return report;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Get execution logs
|
|
300
|
-
* @param {Object} [filter] - Optional filter
|
|
301
|
-
* @returns {Array} Execution logs
|
|
302
|
-
*/
|
|
303
|
-
getLogs(filter = {}) {
|
|
304
|
-
let logs = [...this.executionLogs];
|
|
305
|
-
|
|
306
|
-
if (filter.queryId) {
|
|
307
|
-
logs = logs.filter(log => log.queryId === filter.queryId);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (filter.minExecutionTime) {
|
|
311
|
-
logs = logs.filter(log => log.executionTime >= filter.minExecutionTime);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
if (filter.startTime && filter.endTime) {
|
|
315
|
-
logs = logs.filter(
|
|
316
|
-
log => log.timestamp >= filter.startTime && log.timestamp <= filter.endTime
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
return logs;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Clear all logs
|
|
325
|
-
*/
|
|
326
|
-
clearLogs() {
|
|
327
|
-
this.executionLogs = [];
|
|
328
|
-
this.cache.clear();
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Export logs to JSON
|
|
333
|
-
* @returns {string} JSON string
|
|
334
|
-
*/
|
|
335
|
-
exportLogs() {
|
|
336
|
-
return JSON.stringify(
|
|
337
|
-
{
|
|
338
|
-
logs: this.executionLogs,
|
|
339
|
-
config: this.config,
|
|
340
|
-
timestamp: Date.now(),
|
|
341
|
-
},
|
|
342
|
-
null,
|
|
343
|
-
2
|
|
344
|
-
);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Import logs from JSON
|
|
349
|
-
* @param {string} json - JSON string
|
|
350
|
-
*/
|
|
351
|
-
importLogs(json) {
|
|
352
|
-
const data = JSON.parse(json);
|
|
353
|
-
this.executionLogs = data.logs.map(log => QueryExecutionLogSchema.parse(log));
|
|
354
|
-
this.cache.clear();
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Create a critical path identifier instance
|
|
360
|
-
* @param {Object} [config] - Configuration
|
|
361
|
-
* @returns {CriticalPathIdentifier} Critical path identifier
|
|
362
|
-
*/
|
|
363
|
-
export function createCriticalPathIdentifier(config = {}) {
|
|
364
|
-
return new CriticalPathIdentifier(config);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
export default CriticalPathIdentifier;
|