@nshiab/simple-data-analysis-core 2.1.7 → 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.
Files changed (57) hide show
  1. package/esm/class/SimpleTable.d.ts +187 -104
  2. package/esm/class/SimpleTable.d.ts.map +1 -1
  3. package/esm/class/SimpleTable.js +185 -102
  4. package/esm/helpers/buildGraphTemporalCostStateSql.d.ts +1 -1
  5. package/esm/helpers/buildGraphTemporalCostStateSql.d.ts.map +1 -1
  6. package/esm/helpers/buildGraphTemporalCostStateSql.js +23 -9
  7. package/esm/helpers/graphRouteResultSchema.d.ts +1 -1
  8. package/esm/helpers/graphRouteResultSchema.d.ts.map +1 -1
  9. package/esm/helpers/graphRouteResultSchema.js +3 -3
  10. package/esm/helpers/graphRouteResultSelect.d.ts +1 -1
  11. package/esm/helpers/graphRouteResultSelect.d.ts.map +1 -1
  12. package/esm/helpers/graphRouteResultSelect.js +2 -2
  13. package/esm/helpers/prepareGraphMetricOptions.d.ts +2 -2
  14. package/esm/helpers/prepareGraphMetricOptions.d.ts.map +1 -1
  15. package/esm/helpers/prepareGraphMetricOptions.js +5 -4
  16. package/esm/helpers/prepareGraphRouteSql.d.ts +2 -2
  17. package/esm/helpers/prepareGraphRouteSql.d.ts.map +1 -1
  18. package/esm/helpers/prepareGraphRouteSql.js +4 -4
  19. package/esm/helpers/validateGraphRouteResultSchema.d.ts +1 -1
  20. package/esm/helpers/validateGraphRouteResultSchema.d.ts.map +1 -1
  21. package/esm/helpers/validateGraphRouteResultSchema.js +3 -1
  22. package/esm/methods/distances.d.ts +1 -1
  23. package/esm/methods/distances.d.ts.map +1 -1
  24. package/esm/methods/distances.js +235 -73
  25. package/esm/methods/shortestPath.d.ts +1 -1
  26. package/esm/methods/shortestPath.d.ts.map +1 -1
  27. package/esm/methods/shortestPath.js +44 -28
  28. package/llm.md +207 -112
  29. package/llms.txt +1 -1
  30. package/package.json +1 -1
  31. package/script/class/SimpleTable.d.ts +187 -104
  32. package/script/class/SimpleTable.d.ts.map +1 -1
  33. package/script/class/SimpleTable.js +185 -102
  34. package/script/helpers/buildGraphTemporalCostStateSql.d.ts +1 -1
  35. package/script/helpers/buildGraphTemporalCostStateSql.d.ts.map +1 -1
  36. package/script/helpers/buildGraphTemporalCostStateSql.js +23 -9
  37. package/script/helpers/graphRouteResultSchema.d.ts +1 -1
  38. package/script/helpers/graphRouteResultSchema.d.ts.map +1 -1
  39. package/script/helpers/graphRouteResultSchema.js +3 -3
  40. package/script/helpers/graphRouteResultSelect.d.ts +1 -1
  41. package/script/helpers/graphRouteResultSelect.d.ts.map +1 -1
  42. package/script/helpers/graphRouteResultSelect.js +2 -2
  43. package/script/helpers/prepareGraphMetricOptions.d.ts +2 -2
  44. package/script/helpers/prepareGraphMetricOptions.d.ts.map +1 -1
  45. package/script/helpers/prepareGraphMetricOptions.js +5 -4
  46. package/script/helpers/prepareGraphRouteSql.d.ts +2 -2
  47. package/script/helpers/prepareGraphRouteSql.d.ts.map +1 -1
  48. package/script/helpers/prepareGraphRouteSql.js +4 -4
  49. package/script/helpers/validateGraphRouteResultSchema.d.ts +1 -1
  50. package/script/helpers/validateGraphRouteResultSchema.d.ts.map +1 -1
  51. package/script/helpers/validateGraphRouteResultSchema.js +3 -1
  52. package/script/methods/distances.d.ts +1 -1
  53. package/script/methods/distances.d.ts.map +1 -1
  54. package/script/methods/distances.js +235 -73
  55. package/script/methods/shortestPath.d.ts +1 -1
  56. package/script/methods/shortestPath.d.ts.map +1 -1
  57. package/script/methods/shortestPath.js +44 -28
package/llm.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # The Simple Data Analysis (Core) Library
2
2
 
3
3
  - Package: `@nshiab/simple-data-analysis-core`
4
- - Version: `2.1.7`
4
+ - Version: `2.1.8`
5
5
 
6
6
  To install the library with Deno, use:
7
7
 
@@ -3796,39 +3796,24 @@ await table
3796
3796
 
3797
3797
  #### `distances`
3798
3798
 
3799
- Finds the shortest routes from each starting node to every reachable node and
3800
- reports their total costs. By default, each connection costs one. Use the
3801
- `weight` option to sum values from a numeric column, such as travel time or
3802
- price.
3799
+ Finds the shortest routes from each starting node to every reachable node.
3800
+ Without options, shortest means the fewest connections. Use `weight` to report
3801
+ total cost and `elapsedTime` to report duration including waiting between
3802
+ connections. Use `minimize` to choose which metric defines shortest.
3803
3803
 
3804
- The `direction` option lets you follow connections from source to target, from
3805
- target to source, or in either direction. The result has `start`, `node`, and
3806
- `total` columns.
3807
-
3808
- Each row gives the selected route's total cost from `start` to `node`.
3809
- Intermediate steps along the route are not returned. To get the steps between
3810
- two different nodes, use `shortestPath()` for the shortest routes or `paths()`
3811
- for all routes without repeated nodes.
3804
+ Each row contains `start`, `node`, and `steps`, plus `total` when `weight` is
3805
+ supplied and `elapsedTimeMs` when enabled. Routes tied on the chosen metric
3806
+ produce separate rows only when their reported summaries differ; identical
3807
+ summaries appear once.
3812
3808
 
3813
- A starting node appears in its own results only when a self-connection or a
3814
- route leads back to it. Its total is the cost of the shortest actual return
3815
- route, using at least one connection. With `direction: "both"`, this can mean
3816
- following the same connection out and back.
3817
-
3818
- Unknown starting IDs and starts with no connections to follow produce no rows.
3819
- Empty start arrays and duplicate starting IDs throw an error. Weights must be
3820
- non-null, finite, and non-negative.
3821
-
3822
- Use the `startTimeColumn` or `endTimeColumn` options to follow connections in
3823
- chronological order. The `minGapMs` option sets the minimum gap between
3824
- consecutive connections, in milliseconds. With both time columns, gaps are
3825
- measured from one connection's end to the next connection's start; with one
3826
- column, between their timestamps. The `strictOrdering` option defaults to
3827
- `true`, rejecting zero-duration gaps. These options only work with
3828
- `direction: "outgoing"` or `direction: "incoming"`.
3809
+ Routes cannot repeat nodes except for a final return to the start. A start
3810
+ appears in its own results only through an actual return or self-connection,
3811
+ never with zero steps. With `direction: "both"`, a return can follow the same
3812
+ connection out and back. Use `shortestPath()` to inspect individual connections
3813
+ between two different nodes.
3829
3814
 
3830
- The minimum gap applies only between consecutive connections, not before the
3831
- first connection.
3815
+ Reporting weight or elapsed time can require substantial time and memory on
3816
+ dense networks because many routes may need to be explored.
3832
3817
 
3833
3818
  The next five examples each start with this data:
3834
3819
 
@@ -3844,7 +3829,7 @@ many connections are needed:
3844
3829
  ##### Signature
3845
3830
 
3846
3831
  ```typescript
3847
- distances(sourceColumn: string, targetColumn: string, startNodes: string | number | bigint | (string | number | bigint)[], options?: { direction?: "outgoing" | "incoming" | "both"; elapsedTime?: boolean; endTimeColumn?: string; minGapMs?: number; minimize?: "weight" | "elapsedTime"; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean; weight?: string }): SimpleTable;
3832
+ distances(sourceColumn: string, targetColumn: string, startNodes: string | number | bigint | (string | number | bigint)[], options?: { direction?: "outgoing" | "incoming" | "both"; elapsedTime?: boolean; endTimeColumn?: string; minGapMs?: number; minimize?: "steps" | "weight" | "elapsedTime"; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean; weight?: string }): SimpleTable;
3848
3833
  ```
3849
3834
 
3850
3835
  ##### Parameters
@@ -3853,12 +3838,14 @@ distances(sourceColumn: string, targetColumn: string, startNodes: string | numbe
3853
3838
  node ID.
3854
3839
  - **`targetColumn`**: The name of the column containing each connection's target
3855
3840
  node ID.
3856
- - **`startNodes`**: One starting node ID or an array of distinct starting node
3857
- IDs.
3841
+ - **`startNodes`**: One starting node ID or a non-empty array of distinct IDs.
3842
+ Unknown IDs and starts with no connections to follow produce no rows. Empty
3843
+ arrays and duplicate IDs throw an error.
3858
3844
  - **`options`**: An optional object with direction, time, and result
3859
3845
  configuration.
3860
3846
  - **`options.direction`**: The direction in which to follow connections.
3861
- Defaults to `"outgoing"`.
3847
+ Defaults to `"outgoing"`. Chronological traversal supports only `"outgoing"`
3848
+ and `"incoming"`.
3862
3849
  - **`options.startTimeColumn`**: The name of the column containing each
3863
3850
  connection's start time. Use this or `endTimeColumn` to follow connections in
3864
3851
  chronological order.
@@ -3866,26 +3853,35 @@ distances(sourceColumn: string, targetColumn: string, startNodes: string | numbe
3866
3853
  connection's end time. Use this or `startTimeColumn` to follow connections in
3867
3854
  chronological order.
3868
3855
  - **`options.minGapMs`**: The minimum gap between consecutive connections, in
3869
- milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time
3870
- column.
3856
+ milliseconds; does not apply before the first connection. With both time
3857
+ columns, measured from one connection's end to the next's start; with one
3858
+ column, between timestamps. Must be a non-negative integer. Defaults to `0`.
3859
+ Requires a time column.
3871
3860
  - **`options.strictOrdering`**: Whether to reject zero-duration gaps between
3872
3861
  consecutive connections (equal timestamps). Defaults to `true`. Requires a
3873
3862
  time column.
3874
3863
  - **`options.weight`**: The name of the numeric column used as the cost of each
3875
- connection. If omitted, each connection costs one.
3864
+ connection. Values must be non-null, finite, and non-negative. Adds `total`,
3865
+ the cumulative sum of those costs. If omitted, no `total` column is generated.
3876
3866
  - **`options.elapsedTime`**: Whether to add cumulative `elapsedTimeMs` in
3877
3867
  milliseconds, including connection gaps. Defaults to `false`. Requires both
3878
- time columns.
3879
- - **`options.minimize`**: The metric used to select optimal routes. Required
3880
- when both `weight` and `elapsedTime` are enabled; otherwise inferred. The
3881
- corresponding metric must be enabled.
3868
+ time columns. Optimization compares native timestamp precision before
3869
+ conversion to milliseconds.
3870
+ - **`options.minimize`**: The metric used to select optimal routes: `"steps"`,
3871
+ `"weight"`, or `"elapsedTime"`. Defaults to `"weight"` when only `weight` is
3872
+ enabled, `"elapsedTime"` when only elapsed-time reporting is enabled, and
3873
+ `"steps"` when neither is enabled. Required when both are enabled. `"steps"`
3874
+ is always available; the other metrics require their corresponding options.
3882
3875
  - **`options.outputTable`**: If `true`, stores the result in a new table with a
3883
3876
  generated name. If a string, uses it as the new table's name. If `false` or
3884
3877
  omitted, overwrites the current table. Defaults to `false`.
3885
3878
 
3886
3879
  ##### Returns
3887
3880
 
3888
- The result table, so methods can be chained.
3881
+ The table of distinct optimal summaries with `start`, `node`, and `steps`, plus
3882
+ `total` when `weight` is supplied and `elapsedTimeMs` when enabled, so methods
3883
+ can be chained. Sorted by start, the chosen metric, node, then remaining metrics
3884
+ in the order steps, total, elapsed time.
3889
3885
 
3890
3886
  ##### Examples
3891
3887
 
@@ -3895,7 +3891,7 @@ await connections
3895
3891
  .log();
3896
3892
  ```
3897
3893
 
3898
- | start | node | total |
3894
+ | start | node | steps |
3899
3895
  | ----- | ---- | ----: |
3900
3896
  | A | B | 1 |
3901
3897
  | A | C | 2 |
@@ -3908,10 +3904,10 @@ await connections
3908
3904
  .log();
3909
3905
  ```
3910
3906
 
3911
- | start | node | total |
3912
- | ----- | ---- | ----: |
3913
- | A | B | 4 |
3914
- | A | C | 5 |
3907
+ | start | node | steps | total |
3908
+ | ----- | ---- | ----: | ----: |
3909
+ | A | B | 1 | 4 |
3910
+ | A | C | 2 | 5 |
3915
3911
 
3916
3912
  With `direction: "incoming"`, connections are followed from target to source.
3917
3913
  Starting at C:
@@ -3922,7 +3918,7 @@ await connections
3922
3918
  .log();
3923
3919
  ```
3924
3920
 
3925
- | start | node | total |
3921
+ | start | node | steps |
3926
3922
  | ----- | ---- | ----: |
3927
3923
  | C | B | 1 |
3928
3924
  | C | A | 2 |
@@ -3936,14 +3932,14 @@ await connections
3936
3932
  .log();
3937
3933
  ```
3938
3934
 
3939
- | start | node | total |
3935
+ | start | node | steps |
3940
3936
  | ----- | ---- | ----: |
3941
3937
  | A | B | 1 |
3942
3938
  | A | A | 2 |
3943
3939
  | A | C | 2 |
3944
3940
  | A | D | 2 |
3945
3941
 
3946
- A appears with a total of 2 because A → B → A follows a connection out and back.
3942
+ A appears with 2 steps because A → B → A follows a connection out and back.
3947
3943
 
3948
3944
  An array of starting nodes gives separate distances for each start:
3949
3945
 
@@ -3955,12 +3951,12 @@ await connections
3955
3951
  .log();
3956
3952
  ```
3957
3953
 
3958
- | start | node | total |
3959
- | ----- | ---- | ----: |
3960
- | A | B | 4 |
3961
- | A | C | 5 |
3962
- | D | B | 2 |
3963
- | D | C | 3 |
3954
+ | start | node | steps | total |
3955
+ | ----- | ---- | ----: | ----: |
3956
+ | A | B | 1 | 4 |
3957
+ | A | C | 2 | 5 |
3958
+ | D | B | 1 | 2 |
3959
+ | D | C | 2 | 3 |
3964
3960
 
3965
3961
  A direct self-connection and a longer return route can both lead back to the
3966
3962
  start. This example uses different data:
@@ -3980,14 +3976,14 @@ await connections
3980
3976
  .log();
3981
3977
  ```
3982
3978
 
3983
- | start | node | total |
3984
- | ----- | ---- | ----: |
3985
- | A | B | 2 |
3986
- | A | A | 5 |
3979
+ | start | node | steps | total |
3980
+ | ----- | ---- | ----: | ----: |
3981
+ | A | B | 1 | 2 |
3982
+ | A | A | 2 | 5 |
3987
3983
 
3988
3984
  Chronological options can rule out a cheaper sequence that departs too early.
3989
- For this example, F2 leaves before F1 arrives, while F3 meets the one-hour
3990
- minimum exactly:
3985
+ Here, B → C leaves before A → B arrives, while B → D meets the one-hour minimum
3986
+ exactly:
3991
3987
 
3992
3988
  | origin | destination | departureTime | arrivalTime | minutes |
3993
3989
  | ------ | ----------- | ---------------- | ---------------- | ------: |
@@ -4006,12 +4002,12 @@ await scheduledFlights
4006
4002
  .log();
4007
4003
  ```
4008
4004
 
4009
- | start | node | total |
4010
- | ----- | ---- | ----: |
4011
- | A | B | 2 |
4012
- | A | D | 5 |
4005
+ | start | node | steps | total |
4006
+ | ----- | ---- | ----: | ----: |
4007
+ | A | B | 1 | 2 |
4008
+ | A | D | 2 | 5 |
4013
4009
 
4014
- For the next two examples, `flights` contains these rows, with departure and
4010
+ For the next four examples, `flights` contains these rows, with departure and
4015
4011
  arrival stored as timestamps on the same day:
4016
4012
 
4017
4013
  | flightId | origin | destination | departure | arrival | price |
@@ -4034,7 +4030,7 @@ await flights
4034
4030
  .log();
4035
4031
  ```
4036
4032
 
4037
- | start | node | total | elapsedTimeMs |
4033
+ | start | node | steps | elapsedTimeMs |
4038
4034
  | ----- | ---- | ----: | ------------: |
4039
4035
  | A | B | 1 | 3600000 |
4040
4036
  | A | C | 1 | 10800000 |
@@ -4057,13 +4053,76 @@ await flights
4057
4053
  .log();
4058
4054
  ```
4059
4055
 
4060
- | start | node | total | elapsedTimeMs |
4061
- | ----- | ---- | ----: | ------------: |
4062
- | A | B | 40 | 3600000 |
4063
- | A | C | 120 | 10800000 |
4056
+ | start | node | steps | total | elapsedTimeMs |
4057
+ | ----- | ---- | ----: | ----: | ------------: |
4058
+ | A | B | 1 | 40 | 3600000 |
4059
+ | A | C | 1 | 120 | 10800000 |
4060
+
4061
+ Use `minimize: "weight"` to find the cheapest journeys instead. The selected
4062
+ route to C now takes two steps through B and costs 80:
4063
+
4064
+ ```ts
4065
+ await flights
4066
+ .distances("origin", "destination", "A", {
4067
+ startTimeColumn: "departure",
4068
+ endTimeColumn: "arrival",
4069
+ minGapMs: 60 * 60 * 1000,
4070
+ elapsedTime: true,
4071
+ weight: "price",
4072
+ minimize: "weight",
4073
+ })
4074
+ .log();
4075
+ ```
4076
+
4077
+ | start | node | steps | total | elapsedTimeMs |
4078
+ | ----- | ---- | ----: | ----: | ------------: |
4079
+ | A | B | 1 | 40 | 3600000 |
4080
+ | A | C | 2 | 80 | 14400000 |
4081
+
4082
+ Choose the fewest connections while still reporting price and elapsed time. The
4083
+ direct flight to C has one step, even though it costs more:
4084
+
4085
+ ```ts
4086
+ await flights
4087
+ .distances("origin", "destination", "A", {
4088
+ startTimeColumn: "departure",
4089
+ endTimeColumn: "arrival",
4090
+ minGapMs: 60 * 60 * 1000,
4091
+ elapsedTime: true,
4092
+ weight: "price",
4093
+ minimize: "steps",
4094
+ })
4095
+ .log();
4096
+ ```
4097
+
4098
+ | start | node | steps | total | elapsedTimeMs |
4099
+ | ----- | ---- | ----: | ----: | ------------: |
4100
+ | A | B | 1 | 40 | 3600000 |
4101
+ | A | C | 1 | 120 | 10800000 |
4064
4102
 
4065
- Use `minimize: "weight"` to find the cheapest journeys instead. Equally fast
4066
- journeys are ranked by price; equally cheap journeys are ranked by elapsed time.
4103
+ When two routes to C both take two steps but have different prices, minimizing
4104
+ steps while reporting price returns both summaries:
4105
+
4106
+ ```ts
4107
+ await connections
4108
+ .loadArray([
4109
+ { origin: "A", destination: "B", price: 20 },
4110
+ { origin: "B", destination: "C", price: 30 },
4111
+ { origin: "A", destination: "D", price: 40 },
4112
+ { origin: "D", destination: "C", price: 40 },
4113
+ ])
4114
+ .distances("origin", "destination", "A", {
4115
+ weight: "price",
4116
+ minimize: "steps",
4117
+ })
4118
+ .filter("node = 'C'")
4119
+ .log();
4120
+ ```
4121
+
4122
+ | start | node | steps | total |
4123
+ | ----- | ---- | ----: | ----: |
4124
+ | A | C | 2 | 50 |
4125
+ | A | C | 2 | 80 |
4067
4126
 
4068
4127
  #### `shortestPath`
4069
4128
 
@@ -4081,15 +4140,17 @@ Each connection needs a unique, non-null ID. Pass the name of the column
4081
4140
  containing these IDs as the `edgeId` argument. If your table is missing an ID
4082
4141
  column, you can easily create one with `addId()`.
4083
4142
 
4084
- The result starts with the `pathId`, `step`, `weight`, and `total` columns,
4085
- followed by all original columns. Steps start at one and follow the search
4086
- direction. The `weight` column is the connection cost, and `total` is the sum of
4087
- those costs up to and including the current step. Without the `weight` option,
4088
- each connection costs one.
4143
+ The result starts with `pathId`, `step`, and `weight`, followed by the optional
4144
+ metric columns and all original columns. Steps start at one and follow the
4145
+ search direction. The `weight` column is the connection cost, or one when no
4146
+ `weight` option is supplied. Supplying `weight` also adds `total`, the sum of
4147
+ those costs up to and including the current step. Enabling `elapsedTime` adds
4148
+ cumulative `elapsedTimeMs`, including gaps.
4089
4149
 
4090
- If an input column is already named `pathId`, `step`, `weight`, or `total`
4091
- (regardless of capitalization), the method throws an error. Rename it with
4092
- `renameColumns()` first.
4150
+ If an input column conflicts with a generated result column (regardless of
4151
+ capitalization), the method throws an error. Rename it with `renameColumns()`
4152
+ first. `total` is reserved only when `weight` is supplied, and `elapsedTimeMs`
4153
+ only when elapsed-time reporting is enabled.
4093
4154
 
4094
4155
  Each row is one connection along a route.
4095
4156
 
@@ -4104,6 +4165,16 @@ column, between their timestamps. The `strictOrdering` option defaults to
4104
4165
  The minimum gap applies only between consecutive connections, not before the
4105
4166
  first connection.
4106
4167
 
4168
+ Use `minimize: "steps"` to choose the fewest connections even when weight or
4169
+ elapsed-time reporting is enabled. Without an explicit `minimize`, the method
4170
+ minimizes weight when only `weight` is enabled, elapsed time when only
4171
+ `elapsedTime` is enabled, and steps when neither is enabled. With both enabled,
4172
+ specify `"steps"`, `"weight"`, or `"elapsedTime"` explicitly. Elapsed-time
4173
+ reporting requires both time columns.
4174
+
4175
+ All routes tied on the selected metric are returned, even if their other metrics
4176
+ differ. Each route reports its own weights and elapsed times.
4177
+
4107
4178
  Routes are numbered from zero by comparing their sequences of connection IDs,
4108
4179
  element by element. Rows are sorted by `pathId`, then `step`.
4109
4180
 
@@ -4130,7 +4201,7 @@ connections. Two routes from A to E tie at three connections each:
4130
4201
  ##### Signature
4131
4202
 
4132
4203
  ```typescript
4133
- shortestPath(sourceColumn: string, targetColumn: string, edgeId: string, start: string | number | bigint, end: string | number | bigint, options?: { direction?: "outgoing" | "incoming" | "both"; elapsedTime?: boolean; endTimeColumn?: string; minGapMs?: number; minimize?: "weight" | "elapsedTime"; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean; weight?: string }): SimpleTable;
4204
+ shortestPath(sourceColumn: string, targetColumn: string, edgeId: string, start: string | number | bigint, end: string | number | bigint, options?: { direction?: "outgoing" | "incoming" | "both"; elapsedTime?: boolean; endTimeColumn?: string; minGapMs?: number; minimize?: "steps" | "weight" | "elapsedTime"; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean; weight?: string }): SimpleTable;
4134
4205
  ```
4135
4206
 
4136
4207
  ##### Parameters
@@ -4160,20 +4231,24 @@ shortestPath(sourceColumn: string, targetColumn: string, edgeId: string, start:
4160
4231
  consecutive connections (equal timestamps). Defaults to `true`. Requires a
4161
4232
  time column.
4162
4233
  - **`options.weight`**: The name of the numeric column used as the cost of each
4163
- connection. If omitted, each connection costs one.
4234
+ connection. Adds `total`, the cumulative sum of those costs. If omitted, no
4235
+ `total` column is generated.
4164
4236
  - **`options.elapsedTime`**: Whether to add cumulative `elapsedTimeMs` in
4165
4237
  milliseconds, including connection gaps. Defaults to `false`. Requires both
4166
4238
  time columns.
4167
- - **`options.minimize`**: The metric used to select optimal routes. Required
4168
- when both `weight` and `elapsedTime` are enabled; otherwise inferred. The
4169
- corresponding metric must be enabled.
4239
+ - **`options.minimize`**: The metric used to select optimal routes: `"steps"`,
4240
+ `"weight"`, or `"elapsedTime"`. Defaults to `"weight"` when only `weight` is
4241
+ enabled, `"elapsedTime"` when only elapsed-time reporting is enabled, and
4242
+ `"steps"` when neither is enabled. Required when both are enabled. `"steps"`
4243
+ is always available; the other metrics require their corresponding options.
4170
4244
  - **`options.outputTable`**: If `true`, stores the result in a new table with a
4171
4245
  generated name. If a string, uses it as the new table's name. If `false` or
4172
4246
  omitted, overwrites the current table. Defaults to `false`.
4173
4247
 
4174
4248
  ##### Returns
4175
4249
 
4176
- The result table, so methods can be chained.
4250
+ The table of route connections with optional cumulative `total` and
4251
+ `elapsedTimeMs` metrics, so methods can be chained.
4177
4252
 
4178
4253
  ##### Examples
4179
4254
 
@@ -4183,14 +4258,14 @@ await connections
4183
4258
  .log();
4184
4259
  ```
4185
4260
 
4186
- | pathId | step | weight | total | edgeId | source | target |
4187
- | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4188
- | 0 | 1 | 1 | 1 | E1 | A | B |
4189
- | 0 | 2 | 1 | 2 | E3 | B | D |
4190
- | 0 | 3 | 1 | 3 | E5 | D | E |
4191
- | 1 | 1 | 1 | 1 | E2 | A | C |
4192
- | 1 | 2 | 1 | 2 | E4 | C | D |
4193
- | 1 | 3 | 1 | 3 | E5 | D | E |
4261
+ | pathId | step | weight | edgeId | source | target |
4262
+ | -----: | ---: | -----: | ------ | ------ | ------ |
4263
+ | 0 | 1 | 1 | E1 | A | B |
4264
+ | 0 | 2 | 1 | E3 | B | D |
4265
+ | 0 | 3 | 1 | E5 | D | E |
4266
+ | 1 | 1 | 1 | E2 | A | C |
4267
+ | 1 | 2 | 1 | E4 | C | D |
4268
+ | 1 | 3 | 1 | E5 | D | E |
4194
4269
 
4195
4270
  For an input without connection IDs, use `addId()` first:
4196
4271
 
@@ -4208,10 +4283,10 @@ await unnumberedConnections
4208
4283
  .log();
4209
4284
  ```
4210
4285
 
4211
- | pathId | step | weight | total | source | target | edgeId |
4212
- | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4213
- | 0 | 1 | 1 | 1 | A | B | edge-0 |
4214
- | 0 | 2 | 1 | 2 | B | E | edge-1 |
4286
+ | pathId | step | weight | source | target | edgeId |
4287
+ | -----: | ---: | -----: | ------ | ------ | ------ |
4288
+ | 0 | 1 | 1 | A | B | edge-0 |
4289
+ | 0 | 2 | 1 | B | E | edge-1 |
4215
4290
 
4216
4291
  The next two examples each start with these flights. The direct flight takes ten
4217
4292
  minutes; the route through B and D takes three:
@@ -4248,9 +4323,9 @@ await flights
4248
4323
  .log();
4249
4324
  ```
4250
4325
 
4251
- | pathId | step | weight | total | flightId | origin | destination | minutes |
4252
- | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------: |
4253
- | 0 | 1 | 1 | 1 | F1 | A | E | 10 |
4326
+ | pathId | step | weight | flightId | origin | destination | minutes |
4327
+ | -----: | ---: | -----: | -------- | ------ | ----------- | ------: |
4328
+ | 0 | 1 | 1 | F1 | A | E | 10 |
4254
4329
 
4255
4330
  With time options, the cheaper route through B is ruled out because F2 leaves
4256
4331
  before F1 arrives. The route through C meets the one-hour minimum gap:
@@ -4293,11 +4368,11 @@ await reverseExample
4293
4368
  .log();
4294
4369
  ```
4295
4370
 
4296
- | pathId | step | weight | total | edgeId | source | target |
4297
- | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4298
- | 0 | 1 | 1 | 1 | F1 | A | B |
4371
+ | pathId | step | weight | edgeId | source | target |
4372
+ | -----: | ---: | -----: | ------ | ------ | ------ |
4373
+ | 0 | 1 | 1 | F1 | A | B |
4299
4374
 
4300
- For the next two examples, `flights` contains these rows, with departure and
4375
+ For the next three examples, `flights` contains these rows, with departure and
4301
4376
  arrival stored as timestamps on the same day:
4302
4377
 
4303
4378
  | flightId | origin | destination | departure | arrival | price |
@@ -4321,10 +4396,10 @@ await flights
4321
4396
  .log();
4322
4397
  ```
4323
4398
 
4324
- | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
4325
- | -----: | ---: | -----: | ----: | ------------: | -------- | ------ | ----------- | ------------------- | ------------------- | ----: |
4326
- | 0 | 1 | 1 | 1 | 1800000 | F4 | A | D | 2025-01-01 09:00:00 | 2025-01-01 09:30:00 | 60 |
4327
- | 0 | 2 | 1 | 2 | 7200000 | F5 | D | C | 2025-01-01 10:30:00 | 2025-01-01 11:00:00 | 80 |
4399
+ | pathId | step | weight | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
4400
+ | -----: | ---: | -----: | ------------: | -------- | ------ | ----------- | ------------------- | ------------------- | ----: |
4401
+ | 0 | 1 | 1 | 1800000 | F4 | A | D | 2025-01-01 09:00:00 | 2025-01-01 09:30:00 | 60 |
4402
+ | 0 | 2 | 1 | 7200000 | F5 | D | C | 2025-01-01 10:30:00 | 2025-01-01 11:00:00 | 80 |
4328
4403
 
4329
4404
  The route through D takes two hours (7,200,000 milliseconds), including a
4330
4405
  one-hour layover. The direct flight takes three hours.
@@ -4352,6 +4427,26 @@ await flights
4352
4427
  Use `minimize: "weight"` to find the cheapest journey instead. All ties on the
4353
4428
  chosen metric are returned.
4354
4429
 
4430
+ Choose the fewest flights while still reporting price and elapsed time. The
4431
+ direct flight takes one step, although the route through D is faster:
4432
+
4433
+ ```ts
4434
+ await flights
4435
+ .shortestPath("origin", "destination", "flightId", "A", "C", {
4436
+ startTimeColumn: "departure",
4437
+ endTimeColumn: "arrival",
4438
+ minGapMs: 60 * 60 * 1000,
4439
+ elapsedTime: true,
4440
+ weight: "price",
4441
+ minimize: "steps",
4442
+ })
4443
+ .log();
4444
+ ```
4445
+
4446
+ | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
4447
+ | -----: | ---: | -----: | ----: | ------------: | -------- | ------ | ----------- | ------------------- | ------------------- | ----: |
4448
+ | 0 | 1 | 120 | 120 | 10800000 | F3 | A | C | 2025-01-01 09:00:00 | 2025-01-01 12:00:00 | 120 |
4449
+
4355
4450
  #### `paths`
4356
4451
 
4357
4452
  Finds all routes between two different nodes. A route cannot visit the same node
package/llms.txt CHANGED
@@ -3,7 +3,7 @@
3
3
  > Lightweight DuckDB-powered TypeScript library for tabular, SQL, CSV, Parquet, and geospatial data analysis on Deno, Node.js, and Bun.
4
4
 
5
5
  - Package: `@nshiab/simple-data-analysis-core`
6
- - Version: `2.1.7`
6
+ - Version: `2.1.8`
7
7
 
8
8
  Install with Deno: `deno add jsr:@nshiab/simple-data-analysis-core`
9
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nshiab/simple-data-analysis-core",
3
- "version": "2.1.7",
3
+ "version": "2.1.8",
4
4
  "description": "Lightweight DuckDB-powered TypeScript library for tabular, SQL, CSV, Parquet, and geospatial data analysis on Deno, Node.js, and Bun.",
5
5
  "keywords": [
6
6
  "data-analysis",