@nshiab/simple-data-analysis-core 2.1.6 → 2.1.7
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 +249 -23
- package/esm/class/SimpleTable.d.ts.map +1 -1
- package/esm/class/SimpleTable.js +243 -23
- package/esm/helpers/graphRouteResultSchema.d.ts +1 -1
- package/esm/helpers/graphRouteResultSchema.d.ts.map +1 -1
- package/esm/helpers/graphRouteResultSchema.js +3 -2
- package/esm/helpers/graphRouteResultSelect.d.ts +1 -1
- package/esm/helpers/graphRouteResultSelect.d.ts.map +1 -1
- package/esm/helpers/graphRouteResultSelect.js +4 -1
- package/esm/helpers/prepareGraphMetricOptions.d.ts +14 -0
- package/esm/helpers/prepareGraphMetricOptions.d.ts.map +1 -0
- package/esm/helpers/prepareGraphMetricOptions.js +40 -0
- 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/methods/distances.d.ts +2 -0
- package/esm/methods/distances.d.ts.map +1 -1
- package/esm/methods/distances.js +98 -6
- 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 +125 -20
- package/llm.md +278 -53
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/script/class/SimpleTable.d.ts +249 -23
- package/script/class/SimpleTable.d.ts.map +1 -1
- package/script/class/SimpleTable.js +243 -23
- package/script/helpers/graphRouteResultSchema.d.ts +1 -1
- package/script/helpers/graphRouteResultSchema.d.ts.map +1 -1
- package/script/helpers/graphRouteResultSchema.js +3 -2
- package/script/helpers/graphRouteResultSelect.d.ts +1 -1
- package/script/helpers/graphRouteResultSelect.d.ts.map +1 -1
- package/script/helpers/graphRouteResultSelect.js +4 -1
- package/script/helpers/prepareGraphMetricOptions.d.ts +14 -0
- package/script/helpers/prepareGraphMetricOptions.d.ts.map +1 -0
- package/script/helpers/prepareGraphMetricOptions.js +43 -0
- 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/methods/distances.d.ts +2 -0
- package/script/methods/distances.d.ts.map +1 -1
- package/script/methods/distances.js +98 -6
- 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 +125 -20
|
@@ -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,14 @@ 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
|
+
total: validated.distanceType,
|
|
102
|
+
...(metrics.elapsedTime ? { elapsedTimeMs: "DOUBLE" } : {}),
|
|
100
103
|
};
|
|
101
104
|
},
|
|
102
105
|
});
|
|
@@ -111,7 +114,7 @@ function validateDistanceInputs(schema, source, target, starts, weight, temporal
|
|
|
111
114
|
: (0, prepareGraphTemporalSql_js_1.default)(schema, temporalOptions, "distances()");
|
|
112
115
|
return { idType: endpoints.idType, distanceType, temporal };
|
|
113
116
|
}
|
|
114
|
-
function distancesSelect(input, schema, source, target, starts, direction, weight, temporalOptions) {
|
|
117
|
+
function distancesSelect(input, schema, source, target, starts, direction, weight, temporalOptions, metrics) {
|
|
115
118
|
const prepared = (0, prepareGraphTraversal_js_1.default)(input, schema, source, target, starts, "distances()", "startNodes");
|
|
116
119
|
const weightColumn = weight === undefined
|
|
117
120
|
? undefined
|
|
@@ -122,6 +125,9 @@ function distancesSelect(input, schema, source, target, starts, direction, weigh
|
|
|
122
125
|
: `CAST(${(0, quoteIdentifier_js_1.default)("edges")}.${(0, quoteIdentifier_js_1.default)(weightColumn.column)} AS ${distanceType})`;
|
|
123
126
|
if (temporalOptions !== undefined) {
|
|
124
127
|
const temporal = (0, prepareGraphTemporalSql_js_1.default)(schema, temporalOptions, "distances()");
|
|
128
|
+
if (metrics.elapsedTime) {
|
|
129
|
+
return elapsedDistancesSelect(prepared, direction, temporal, distanceType, edgeWeight, metrics.minimize);
|
|
130
|
+
}
|
|
125
131
|
return temporalDistancesSelect(prepared, direction, temporal, distanceType, edgeWeight);
|
|
126
132
|
}
|
|
127
133
|
const relations = prepared.relationNames([
|
|
@@ -183,7 +189,7 @@ function distancesSelect(input, schema, source, target, starts, direction, weigh
|
|
|
183
189
|
HAVING ${bestDistance} IS NULL OR MIN(${candidateDistance}) < ${bestDistance}
|
|
184
190
|
)
|
|
185
191
|
SELECT ${(0, quoteIdentifier_js_1.default)("start")}, ${(0, quoteIdentifier_js_1.default)("node")},
|
|
186
|
-
${(0, quoteIdentifier_js_1.default)("distance")}
|
|
192
|
+
${(0, quoteIdentifier_js_1.default)("distance")} AS ${(0, quoteIdentifier_js_1.default)("total")}
|
|
187
193
|
FROM ${distancesRelation}
|
|
188
194
|
ORDER BY ${(0, quoteIdentifier_js_1.default)("__start_key")}, ${(0, quoteIdentifier_js_1.default)("distance")}, ${(0, quoteIdentifier_js_1.default)("__node_key")}`;
|
|
189
195
|
}
|
|
@@ -195,9 +201,95 @@ function temporalDistancesSelect(prepared, direction, temporal, distanceType, ed
|
|
|
195
201
|
const costStates = (0, buildGraphTemporalCostStateSql_js_1.default)(prepared, startsSelect, direction, temporal, distanceType, edgeWeight);
|
|
196
202
|
return `${costStates.withClause}
|
|
197
203
|
SELECT ${q("start")}, ${q("node")},
|
|
198
|
-
MIN(${q("distance")}) AS ${q("
|
|
204
|
+
MIN(${q("distance")}) AS ${q("total")}
|
|
199
205
|
FROM ${costStates.costRelation}
|
|
200
206
|
GROUP BY ${q("start")}, ${q("node")}, ${q("__start_key")},
|
|
201
207
|
${q("__node_key")}
|
|
202
|
-
ORDER BY ${q("__start_key")}, ${q("
|
|
208
|
+
ORDER BY ${q("__start_key")}, ${q("total")}, ${q("__node_key")}`;
|
|
209
|
+
}
|
|
210
|
+
function elapsedDistancesSelect(prepared, direction, temporal, distanceType, edgeWeight, minimize) {
|
|
211
|
+
const q = quoteIdentifier_js_1.default;
|
|
212
|
+
const relations = prepared.relationNames([
|
|
213
|
+
"graph_starts",
|
|
214
|
+
"graph_temporal_settings",
|
|
215
|
+
"graph_event_rows",
|
|
216
|
+
"graph_edges",
|
|
217
|
+
"graph_elapsed_states",
|
|
218
|
+
"graph_elapsed_results",
|
|
219
|
+
]);
|
|
220
|
+
const starts = relations.graph_starts;
|
|
221
|
+
const settings = relations.graph_temporal_settings;
|
|
222
|
+
const events = relations.graph_event_rows;
|
|
223
|
+
const edges = relations.graph_edges;
|
|
224
|
+
const states = relations.graph_elapsed_states;
|
|
225
|
+
const results = relations.graph_elapsed_results;
|
|
226
|
+
const ref = (alias, column) => `${q(alias)}.${q(column)}`;
|
|
227
|
+
const anchor = temporal.journeyAnchor("edges", direction);
|
|
228
|
+
const reachedAnchor = ref("reached", "__anchor");
|
|
229
|
+
const candidateDistance = `CAST(${ref("reached", "distance")} + ${ref("edges", "__weight")} AS ${distanceType})`;
|
|
230
|
+
const order = minimize === "elapsedTime"
|
|
231
|
+
? `${q("__elapsed")}, ${q("distance")}`
|
|
232
|
+
: `${q("distance")}, ${q("__elapsed")}`;
|
|
233
|
+
// A physical event and the first departure (last arrival for incoming
|
|
234
|
+
// traversal) fix elapsed time. Keep the cheapest cost for each such state;
|
|
235
|
+
// merging different anchors would lose later-departing, faster journeys.
|
|
236
|
+
// The state space is finite, and strict improvements terminate zero cycles.
|
|
237
|
+
return `WITH RECURSIVE ${settings} AS MATERIALIZED (
|
|
238
|
+
SELECT CAST(? AS HUGEINT) AS ${q("__gap")}
|
|
239
|
+
), ${events} AS MATERIALIZED (
|
|
240
|
+
${prepared.edges(direction, [
|
|
241
|
+
`${edgeWeight} AS ${q("__weight")}`,
|
|
242
|
+
...temporal.eventSelections("edges"),
|
|
243
|
+
])}
|
|
244
|
+
), ${edges} AS MATERIALIZED (
|
|
245
|
+
SELECT * FROM ${events} AS ${q("events")}
|
|
246
|
+
WHERE ${temporal.eventValidity("events")}
|
|
247
|
+
), ${starts} AS MATERIALIZED (
|
|
248
|
+
SELECT ${q("start")}, ${prepared.key(q("start"))} AS ${q("__key")}
|
|
249
|
+
FROM (VALUES ${prepared.startValues}) AS ${q("start_values")}(${q("start")})
|
|
250
|
+
), ${states}(
|
|
251
|
+
${q("start")}, ${q("node")}, ${q("__start_key")}, ${q("__node_key")},
|
|
252
|
+
${q("__event_id")}, ${q("__event_start")}, ${q("__event_end")},
|
|
253
|
+
${q("__anchor")}, ${q("distance")}
|
|
254
|
+
) USING KEY(${q("__start_key")}, ${q("__event_id")}, ${q("__anchor")}) AS (
|
|
255
|
+
SELECT ${ref("starts", "start")}, ${ref("edges", "__to")},
|
|
256
|
+
${ref("starts", "__key")}, ${ref("edges", "__to_key")},
|
|
257
|
+
${ref("edges", "__event_id")}, ${ref("edges", "__event_start")},
|
|
258
|
+
${ref("edges", "__event_end")}, ${anchor}, ${ref("edges", "__weight")}
|
|
259
|
+
FROM ${starts} AS ${q("starts")}
|
|
260
|
+
INNER JOIN ${edges} AS ${q("edges")}
|
|
261
|
+
ON ${ref("starts", "__key")} = ${ref("edges", "__from_key")}
|
|
262
|
+
UNION
|
|
263
|
+
SELECT ${ref("reached", "start")}, ${ref("edges", "__to")},
|
|
264
|
+
${ref("reached", "__start_key")}, ${ref("edges", "__to_key")},
|
|
265
|
+
${ref("edges", "__event_id")}, ${ref("edges", "__event_start")},
|
|
266
|
+
${ref("edges", "__event_end")}, ${reachedAnchor},
|
|
267
|
+
MIN(${candidateDistance}) AS ${q("distance")}
|
|
268
|
+
FROM ${states} AS ${q("reached")}
|
|
269
|
+
INNER JOIN ${edges} AS ${q("edges")}
|
|
270
|
+
ON ${ref("reached", "__node_key")} = ${ref("edges", "__from_key")}
|
|
271
|
+
CROSS JOIN ${settings} AS ${q("settings")}
|
|
272
|
+
LEFT JOIN recurring.${states} AS ${q("best")}
|
|
273
|
+
ON ${ref("reached", "__start_key")} = ${ref("best", "__start_key")}
|
|
274
|
+
AND ${ref("edges", "__event_id")} = ${ref("best", "__event_id")}
|
|
275
|
+
AND ${reachedAnchor} = ${ref("best", "__anchor")}
|
|
276
|
+
WHERE ${temporal.transition("reached", "edges", direction, ref("settings", "__gap"))}
|
|
277
|
+
GROUP BY ${ref("reached", "start")}, ${ref("edges", "__to")},
|
|
278
|
+
${ref("reached", "__start_key")}, ${ref("edges", "__to_key")},
|
|
279
|
+
${ref("edges", "__event_id")}, ${ref("edges", "__event_start")},
|
|
280
|
+
${ref("edges", "__event_end")}, ${reachedAnchor}, ${ref("best", "distance")}
|
|
281
|
+
HAVING ${ref("best", "distance")} IS NULL OR
|
|
282
|
+
MIN(${candidateDistance}) < ${ref("best", "distance")}
|
|
283
|
+
), ${results} AS (
|
|
284
|
+
SELECT *, ${temporal.journeyElapsed("states", ref("states", "__anchor"), direction)} AS ${q("__elapsed")}
|
|
285
|
+
FROM ${states} AS ${q("states")}
|
|
286
|
+
)
|
|
287
|
+
SELECT ${q("start")}, ${q("node")}, ${q("distance")} AS ${q("total")},
|
|
288
|
+
${temporal.elapsedMilliseconds(q("__elapsed"))} AS ${q("elapsedTimeMs")}
|
|
289
|
+
FROM ${results}
|
|
290
|
+
QUALIFY row_number() OVER (
|
|
291
|
+
PARTITION BY ${q("__start_key")}, ${q("__node_key")}
|
|
292
|
+
ORDER BY ${order}, ${q("__event_id")}, ${q("__anchor")}
|
|
293
|
+
) = 1
|
|
294
|
+
ORDER BY ${q("__start_key")}, ${order}, ${q("__node_key")}`;
|
|
203
295
|
}
|
|
@@ -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"}
|
package/script/methods/paths.js
CHANGED
|
@@ -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 = paths;
|
|
40
|
+
const prepareGraphMetricOptions_js_1 = __importDefault(require("../helpers/prepareGraphMetricOptions.js"));
|
|
40
41
|
const prepareGraphRouteSql_js_1 = require("../helpers/prepareGraphRouteSql.js");
|
|
41
42
|
const graphRouteResultSchema_js_1 = __importDefault(require("../helpers/graphRouteResultSchema.js"));
|
|
42
43
|
const graphRouteResultSelect_js_1 = __importDefault(require("../helpers/graphRouteResultSelect.js"));
|
|
@@ -69,6 +70,7 @@ function paths(simpleTable, sourceColumn, targetColumn, edgeId, start, end, opti
|
|
|
69
70
|
typeof options.outputTable !== "boolean") {
|
|
70
71
|
throw new TypeError("paths() options.outputTable must be a string or boolean.");
|
|
71
72
|
}
|
|
73
|
+
const metric = (0, prepareGraphMetricOptions_js_1.default)(options, "paths()", false);
|
|
72
74
|
const endpoints = (0, prepareGraphRouteSql_js_1.prepareGraphRouteEndpoints)(start, end, "paths()");
|
|
73
75
|
const direction = options.direction ?? "outgoing";
|
|
74
76
|
const temporalOptions = (0, prepareGraphTemporalSql_js_1.prepareGraphTemporalOptions)(options, direction, "paths()");
|
|
@@ -89,7 +91,8 @@ function paths(simpleTable, sourceColumn, targetColumn, edgeId, start, end, opti
|
|
|
89
91
|
? undefined
|
|
90
92
|
: (input) => (0, validateGraphTemporalEvents_js_1.default)(input, temporalOptions, "paths()", parameters),
|
|
91
93
|
values: (schema) => {
|
|
92
|
-
(0, prepareGraphRouteSql_js_1.validateGraphRouteInputs)(schema, sourceColumn, targetColumn, edgeId, endpoints, options.weight, "paths()");
|
|
94
|
+
const validated = (0, prepareGraphRouteSql_js_1.validateGraphRouteInputs)(schema, sourceColumn, targetColumn, edgeId, endpoints, options.weight, "paths()");
|
|
95
|
+
(0, graphRouteResultSchema_js_1.default)(schema, validated.distanceType, "paths()", metric.elapsedTime);
|
|
93
96
|
const temporal = temporalOptions === undefined
|
|
94
97
|
? undefined
|
|
95
98
|
: (0, prepareGraphTemporalSql_js_1.default)(schema, temporalOptions, "paths()");
|
|
@@ -97,22 +100,22 @@ function paths(simpleTable, sourceColumn, targetColumn, edgeId, start, end, opti
|
|
|
97
100
|
? endpoints.values.values
|
|
98
101
|
: [temporal.gapParameter, ...endpoints.values.values];
|
|
99
102
|
},
|
|
100
|
-
buildSelect: (input, schema) => pathsSelect(input, schema, sourceColumn, targetColumn, edgeId, endpoints, direction, options.weight, temporalOptions),
|
|
103
|
+
buildSelect: (input, schema) => pathsSelect(input, schema, sourceColumn, targetColumn, edgeId, endpoints, direction, options.weight, temporalOptions, metric.elapsedTime),
|
|
101
104
|
outputSchema: (schema) => {
|
|
102
105
|
const validated = (0, prepareGraphRouteSql_js_1.validateGraphRouteInputs)(schema, sourceColumn, targetColumn, edgeId, endpoints, options.weight, "paths()");
|
|
103
106
|
if (temporalOptions !== undefined) {
|
|
104
107
|
(0, prepareGraphTemporalSql_js_1.default)(schema, temporalOptions, "paths()");
|
|
105
108
|
}
|
|
106
|
-
return (0, graphRouteResultSchema_js_1.default)(schema, validated.distanceType, "paths()");
|
|
109
|
+
return (0, graphRouteResultSchema_js_1.default)(schema, validated.distanceType, "paths()", metric.elapsedTime);
|
|
107
110
|
},
|
|
108
111
|
});
|
|
109
112
|
}
|
|
110
|
-
function pathsSelect(input, schema, source, target, edgeId, routeEndpoints, direction, weight, temporalOptions) {
|
|
113
|
+
function pathsSelect(input, schema, source, target, edgeId, routeEndpoints, direction, weight, temporalOptions, elapsedTime) {
|
|
111
114
|
const route = (0, prepareGraphRouteSql_js_1.prepareGraphRouteSql)(input, schema, source, target, edgeId, routeEndpoints, weight, "paths()");
|
|
112
115
|
const prepared = route.traversal;
|
|
113
116
|
if (temporalOptions !== undefined) {
|
|
114
117
|
const temporal = (0, prepareGraphTemporalSql_js_1.default)(schema, temporalOptions, "paths()");
|
|
115
|
-
return temporalPathsSelect(route, direction, temporal);
|
|
118
|
+
return temporalPathsSelect(route, direction, temporal, elapsedTime);
|
|
116
119
|
}
|
|
117
120
|
const distanceType = route.distanceType;
|
|
118
121
|
const q = quoteIdentifier_js_1.default;
|
|
@@ -205,7 +208,7 @@ function pathsSelect(input, schema, source, target, edgeId, routeEndpoints, dire
|
|
|
205
208
|
)
|
|
206
209
|
${(0, graphRouteResultSelect_js_1.default)(rankedRelation, route.input, route.edgeIdColumn)}`;
|
|
207
210
|
}
|
|
208
|
-
function temporalPathsSelect(route, direction, temporal) {
|
|
211
|
+
function temporalPathsSelect(route, direction, temporal, elapsedTime) {
|
|
209
212
|
const prepared = route.traversal;
|
|
210
213
|
const distanceType = route.distanceType;
|
|
211
214
|
const q = quoteIdentifier_js_1.default;
|
|
@@ -236,12 +239,16 @@ function temporalPathsSelect(route, direction, temporal) {
|
|
|
236
239
|
const edgeKey = `${q("edges")}.${q("__edge_key")}`;
|
|
237
240
|
const candidateDistance = `CAST(${q("routes")}.${q("distance")} + ${edgeCost} AS ${distanceType})`;
|
|
238
241
|
const gap = `${q("settings")}.${q("__gap")}`;
|
|
239
|
-
const
|
|
242
|
+
const firstAnchor = temporal.journeyAnchor("edges", direction);
|
|
243
|
+
const anchor = `${q("routes")}.${q("__journey_anchor")}`;
|
|
244
|
+
const step = (distance, journeyAnchor) => `struct_pack(
|
|
240
245
|
${q("edgeId")} := ${q("edges")}.${q("__edge_id")},
|
|
241
246
|
${q("source")} := ${q("edges")}.${q("__from")},
|
|
242
247
|
${q("target")} := ${edgeTo},
|
|
243
248
|
${q("weight")} := ${edgeCost},
|
|
244
|
-
${q("distance")} := ${distance}
|
|
249
|
+
${q("distance")} := ${distance}${elapsedTime
|
|
250
|
+
? `, ${q("elapsedTimeMs")} := ${temporal.elapsedMilliseconds(temporal.journeyElapsed("edges", journeyAnchor, direction))}`
|
|
251
|
+
: ""}
|
|
245
252
|
)`;
|
|
246
253
|
return `WITH RECURSIVE ${settingsRelation} AS MATERIALIZED (
|
|
247
254
|
SELECT CAST(? AS HUGEINT) AS ${q("__gap")}
|
|
@@ -280,14 +287,14 @@ function temporalPathsSelect(route, direction, temporal) {
|
|
|
280
287
|
), ${routesRelation}(
|
|
281
288
|
${q("node")}, ${q("__node_key")}, ${q("__visited")},
|
|
282
289
|
${q("__edge_keys")}, ${q("steps")}, ${q("distance")},
|
|
283
|
-
${q("__event_id")}, ${q("__event_start")}, ${q("__event_end")}
|
|
290
|
+
${q("__event_id")}, ${q("__event_start")}, ${q("__event_end")}${elapsedTime ? `, ${q("__journey_anchor")}` : ""}
|
|
284
291
|
) AS (
|
|
285
292
|
SELECT ${edgeTo}, ${edgeToKey},
|
|
286
293
|
[${q("__start_key")}, ${edgeToKey}], [${edgeKey}],
|
|
287
|
-
[${step(edgeCost)}], ${edgeCost},
|
|
294
|
+
[${step(edgeCost, firstAnchor)}], ${edgeCost},
|
|
288
295
|
${q("edges")}.${q("__event_id")},
|
|
289
296
|
${q("edges")}.${q("__event_start")},
|
|
290
|
-
${q("edges")}.${q("__event_end")}
|
|
297
|
+
${q("edges")}.${q("__event_end")}${elapsedTime ? `, ${firstAnchor}` : ""}
|
|
291
298
|
FROM ${endpointRelation}
|
|
292
299
|
INNER JOIN ${edgesRelation} AS ${q("edges")}
|
|
293
300
|
ON ${q("__start_key")} = ${edgeFromKey}
|
|
@@ -298,10 +305,10 @@ function temporalPathsSelect(route, direction, temporal) {
|
|
|
298
305
|
SELECT ${edgeTo}, ${edgeToKey},
|
|
299
306
|
list_append(${q("routes")}.${q("__visited")}, ${edgeToKey}),
|
|
300
307
|
list_append(${q("routes")}.${q("__edge_keys")}, ${edgeKey}),
|
|
301
|
-
list_append(${q("routes")}.${q("steps")}, ${step(candidateDistance)}),
|
|
308
|
+
list_append(${q("routes")}.${q("steps")}, ${step(candidateDistance, anchor)}),
|
|
302
309
|
${candidateDistance}, ${q("edges")}.${q("__event_id")},
|
|
303
310
|
${q("edges")}.${q("__event_start")},
|
|
304
|
-
${q("edges")}.${q("__event_end")}
|
|
311
|
+
${q("edges")}.${q("__event_end")}${elapsedTime ? `, ${anchor}` : ""}
|
|
305
312
|
FROM ${routesRelation} AS ${q("routes")}
|
|
306
313
|
INNER JOIN ${edgesRelation} AS ${q("edges")}
|
|
307
314
|
ON ${q("routes")}.${q("__node_key")} = ${edgeFromKey}
|
|
@@ -322,5 +329,5 @@ function temporalPathsSelect(route, direction, temporal) {
|
|
|
322
329
|
AS ${q("pathId")}, ${q("steps")}
|
|
323
330
|
FROM ${completeRelation}
|
|
324
331
|
)
|
|
325
|
-
${(0, graphRouteResultSelect_js_1.default)(rankedRelation, route.input, route.edgeIdColumn)}`;
|
|
332
|
+
${(0, graphRouteResultSelect_js_1.default)(rankedRelation, route.input, route.edgeIdColumn, false, elapsedTime)}`;
|
|
326
333
|
}
|
|
@@ -6,6 +6,8 @@ type ShortestPathOptions = GraphTemporalOptions & {
|
|
|
6
6
|
direction?: GraphDirection;
|
|
7
7
|
outputTable?: string | boolean;
|
|
8
8
|
weight?: string;
|
|
9
|
+
elapsedTime?: boolean;
|
|
10
|
+
minimize?: "weight" | "elapsedTime";
|
|
9
11
|
};
|
|
10
12
|
export default function shortestPath(simpleTable: SimpleTable, sourceColumn: string, targetColumn: string, edgeId: string, start: GraphId, end: GraphId, options?: ShortestPathOptions): SimpleTable;
|
|
11
13
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shortestPath.d.ts","sourceRoot":"","sources":["../../src/methods/shortestPath.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"shortestPath.d.ts","sourceRoot":"","sources":["../../src/methods/shortestPath.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAMvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAShE,OAAgC,EAC9B,KAAK,oBAAoB,EAG1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAK1E,KAAK,mBAAmB,GAAG,oBAAoB,GAAG;IAChD,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,QAAQ,GAAG,aAAa,CAAC;CACrC,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,YAAY,CAClC,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,mBAAwB,GAChC,WAAW,CAsHb"}
|