@nshiab/simple-data-analysis-core 2.1.6 → 2.1.8
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/esm/class/SimpleTable.d.ts +399 -90
- package/esm/class/SimpleTable.d.ts.map +1 -1
- package/esm/class/SimpleTable.js +393 -90
- package/esm/helpers/buildGraphTemporalCostStateSql.d.ts +1 -1
- package/esm/helpers/buildGraphTemporalCostStateSql.d.ts.map +1 -1
- package/esm/helpers/buildGraphTemporalCostStateSql.js +23 -9
- package/esm/helpers/graphRouteResultSchema.d.ts +1 -1
- package/esm/helpers/graphRouteResultSchema.d.ts.map +1 -1
- package/esm/helpers/graphRouteResultSchema.js +4 -3
- package/esm/helpers/graphRouteResultSelect.d.ts +1 -1
- package/esm/helpers/graphRouteResultSelect.d.ts.map +1 -1
- package/esm/helpers/graphRouteResultSelect.js +5 -2
- package/esm/helpers/prepareGraphMetricOptions.d.ts +14 -0
- package/esm/helpers/prepareGraphMetricOptions.d.ts.map +1 -0
- package/esm/helpers/prepareGraphMetricOptions.js +41 -0
- package/esm/helpers/prepareGraphRouteSql.d.ts +2 -2
- package/esm/helpers/prepareGraphRouteSql.d.ts.map +1 -1
- package/esm/helpers/prepareGraphRouteSql.js +4 -4
- package/esm/helpers/prepareGraphTemporalSql.d.ts +3 -0
- package/esm/helpers/prepareGraphTemporalSql.d.ts.map +1 -1
- package/esm/helpers/prepareGraphTemporalSql.js +7 -0
- package/esm/helpers/validateGraphRouteResultSchema.d.ts +1 -1
- package/esm/helpers/validateGraphRouteResultSchema.d.ts.map +1 -1
- package/esm/helpers/validateGraphRouteResultSchema.js +3 -1
- package/esm/methods/distances.d.ts +2 -0
- package/esm/methods/distances.d.ts.map +1 -1
- package/esm/methods/distances.js +274 -20
- package/esm/methods/findCycles.d.ts +1 -0
- package/esm/methods/findCycles.d.ts.map +1 -1
- package/esm/methods/findCycles.js +22 -15
- package/esm/methods/paths.d.ts +1 -0
- package/esm/methods/paths.d.ts.map +1 -1
- package/esm/methods/paths.js +21 -14
- package/esm/methods/shortestPath.d.ts +2 -0
- package/esm/methods/shortestPath.d.ts.map +1 -1
- package/esm/methods/shortestPath.js +155 -34
- package/llm.md +428 -108
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/script/class/SimpleTable.d.ts +399 -90
- package/script/class/SimpleTable.d.ts.map +1 -1
- package/script/class/SimpleTable.js +393 -90
- package/script/helpers/buildGraphTemporalCostStateSql.d.ts +1 -1
- package/script/helpers/buildGraphTemporalCostStateSql.d.ts.map +1 -1
- package/script/helpers/buildGraphTemporalCostStateSql.js +23 -9
- package/script/helpers/graphRouteResultSchema.d.ts +1 -1
- package/script/helpers/graphRouteResultSchema.d.ts.map +1 -1
- package/script/helpers/graphRouteResultSchema.js +4 -3
- package/script/helpers/graphRouteResultSelect.d.ts +1 -1
- package/script/helpers/graphRouteResultSelect.d.ts.map +1 -1
- package/script/helpers/graphRouteResultSelect.js +5 -2
- package/script/helpers/prepareGraphMetricOptions.d.ts +14 -0
- package/script/helpers/prepareGraphMetricOptions.d.ts.map +1 -0
- package/script/helpers/prepareGraphMetricOptions.js +44 -0
- package/script/helpers/prepareGraphRouteSql.d.ts +2 -2
- package/script/helpers/prepareGraphRouteSql.d.ts.map +1 -1
- package/script/helpers/prepareGraphRouteSql.js +4 -4
- package/script/helpers/prepareGraphTemporalSql.d.ts +3 -0
- package/script/helpers/prepareGraphTemporalSql.d.ts.map +1 -1
- package/script/helpers/prepareGraphTemporalSql.js +7 -0
- package/script/helpers/validateGraphRouteResultSchema.d.ts +1 -1
- package/script/helpers/validateGraphRouteResultSchema.d.ts.map +1 -1
- package/script/helpers/validateGraphRouteResultSchema.js +3 -1
- package/script/methods/distances.d.ts +2 -0
- package/script/methods/distances.d.ts.map +1 -1
- package/script/methods/distances.js +274 -20
- package/script/methods/findCycles.d.ts +1 -0
- package/script/methods/findCycles.d.ts.map +1 -1
- package/script/methods/findCycles.js +22 -15
- package/script/methods/paths.d.ts +1 -0
- package/script/methods/paths.d.ts.map +1 -1
- package/script/methods/paths.js +21 -14
- package/script/methods/shortestPath.d.ts +2 -0
- package/script/methods/shortestPath.d.ts.map +1 -1
- package/script/methods/shortestPath.js +155 -34
|
@@ -39,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.default = distances;
|
|
40
40
|
const buildGraphTemporalCostStateSql_js_1 = __importDefault(require("../helpers/buildGraphTemporalCostStateSql.js"));
|
|
41
41
|
const getGraphWeightColumn_js_1 = __importDefault(require("../helpers/getGraphWeightColumn.js"));
|
|
42
|
+
const prepareGraphMetricOptions_js_1 = __importDefault(require("../helpers/prepareGraphMetricOptions.js"));
|
|
42
43
|
const prepareGraphTemporalSql_js_1 = __importStar(require("../helpers/prepareGraphTemporalSql.js"));
|
|
43
44
|
const prepareGraphStarts_js_1 = __importDefault(require("../helpers/prepareGraphStarts.js"));
|
|
44
45
|
const prepareGraphTraversal_js_1 = __importStar(require("../helpers/prepareGraphTraversal.js"));
|
|
@@ -67,6 +68,7 @@ function distances(simpleTable, sourceColumn, targetColumn, startNodes, options
|
|
|
67
68
|
typeof options.outputTable !== "boolean") {
|
|
68
69
|
throw new TypeError("distances() options.outputTable must be a string or boolean.");
|
|
69
70
|
}
|
|
71
|
+
const metrics = (0, prepareGraphMetricOptions_js_1.default)(options, "distances()", true);
|
|
70
72
|
const preparedStarts = (0, prepareGraphStarts_js_1.default)(startNodes, "distances()", "startNodes");
|
|
71
73
|
const direction = options.direction ?? "outgoing";
|
|
72
74
|
const temporalOptions = (0, prepareGraphTemporalSql_js_1.prepareGraphTemporalOptions)(options, direction, "distances()");
|
|
@@ -90,13 +92,17 @@ function distances(simpleTable, sourceColumn, targetColumn, startNodes, options
|
|
|
90
92
|
? preparedStarts.values
|
|
91
93
|
: [temporal.gapParameter, ...preparedStarts.values];
|
|
92
94
|
},
|
|
93
|
-
buildSelect: (input, schema) => distancesSelect(input, schema, sourceColumn, targetColumn, preparedStarts, direction, options.weight, temporalOptions),
|
|
95
|
+
buildSelect: (input, schema) => distancesSelect(input, schema, sourceColumn, targetColumn, preparedStarts, direction, options.weight, temporalOptions, metrics),
|
|
94
96
|
outputSchema: (schema) => {
|
|
95
97
|
const validated = validateDistanceInputs(schema, sourceColumn, targetColumn, preparedStarts, options.weight, temporalOptions);
|
|
96
98
|
return {
|
|
97
99
|
start: validated.idType,
|
|
98
100
|
node: validated.idType,
|
|
99
|
-
|
|
101
|
+
steps: "BIGINT",
|
|
102
|
+
...(options.weight === undefined
|
|
103
|
+
? {}
|
|
104
|
+
: { total: validated.distanceType }),
|
|
105
|
+
...(metrics.elapsedTime ? { elapsedTimeMs: "DOUBLE" } : {}),
|
|
100
106
|
};
|
|
101
107
|
},
|
|
102
108
|
});
|
|
@@ -111,7 +117,7 @@ function validateDistanceInputs(schema, source, target, starts, weight, temporal
|
|
|
111
117
|
: (0, prepareGraphTemporalSql_js_1.default)(schema, temporalOptions, "distances()");
|
|
112
118
|
return { idType: endpoints.idType, distanceType, temporal };
|
|
113
119
|
}
|
|
114
|
-
function distancesSelect(input, schema, source, target, starts, direction, weight, temporalOptions) {
|
|
120
|
+
function distancesSelect(input, schema, source, target, starts, direction, weight, temporalOptions, metrics) {
|
|
115
121
|
const prepared = (0, prepareGraphTraversal_js_1.default)(input, schema, source, target, starts, "distances()", "startNodes");
|
|
116
122
|
const weightColumn = weight === undefined
|
|
117
123
|
? undefined
|
|
@@ -120,9 +126,14 @@ function distancesSelect(input, schema, source, target, starts, direction, weigh
|
|
|
120
126
|
const edgeWeight = weightColumn === undefined
|
|
121
127
|
? `CAST(1 AS ${distanceType})`
|
|
122
128
|
: `CAST(${(0, quoteIdentifier_js_1.default)("edges")}.${(0, quoteIdentifier_js_1.default)(weightColumn.column)} AS ${distanceType})`;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
const temporal = temporalOptions === undefined
|
|
130
|
+
? undefined
|
|
131
|
+
: (0, prepareGraphTemporalSql_js_1.default)(schema, temporalOptions, "distances()");
|
|
132
|
+
if (weight !== undefined || metrics.elapsedTime) {
|
|
133
|
+
return summaryDistancesSelect(prepared, direction, temporal, distanceType, edgeWeight, metrics, weight !== undefined, weightColumn?.type === "FLOAT" || weightColumn?.type === "DOUBLE");
|
|
134
|
+
}
|
|
135
|
+
if (temporal !== undefined) {
|
|
136
|
+
return temporalDistancesSelect(prepared, direction, temporal, distanceType, edgeWeight, "steps", false);
|
|
126
137
|
}
|
|
127
138
|
const relations = prepared.relationNames([
|
|
128
139
|
"graph_start_values",
|
|
@@ -146,6 +157,14 @@ function distancesSelect(input, schema, source, target, starts, direction, weigh
|
|
|
146
157
|
const edgeCost = `${(0, quoteIdentifier_js_1.default)("edges")}.${(0, quoteIdentifier_js_1.default)("__weight")}`;
|
|
147
158
|
const bestDistance = `${(0, quoteIdentifier_js_1.default)("best")}.${(0, quoteIdentifier_js_1.default)("distance")}`;
|
|
148
159
|
const candidateDistance = `CAST(${reachedDistance} + ${edgeCost} AS ${distanceType})`;
|
|
160
|
+
const candidateSteps = `${(0, quoteIdentifier_js_1.default)("reached")}.${(0, quoteIdentifier_js_1.default)("steps")} + 1`;
|
|
161
|
+
const bestSteps = `${(0, quoteIdentifier_js_1.default)("best")}.${(0, quoteIdentifier_js_1.default)("steps")}`;
|
|
162
|
+
const order = (distance, steps) => metrics.minimize === "steps"
|
|
163
|
+
? `ROW(${steps}, ${distance})`
|
|
164
|
+
: `ROW(${distance}, ${steps})`;
|
|
165
|
+
const candidateOrder = order(candidateDistance, candidateSteps);
|
|
166
|
+
const selectedDistance = `arg_min(${candidateDistance}, ${candidateOrder})`;
|
|
167
|
+
const selectedSteps = `arg_min(${candidateSteps}, ${candidateOrder})`;
|
|
149
168
|
return `WITH RECURSIVE ${startValuesRelation}(${(0, quoteIdentifier_js_1.default)("start")}) AS (
|
|
150
169
|
VALUES ${prepared.startValues}
|
|
151
170
|
), ${startsRelation} AS (
|
|
@@ -159,19 +178,20 @@ function distancesSelect(input, schema, source, target, starts, direction, weigh
|
|
|
159
178
|
), ${distancesRelation}(
|
|
160
179
|
${(0, quoteIdentifier_js_1.default)("start")}, ${(0, quoteIdentifier_js_1.default)("node")},
|
|
161
180
|
${(0, quoteIdentifier_js_1.default)("__start_key")}, ${(0, quoteIdentifier_js_1.default)("__node_key")},
|
|
162
|
-
${(0, quoteIdentifier_js_1.default)("distance")}
|
|
181
|
+
${(0, quoteIdentifier_js_1.default)("distance")}, ${(0, quoteIdentifier_js_1.default)("steps")}
|
|
163
182
|
) USING KEY(
|
|
164
183
|
${(0, quoteIdentifier_js_1.default)("__start_key")}, ${(0, quoteIdentifier_js_1.default)("__node_key")}
|
|
165
184
|
) AS (
|
|
166
185
|
SELECT ${start}, ${edgeTo}, ${startKey}, ${edgeToKey},
|
|
167
|
-
MIN(${edgeCost}) AS ${(0, quoteIdentifier_js_1.default)("distance")}
|
|
186
|
+
MIN(${edgeCost}) AS ${(0, quoteIdentifier_js_1.default)("distance")}, CAST(1 AS BIGINT)
|
|
168
187
|
FROM ${startsRelation} AS ${(0, quoteIdentifier_js_1.default)("starts")}
|
|
169
188
|
INNER JOIN ${edgesRelation} AS ${(0, quoteIdentifier_js_1.default)("edges")}
|
|
170
189
|
ON ${startKey} = ${edgeFromKey}
|
|
171
190
|
GROUP BY ${start}, ${edgeTo}, ${startKey}, ${edgeToKey}
|
|
172
191
|
UNION
|
|
173
192
|
SELECT ${reachedStart}, ${edgeTo}, ${reachedStartKey}, ${edgeToKey},
|
|
174
|
-
|
|
193
|
+
${selectedDistance} AS ${(0, quoteIdentifier_js_1.default)("distance")},
|
|
194
|
+
${selectedSteps} AS ${(0, quoteIdentifier_js_1.default)("steps")}
|
|
175
195
|
FROM ${distancesRelation} AS ${(0, quoteIdentifier_js_1.default)("reached")}
|
|
176
196
|
INNER JOIN ${edgesRelation} AS ${(0, quoteIdentifier_js_1.default)("edges")}
|
|
177
197
|
ON ${reachedNodeKey} = ${edgeFromKey}
|
|
@@ -179,25 +199,259 @@ function distancesSelect(input, schema, source, target, starts, direction, weigh
|
|
|
179
199
|
ON ${reachedStartKey} = ${(0, quoteIdentifier_js_1.default)("best")}.${(0, quoteIdentifier_js_1.default)("__start_key")}
|
|
180
200
|
AND ${edgeToKey} = ${(0, quoteIdentifier_js_1.default)("best")}.${(0, quoteIdentifier_js_1.default)("__node_key")}
|
|
181
201
|
GROUP BY ${reachedStart}, ${edgeTo}, ${reachedStartKey}, ${edgeToKey},
|
|
182
|
-
${bestDistance}
|
|
183
|
-
HAVING ${bestDistance} IS NULL OR
|
|
202
|
+
${bestDistance}, ${bestSteps}
|
|
203
|
+
HAVING ${bestDistance} IS NULL OR
|
|
204
|
+
${order(selectedDistance, selectedSteps)} < ${order(bestDistance, bestSteps)}
|
|
184
205
|
)
|
|
185
206
|
SELECT ${(0, quoteIdentifier_js_1.default)("start")}, ${(0, quoteIdentifier_js_1.default)("node")},
|
|
186
|
-
${(0, quoteIdentifier_js_1.default)("
|
|
207
|
+
${(0, quoteIdentifier_js_1.default)("steps")}${weight === undefined
|
|
208
|
+
? ""
|
|
209
|
+
: `, ${(0, quoteIdentifier_js_1.default)("distance")} AS ${(0, quoteIdentifier_js_1.default)("total")}`}
|
|
187
210
|
FROM ${distancesRelation}
|
|
188
|
-
ORDER BY ${(0, quoteIdentifier_js_1.default)("__start_key")}, ${(0, quoteIdentifier_js_1.default)("distance")}, ${(0, quoteIdentifier_js_1.default)("__node_key")}`;
|
|
211
|
+
ORDER BY ${(0, quoteIdentifier_js_1.default)("__start_key")}, ${(0, quoteIdentifier_js_1.default)(metrics.minimize === "steps" ? "steps" : "distance")}, ${(0, quoteIdentifier_js_1.default)("__node_key")}`;
|
|
189
212
|
}
|
|
190
|
-
function temporalDistancesSelect(prepared, direction, temporal, distanceType, edgeWeight) {
|
|
213
|
+
function temporalDistancesSelect(prepared, direction, temporal, distanceType, edgeWeight, minimize, includeTotal) {
|
|
191
214
|
const q = quoteIdentifier_js_1.default;
|
|
192
215
|
const startsSelect = `SELECT ${q("start")},
|
|
193
216
|
${prepared.key(q("start"))} AS ${q("__key")}
|
|
194
217
|
FROM (VALUES ${prepared.startValues}) AS ${q("start_values")}(${q("start")})`;
|
|
195
|
-
const costStates = (0, buildGraphTemporalCostStateSql_js_1.default)(prepared, startsSelect, direction, temporal, distanceType, edgeWeight);
|
|
218
|
+
const costStates = (0, buildGraphTemporalCostStateSql_js_1.default)(prepared, startsSelect, direction, temporal, distanceType, edgeWeight, [], minimize);
|
|
219
|
+
const order = minimize === "steps"
|
|
220
|
+
? `${q("steps")}, ${q("distance")}`
|
|
221
|
+
: `${q("distance")}, ${q("steps")}`;
|
|
196
222
|
return `${costStates.withClause}
|
|
197
|
-
SELECT ${q("start")}, ${q("node")},
|
|
198
|
-
MIN(${q("distance")}) AS ${q("distance")}
|
|
223
|
+
SELECT ${q("start")}, ${q("node")}, ${q("steps")}${includeTotal ? `, ${q("distance")} AS ${q("total")}` : ""}
|
|
199
224
|
FROM ${costStates.costRelation}
|
|
200
|
-
|
|
201
|
-
${q("__node_key")}
|
|
202
|
-
|
|
225
|
+
QUALIFY row_number() OVER (
|
|
226
|
+
PARTITION BY ${q("__start_key")}, ${q("__node_key")}
|
|
227
|
+
ORDER BY ${order}
|
|
228
|
+
) = 1
|
|
229
|
+
ORDER BY ${q("__start_key")}, ${q(minimize === "steps" ? "steps" : "distance")}, ${q("__node_key")}`;
|
|
230
|
+
}
|
|
231
|
+
// Distinct visited sets, metrics, and temporal boundaries are enough to extend
|
|
232
|
+
// summaries. No edge IDs or full connection sequences are needed. Keeping the
|
|
233
|
+
// visited set is necessary: equal summaries can have different legal extensions.
|
|
234
|
+
function summaryDistancesSelect(prepared, direction, temporal, distanceType, edgeWeight, metrics, includeTotal, floatingWeight) {
|
|
235
|
+
const q = quoteIdentifier_js_1.default;
|
|
236
|
+
const relations = prepared.relationNames([
|
|
237
|
+
"graph_starts",
|
|
238
|
+
"graph_temporal_settings",
|
|
239
|
+
"graph_event_rows",
|
|
240
|
+
"graph_edges",
|
|
241
|
+
"graph_summaries",
|
|
242
|
+
"graph_metric_results",
|
|
243
|
+
"graph_tied_summaries",
|
|
244
|
+
"graph_best_metrics",
|
|
245
|
+
"graph_metric_bounds",
|
|
246
|
+
]);
|
|
247
|
+
const starts = relations.graph_starts;
|
|
248
|
+
const settings = relations.graph_temporal_settings;
|
|
249
|
+
const events = relations.graph_event_rows;
|
|
250
|
+
const edges = relations.graph_edges;
|
|
251
|
+
const summaries = relations.graph_summaries;
|
|
252
|
+
const results = relations.graph_metric_results;
|
|
253
|
+
const tied = relations.graph_tied_summaries;
|
|
254
|
+
const ref = (alias, column) => `${q(alias)}.${q(column)}`;
|
|
255
|
+
const searchDirection = direction;
|
|
256
|
+
const firstAnchor = temporal?.journeyAnchor("edges", searchDirection);
|
|
257
|
+
const sum = `CAST(${ref("reached", "distance")} + ${ref("edges", "__weight")} AS ${distanceType})`;
|
|
258
|
+
// Reported costs must not reject routes before the primary objective has
|
|
259
|
+
// selected its results. NULL marks overflow and propagates through sums;
|
|
260
|
+
// non-negative weights cannot bring an overflowing total back into range.
|
|
261
|
+
const nextDistance = metrics.minimize === "weight" ? sum : `TRY(${sum})`;
|
|
262
|
+
const temporalColumns = temporal === undefined
|
|
263
|
+
? ""
|
|
264
|
+
: `, ${q("__event_start")}, ${q("__event_end")}`;
|
|
265
|
+
const eventValues = temporal === undefined
|
|
266
|
+
? ""
|
|
267
|
+
: `, ${ref("edges", "__event_start")}, ${ref("edges", "__event_end")}`;
|
|
268
|
+
const metric = metrics.minimize === "steps"
|
|
269
|
+
? q("steps")
|
|
270
|
+
: metrics.minimize === "weight"
|
|
271
|
+
? q("distance")
|
|
272
|
+
: q("__elapsed");
|
|
273
|
+
// Use native time precision for selection. Collapse equal reported values
|
|
274
|
+
// after conversion to milliseconds, since these are summary rows.
|
|
275
|
+
const reportedElapsed = metrics.elapsedTime
|
|
276
|
+
? `, ${temporal.elapsedMilliseconds(q("__elapsed"))} AS ${q("elapsedTimeMs")}`
|
|
277
|
+
: "";
|
|
278
|
+
const order = metrics.minimize === "steps"
|
|
279
|
+
? [
|
|
280
|
+
q("steps"),
|
|
281
|
+
q("__node_key"),
|
|
282
|
+
...(includeTotal ? [q("total")] : []),
|
|
283
|
+
...(metrics.elapsedTime ? [q("elapsedTimeMs")] : []),
|
|
284
|
+
]
|
|
285
|
+
: metrics.minimize === "weight"
|
|
286
|
+
? [
|
|
287
|
+
q("total"),
|
|
288
|
+
q("__node_key"),
|
|
289
|
+
q("steps"),
|
|
290
|
+
...(metrics.elapsedTime ? [q("elapsedTimeMs")] : []),
|
|
291
|
+
]
|
|
292
|
+
: [
|
|
293
|
+
q("elapsedTimeMs"),
|
|
294
|
+
q("__node_key"),
|
|
295
|
+
q("steps"),
|
|
296
|
+
...(includeTotal ? [q("total")] : []),
|
|
297
|
+
];
|
|
298
|
+
const bounds = summaryBoundsSql(relations.graph_best_metrics, relations.graph_metric_bounds, starts, edges, settings, temporal, searchDirection, metrics.minimize, distanceType, floatingWeight);
|
|
299
|
+
return `WITH RECURSIVE ${settings} AS (
|
|
300
|
+
${temporal === undefined
|
|
301
|
+
? `SELECT 0 AS ${q("__gap")}`
|
|
302
|
+
: `SELECT CAST(? AS HUGEINT) AS ${q("__gap")}`}
|
|
303
|
+
), ${events} AS MATERIALIZED (
|
|
304
|
+
${prepared.edges(direction, [
|
|
305
|
+
`${edgeWeight} AS ${q("__weight")}`,
|
|
306
|
+
...(temporal?.eventSelections("edges") ?? []),
|
|
307
|
+
])}
|
|
308
|
+
), ${edges} AS MATERIALIZED (
|
|
309
|
+
SELECT DISTINCT ${q("__from")}, ${q("__to")}, ${q("__from_key")},
|
|
310
|
+
${q("__to_key")}, ${q("__weight")}${temporalColumns}
|
|
311
|
+
FROM ${events} AS ${q("events")}
|
|
312
|
+
${temporal === undefined ? "" : `WHERE ${temporal.eventValidity("events")}`}
|
|
313
|
+
), ${starts} AS (
|
|
314
|
+
SELECT ${q("start")}, ${prepared.key(q("start"))} AS ${q("__key")}
|
|
315
|
+
FROM (VALUES ${prepared.startValues}) AS ${q("start_values")}(${q("start")})
|
|
316
|
+
), ${bounds.ctes}, ${summaries}(
|
|
317
|
+
${q("start")}, ${q("node")}, ${q("__start_key")}, ${q("__node_key")},
|
|
318
|
+
${q("__visited")}, ${q("steps")}, ${q("distance")}${temporalColumns}${metrics.elapsedTime ? `, ${q("__anchor")}` : ""}
|
|
319
|
+
) AS (
|
|
320
|
+
SELECT ${ref("starts", "start")}, ${ref("edges", "__to")},
|
|
321
|
+
${ref("starts", "__key")}, ${ref("edges", "__to_key")},
|
|
322
|
+
list_sort(list_distinct([${ref("starts", "__key")}, ${ref("edges", "__to_key")}])),
|
|
323
|
+
CAST(1 AS BIGINT), ${ref("edges", "__weight")}${eventValues}${metrics.elapsedTime ? `, ${firstAnchor}` : ""}
|
|
324
|
+
FROM ${starts} AS ${q("starts")}
|
|
325
|
+
INNER JOIN ${edges} AS ${q("edges")}
|
|
326
|
+
ON ${ref("starts", "__key")} = ${ref("edges", "__from_key")}
|
|
327
|
+
${bounds.join(ref("starts", "__key"))}
|
|
328
|
+
WHERE ${bounds.test("CAST(1 AS BIGINT)", ref("edges", "__weight"), firstAnchor)}
|
|
329
|
+
UNION
|
|
330
|
+
SELECT ${ref("reached", "start")}, ${ref("edges", "__to")},
|
|
331
|
+
${ref("reached", "__start_key")}, ${ref("edges", "__to_key")},
|
|
332
|
+
list_sort(list_distinct(list_append(${ref("reached", "__visited")}, ${ref("edges", "__to_key")}))),
|
|
333
|
+
${ref("reached", "steps")} + 1, ${nextDistance}${eventValues}${metrics.elapsedTime ? `, ${ref("reached", "__anchor")}` : ""}
|
|
334
|
+
FROM ${summaries} AS ${q("reached")}
|
|
335
|
+
INNER JOIN ${edges} AS ${q("edges")}
|
|
336
|
+
ON ${ref("reached", "__node_key")} = ${ref("edges", "__from_key")}
|
|
337
|
+
CROSS JOIN ${settings} AS ${q("settings")}
|
|
338
|
+
${bounds.join(ref("reached", "__start_key"))}
|
|
339
|
+
WHERE ${bounds.test(`${ref("reached", "steps")} + 1`, nextDistance, ref("reached", "__anchor"))}
|
|
340
|
+
AND ${ref("reached", "__node_key")} <> ${ref("reached", "__start_key")}
|
|
341
|
+
AND (NOT list_contains(${ref("reached", "__visited")}, ${ref("edges", "__to_key")})
|
|
342
|
+
OR ${ref("edges", "__to_key")} = ${ref("reached", "__start_key")})
|
|
343
|
+
${temporal === undefined ? "" : `AND ${temporal.transition("reached", "edges", searchDirection, ref("settings", "__gap"))}`}
|
|
344
|
+
), ${results} AS (
|
|
345
|
+
SELECT *${metrics.elapsedTime
|
|
346
|
+
? `, ${temporal.journeyElapsed("summaries", ref("summaries", "__anchor"), searchDirection)} AS ${q("__elapsed")}`
|
|
347
|
+
: ""}
|
|
348
|
+
FROM ${summaries} AS ${q("summaries")}
|
|
349
|
+
), ${tied} AS MATERIALIZED (
|
|
350
|
+
SELECT DISTINCT ${q("start")}, ${q("node")}, ${q("__start_key")}, ${q("__node_key")},
|
|
351
|
+
${q("steps")}${includeTotal ? `, ${q("distance")} AS ${q("total")}` : ""}${reportedElapsed}
|
|
352
|
+
FROM ${results}
|
|
353
|
+
QUALIFY ${metric} = MIN(${metric}) OVER (
|
|
354
|
+
PARTITION BY ${q("__start_key")}, ${q("__node_key")}
|
|
355
|
+
)
|
|
356
|
+
)
|
|
357
|
+
SELECT ${q("start")}, ${q("node")}, ${q("steps")}${includeTotal
|
|
358
|
+
? `, CASE WHEN ${q("total")} IS NULL
|
|
359
|
+
THEN error('distances() total exceeds the supported ${distanceType} range for an optimal route.')
|
|
360
|
+
ELSE ${q("total")} END AS ${q("total")}`
|
|
361
|
+
: ""}${metrics.elapsedTime ? `, ${q("elapsedTimeMs")}` : ""}
|
|
362
|
+
FROM ${tied}
|
|
363
|
+
ORDER BY ${q("__start_key")}, ${order.join(", ")}`;
|
|
364
|
+
}
|
|
365
|
+
// Compute primary optima without enumerating visited sets. Exact additive
|
|
366
|
+
// objectives have optimal prefixes (at the same event boundary in temporal
|
|
367
|
+
// traversal). Floating addition can erase prefix differences, and elapsed
|
|
368
|
+
// optima can depend on a later departure, so those use a per-start upper bound.
|
|
369
|
+
function summaryBoundsSql(best, limits, starts, edges, settings, temporal, direction, minimize, distanceType, floatingWeight) {
|
|
370
|
+
const q = quoteIdentifier_js_1.default;
|
|
371
|
+
const ref = (alias, column) => `${q(alias)}.${q(column)}`;
|
|
372
|
+
const elapsed = minimize === "elapsedTime";
|
|
373
|
+
const globalBound = elapsed || (minimize === "weight" && floatingWeight);
|
|
374
|
+
const boundaries = temporal === undefined
|
|
375
|
+
? []
|
|
376
|
+
: ["__event_start", "__event_end"];
|
|
377
|
+
const keys = [
|
|
378
|
+
"__start_key",
|
|
379
|
+
"__node_key",
|
|
380
|
+
...boundaries,
|
|
381
|
+
...(elapsed ? ["__anchor"] : []),
|
|
382
|
+
];
|
|
383
|
+
const firstAnchor = elapsed
|
|
384
|
+
? temporal.journeyAnchor("edges", direction)
|
|
385
|
+
: undefined;
|
|
386
|
+
const firstKeys = [
|
|
387
|
+
ref("starts", "__key"),
|
|
388
|
+
ref("edges", "__to_key"),
|
|
389
|
+
...boundaries.map((key) => ref("edges", key)),
|
|
390
|
+
...(elapsed ? [firstAnchor] : []),
|
|
391
|
+
];
|
|
392
|
+
const nextKeys = [
|
|
393
|
+
ref("reached", "__start_key"),
|
|
394
|
+
ref("edges", "__to_key"),
|
|
395
|
+
...boundaries.map((key) => ref("edges", key)),
|
|
396
|
+
...(elapsed ? [ref("reached", "__anchor")] : []),
|
|
397
|
+
];
|
|
398
|
+
const firstMetric = minimize === "steps"
|
|
399
|
+
? "CAST(1 AS BIGINT)"
|
|
400
|
+
: elapsed
|
|
401
|
+
? temporal.journeyElapsed("edges", firstAnchor, direction)
|
|
402
|
+
: ref("edges", "__weight");
|
|
403
|
+
const nextMetric = minimize === "steps"
|
|
404
|
+
? `${ref("reached", "__metric")} + 1`
|
|
405
|
+
: elapsed
|
|
406
|
+
? temporal.journeyElapsed("edges", ref("reached", "__anchor"), direction)
|
|
407
|
+
: `CAST(${ref("reached", "__metric")} + ${ref("edges", "__weight")} AS ${distanceType})`;
|
|
408
|
+
const minimum = `MIN(${nextMetric})`;
|
|
409
|
+
const bestMetric = ref("best", "__metric");
|
|
410
|
+
const ctes = `${best}(${keys.map(q).join(", ")}, ${q("__metric")})
|
|
411
|
+
USING KEY(${keys.map(q).join(", ")}) AS (
|
|
412
|
+
SELECT ${firstKeys.join(", ")}, MIN(${firstMetric})
|
|
413
|
+
FROM ${starts} AS ${q("starts")}
|
|
414
|
+
INNER JOIN ${edges} AS ${q("edges")}
|
|
415
|
+
ON ${ref("starts", "__key")} = ${ref("edges", "__from_key")}
|
|
416
|
+
GROUP BY ${firstKeys.join(", ")}
|
|
417
|
+
UNION
|
|
418
|
+
SELECT ${nextKeys.join(", ")}, ${minimum}
|
|
419
|
+
FROM ${best} AS ${q("reached")}
|
|
420
|
+
INNER JOIN ${edges} AS ${q("edges")}
|
|
421
|
+
ON ${ref("reached", "__node_key")} = ${ref("edges", "__from_key")}
|
|
422
|
+
CROSS JOIN ${settings} AS ${q("settings")}
|
|
423
|
+
LEFT JOIN recurring.${best} AS ${q("best")}
|
|
424
|
+
ON ${keys.map((key, i) => `${ref("best", key)} = ${nextKeys[i]}`).join(" AND ")}
|
|
425
|
+
WHERE ${ref("reached", "__node_key")} <> ${ref("reached", "__start_key")}
|
|
426
|
+
${temporal === undefined ? "" : `AND ${temporal.transition("reached", "edges", direction, ref("settings", "__gap"))}`}
|
|
427
|
+
GROUP BY ${nextKeys.join(", ")}, ${bestMetric}
|
|
428
|
+
HAVING ${bestMetric} IS NULL OR ${minimum} < ${bestMetric}
|
|
429
|
+
)${globalBound
|
|
430
|
+
? `, ${limits} AS (
|
|
431
|
+
SELECT ${q("__start_key")}, MAX(${q("__minimum")}) AS ${q("__metric")}
|
|
432
|
+
FROM (
|
|
433
|
+
SELECT ${q("__start_key")}, ${q("__node_key")}, MIN(${q("__metric")}) AS ${q("__minimum")}
|
|
434
|
+
FROM ${best}
|
|
435
|
+
GROUP BY ${q("__start_key")}, ${q("__node_key")}
|
|
436
|
+
) AS ${q("minima")}
|
|
437
|
+
GROUP BY ${q("__start_key")}
|
|
438
|
+
)`
|
|
439
|
+
: ""}`;
|
|
440
|
+
return {
|
|
441
|
+
ctes,
|
|
442
|
+
join: (startKey) => `INNER JOIN ${globalBound ? limits : best} AS ${q("bounds")}
|
|
443
|
+
ON ${ref("bounds", "__start_key")} = ${startKey}
|
|
444
|
+
${globalBound
|
|
445
|
+
? ""
|
|
446
|
+
: `AND ${ref("bounds", "__node_key")} = ${ref("edges", "__to_key")}
|
|
447
|
+
${boundaries.map((key) => `AND ${ref("bounds", key)} = ${ref("edges", key)}`).join(" ")}`}`,
|
|
448
|
+
test: (steps, distance, anchor) => {
|
|
449
|
+
const metric = minimize === "steps"
|
|
450
|
+
? steps
|
|
451
|
+
: elapsed
|
|
452
|
+
? temporal.journeyElapsed("edges", anchor, direction)
|
|
453
|
+
: distance;
|
|
454
|
+
return `${metric} ${globalBound ? "<=" : "="} ${ref("bounds", "__metric")}`;
|
|
455
|
+
},
|
|
456
|
+
};
|
|
203
457
|
}
|
|
@@ -3,6 +3,7 @@ import { type GraphTemporalOptions } from "../helpers/prepareGraphTemporalSql.js
|
|
|
3
3
|
import { type GraphId } from "../helpers/prepareGraphStarts.js";
|
|
4
4
|
import { type GraphDirection } from "../helpers/prepareGraphTraversal.js";
|
|
5
5
|
type FindCyclesOptions = GraphTemporalOptions & {
|
|
6
|
+
elapsedTime?: boolean;
|
|
6
7
|
direction?: GraphDirection;
|
|
7
8
|
outputTable?: string | boolean;
|
|
8
9
|
weight?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findCycles.d.ts","sourceRoot":"","sources":["../../src/methods/findCycles.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"findCycles.d.ts","sourceRoot":"","sources":["../../src/methods/findCycles.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAMvD,OAAgC,EAC9B,KAAK,oBAAoB,EAG1B,MAAM,uCAAuC,CAAC;AAC/C,OAA2B,EACzB,KAAK,OAAO,EAEb,MAAM,kCAAkC,CAAC;AAC1C,OAA8B,EAC5B,KAAK,cAAc,EAEpB,MAAM,qCAAqC,CAAC;AAM7C,KAAK,iBAAiB,GAAG,oBAAoB,GAAG;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,UAAU,CAChC,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,OAAO,GAAG,OAAO,EAAE,EAC/B,OAAO,GAAE,iBAAsB,GAC9B,WAAW,CAgIb"}
|
|
@@ -37,6 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.default = findCycles;
|
|
40
|
+
const prepareGraphMetricOptions_js_1 = __importDefault(require("../helpers/prepareGraphMetricOptions.js"));
|
|
40
41
|
const getGraphEdgeIdColumn_js_1 = __importDefault(require("../helpers/getGraphEdgeIdColumn.js"));
|
|
41
42
|
const getGraphWeightColumn_js_1 = __importDefault(require("../helpers/getGraphWeightColumn.js"));
|
|
42
43
|
const graphRouteResultSchema_js_1 = __importDefault(require("../helpers/graphRouteResultSchema.js"));
|
|
@@ -74,6 +75,7 @@ function findCycles(simpleTable, sourceColumn, targetColumn, edgeId, startNodes,
|
|
|
74
75
|
typeof options.outputTable !== "boolean") {
|
|
75
76
|
throw new TypeError("findCycles() options.outputTable must be a string or boolean.");
|
|
76
77
|
}
|
|
78
|
+
const metric = (0, prepareGraphMetricOptions_js_1.default)(options, "findCycles()", false);
|
|
77
79
|
const direction = options.direction ?? "outgoing";
|
|
78
80
|
const temporalOptions = (0, prepareGraphTemporalSql_js_1.prepareGraphTemporalOptions)(options, direction, "findCycles()");
|
|
79
81
|
options = structuredClone(options);
|
|
@@ -92,7 +94,8 @@ function findCycles(simpleTable, sourceColumn, targetColumn, edgeId, startNodes,
|
|
|
92
94
|
? undefined
|
|
93
95
|
: (input) => (0, validateGraphTemporalEvents_js_1.default)(input, temporalOptions, "findCycles()", parameters),
|
|
94
96
|
values: (schema) => {
|
|
95
|
-
validateFindCyclesInputs(schema, sourceColumn, targetColumn, edgeId, preparedStarts, options.weight);
|
|
97
|
+
const validated = validateFindCyclesInputs(schema, sourceColumn, targetColumn, edgeId, preparedStarts, options.weight);
|
|
98
|
+
(0, graphRouteResultSchema_js_1.default)(schema, validated.distanceType, "findCycles()", metric.elapsedTime);
|
|
96
99
|
const temporal = temporalOptions === undefined
|
|
97
100
|
? undefined
|
|
98
101
|
: (0, prepareGraphTemporalSql_js_1.default)(schema, temporalOptions, "findCycles()");
|
|
@@ -100,7 +103,7 @@ function findCycles(simpleTable, sourceColumn, targetColumn, edgeId, startNodes,
|
|
|
100
103
|
? preparedStarts.values
|
|
101
104
|
: [temporal.gapParameter, ...preparedStarts.values];
|
|
102
105
|
},
|
|
103
|
-
buildSelect: (input, schema) => findCyclesSelect(input, schema, sourceColumn, targetColumn, edgeId, preparedStarts, direction, options.weight, temporalOptions),
|
|
106
|
+
buildSelect: (input, schema) => findCyclesSelect(input, schema, sourceColumn, targetColumn, edgeId, preparedStarts, direction, options.weight, temporalOptions, metric.elapsedTime),
|
|
104
107
|
outputSchema: (schema) => {
|
|
105
108
|
const validated = validateFindCyclesInputs(schema, sourceColumn, targetColumn, edgeId, preparedStarts, options.weight);
|
|
106
109
|
if (temporalOptions !== undefined) {
|
|
@@ -108,7 +111,7 @@ function findCycles(simpleTable, sourceColumn, targetColumn, edgeId, startNodes,
|
|
|
108
111
|
}
|
|
109
112
|
return {
|
|
110
113
|
start: validated.nodeIdType,
|
|
111
|
-
...(0, graphRouteResultSchema_js_1.default)(schema, validated.distanceType, "findCycles()"),
|
|
114
|
+
...(0, graphRouteResultSchema_js_1.default)(schema, validated.distanceType, "findCycles()", metric.elapsedTime),
|
|
112
115
|
};
|
|
113
116
|
},
|
|
114
117
|
});
|
|
@@ -126,7 +129,7 @@ function validateFindCyclesInputs(schema, source, target, edgeId, starts, weight
|
|
|
126
129
|
nodeIdType: endpoints.idType,
|
|
127
130
|
};
|
|
128
131
|
}
|
|
129
|
-
function findCyclesSelect(input, schema, source, target, edgeId, starts, direction, weight, temporalOptions) {
|
|
132
|
+
function findCyclesSelect(input, schema, source, target, edgeId, starts, direction, weight, temporalOptions, elapsedTime) {
|
|
130
133
|
const prepared = (0, prepareGraphTraversal_js_1.default)(input, schema, source, target, starts, "findCycles()", "startNodes");
|
|
131
134
|
const edgeIdColumn = (0, getGraphEdgeIdColumn_js_1.default)(schema, edgeId, "findCycles()");
|
|
132
135
|
const weightColumn = weight === undefined
|
|
@@ -142,10 +145,10 @@ function findCyclesSelect(input, schema, source, target, edgeId, starts, directi
|
|
|
142
145
|
const edgeWeight = weightColumn === undefined
|
|
143
146
|
? `CAST(1 AS ${distanceType})`
|
|
144
147
|
: `CAST(${q("edges")}.${q(weightColumn.column)} AS ${distanceType})`;
|
|
145
|
-
const stepType = `STRUCT(${q("edgeId")} ${edgeIdColumn.idType}, ${q("source")} ${prepared.endpoints.idType}, ${q("target")} ${prepared.endpoints.idType}, ${q("weight")} ${distanceType}, ${q("distance")} ${distanceType})`;
|
|
148
|
+
const stepType = `STRUCT(${q("edgeId")} ${edgeIdColumn.idType}, ${q("source")} ${prepared.endpoints.idType}, ${q("target")} ${prepared.endpoints.idType}, ${q("weight")} ${distanceType}, ${q("distance")} ${distanceType}${elapsedTime ? `, ${q("elapsedTimeMs")} DOUBLE` : ""})`;
|
|
146
149
|
if (temporalOptions !== undefined) {
|
|
147
150
|
const temporal = (0, prepareGraphTemporalSql_js_1.default)(schema, temporalOptions, "findCycles()");
|
|
148
|
-
return temporalFindCyclesSelect(prepared, direction, temporal, typedEdgeId, edgeKey, edgeWeight, distanceType, stepType, input, edgeIdColumn);
|
|
151
|
+
return temporalFindCyclesSelect(prepared, direction, temporal, typedEdgeId, edgeKey, edgeWeight, distanceType, stepType, input, edgeIdColumn, elapsedTime);
|
|
149
152
|
}
|
|
150
153
|
const relations = prepared.relationNames([
|
|
151
154
|
"graph_start_values",
|
|
@@ -249,7 +252,7 @@ function findCyclesSelect(input, schema, source, target, edgeId, starts, directi
|
|
|
249
252
|
)
|
|
250
253
|
${(0, graphRouteResultSelect_js_1.default)(rankedRelation, input, edgeIdColumn, true)}`;
|
|
251
254
|
}
|
|
252
|
-
function temporalFindCyclesSelect(prepared, direction, temporal, typedEdgeId, edgeKey, edgeWeight, distanceType, stepType, input, edgeIdColumn) {
|
|
255
|
+
function temporalFindCyclesSelect(prepared, direction, temporal, typedEdgeId, edgeKey, edgeWeight, distanceType, stepType, input, edgeIdColumn, elapsedTime) {
|
|
253
256
|
const q = quoteIdentifier_js_1.default;
|
|
254
257
|
const relations = prepared.relationNames([
|
|
255
258
|
"graph_start_values",
|
|
@@ -279,12 +282,16 @@ function temporalFindCyclesSelect(prepared, direction, temporal, typedEdgeId, ed
|
|
|
279
282
|
const walkDistance = `${q("walks")}.${q("distance")}`;
|
|
280
283
|
const candidateDistance = `CAST(${walkDistance} + ${edgeCost} AS ${distanceType})`;
|
|
281
284
|
const gap = `${q("settings")}.${q("__gap")}`;
|
|
282
|
-
const
|
|
285
|
+
const firstAnchor = temporal.journeyAnchor("edges", direction);
|
|
286
|
+
const anchor = `${q("walks")}.${q("__journey_anchor")}`;
|
|
287
|
+
const step = (distance, journeyAnchor) => `struct_pack(
|
|
283
288
|
${q("edgeId")} := ${edgeIdentity},
|
|
284
289
|
${q("source")} := ${edgeFrom},
|
|
285
290
|
${q("target")} := ${edgeTo},
|
|
286
291
|
${q("weight")} := ${edgeCost},
|
|
287
|
-
${q("distance")} := ${distance}
|
|
292
|
+
${q("distance")} := ${distance}${elapsedTime
|
|
293
|
+
? `, ${q("elapsedTimeMs")} := ${temporal.elapsedMilliseconds(temporal.journeyElapsed("edges", journeyAnchor, direction))}`
|
|
294
|
+
: ""}
|
|
288
295
|
)`;
|
|
289
296
|
return `WITH RECURSIVE ${settingsRelation} AS MATERIALIZED (
|
|
290
297
|
SELECT CAST(? AS HUGEINT) AS ${q("__gap")}
|
|
@@ -310,7 +317,7 @@ function temporalFindCyclesSelect(prepared, direction, temporal, typedEdgeId, ed
|
|
|
310
317
|
${q("__node_key")}, ${q("__visited")}, ${q("__event_ids")},
|
|
311
318
|
${q("__edge_keys")}, ${q("steps")}, ${q("distance")},
|
|
312
319
|
${q("closed")}, ${q("__event_id")}, ${q("__event_start")},
|
|
313
|
-
${q("__event_end")}
|
|
320
|
+
${q("__event_end")}${elapsedTime ? `, ${q("__journey_anchor")}` : ""}
|
|
314
321
|
) AS (
|
|
315
322
|
SELECT ${q("starts")}.${q("start")},
|
|
316
323
|
${q("starts")}.${q("__start_key")}, ${edgeTo}, ${edgeToKey},
|
|
@@ -319,11 +326,11 @@ function temporalFindCyclesSelect(prepared, direction, temporal, typedEdgeId, ed
|
|
|
319
326
|
ELSE [${edgeFromKey}, ${edgeToKey}]
|
|
320
327
|
END,
|
|
321
328
|
[${q("edges")}.${q("__event_id")}], [${edgeIdentityKey}],
|
|
322
|
-
[${step(edgeCost)}]::${stepType}[], ${edgeCost},
|
|
329
|
+
[${step(edgeCost, firstAnchor)}]::${stepType}[], ${edgeCost},
|
|
323
330
|
${edgeFromKey} = ${edgeToKey},
|
|
324
331
|
${q("edges")}.${q("__event_id")},
|
|
325
332
|
${q("edges")}.${q("__event_start")},
|
|
326
|
-
${q("edges")}.${q("__event_end")}
|
|
333
|
+
${q("edges")}.${q("__event_end")}${elapsedTime ? `, ${firstAnchor}` : ""}
|
|
327
334
|
FROM ${edgesRelation} AS ${q("edges")}
|
|
328
335
|
INNER JOIN ${startsRelation} AS ${q("starts")}
|
|
329
336
|
ON ${q("starts")}.${q("__start_key")} = ${edgeFromKey}
|
|
@@ -334,12 +341,12 @@ function temporalFindCyclesSelect(prepared, direction, temporal, typedEdgeId, ed
|
|
|
334
341
|
list_append(${q("walks")}.${q("__event_ids")},
|
|
335
342
|
${q("edges")}.${q("__event_id")}),
|
|
336
343
|
list_append(${q("walks")}.${q("__edge_keys")}, ${edgeIdentityKey}),
|
|
337
|
-
list_append(${q("walks")}.${q("steps")}, ${step(candidateDistance)}),
|
|
344
|
+
list_append(${q("walks")}.${q("steps")}, ${step(candidateDistance, anchor)}),
|
|
338
345
|
${candidateDistance},
|
|
339
346
|
${edgeToKey} = ${q("walks")}.${q("__start_key")},
|
|
340
347
|
${q("edges")}.${q("__event_id")},
|
|
341
348
|
${q("edges")}.${q("__event_start")},
|
|
342
|
-
${q("edges")}.${q("__event_end")}
|
|
349
|
+
${q("edges")}.${q("__event_end")}${elapsedTime ? `, ${anchor}` : ""}
|
|
343
350
|
FROM ${walksRelation} AS ${q("walks")}
|
|
344
351
|
INNER JOIN ${edgesRelation} AS ${q("edges")}
|
|
345
352
|
ON ${q("walks")}.${q("__node_key")} = ${edgeFromKey}
|
|
@@ -365,5 +372,5 @@ function temporalFindCyclesSelect(prepared, direction, temporal, typedEdgeId, ed
|
|
|
365
372
|
AS BIGINT) AS ${q("pathId")}, ${q("steps")}
|
|
366
373
|
FROM ${completeRelation}
|
|
367
374
|
)
|
|
368
|
-
${(0, graphRouteResultSelect_js_1.default)(rankedRelation, input, edgeIdColumn, true)}`;
|
|
375
|
+
${(0, graphRouteResultSelect_js_1.default)(rankedRelation, input, edgeIdColumn, true, elapsedTime)}`;
|
|
369
376
|
}
|
|
@@ -3,6 +3,7 @@ import type { GraphId } from "../helpers/prepareGraphStarts.js";
|
|
|
3
3
|
import { type GraphTemporalOptions } from "../helpers/prepareGraphTemporalSql.js";
|
|
4
4
|
import type { GraphDirection } from "../helpers/prepareGraphTraversal.js";
|
|
5
5
|
type PathsOptions = GraphTemporalOptions & {
|
|
6
|
+
elapsedTime?: boolean;
|
|
6
7
|
direction?: GraphDirection;
|
|
7
8
|
outputTable?: string | boolean;
|
|
8
9
|
weight?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/methods/paths.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/methods/paths.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AASvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAChE,OAAgC,EAC9B,KAAK,oBAAoB,EAG1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAM1E,KAAK,YAAY,GAAG,oBAAoB,GAAG;IACzC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,KAAK,CAC3B,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,OAAO,EACZ,OAAO,GAAE,YAAiB,GACzB,WAAW,CA4Hb"}
|