@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.
Files changed (57) hide show
  1. package/esm/class/SimpleTable.d.ts +249 -23
  2. package/esm/class/SimpleTable.d.ts.map +1 -1
  3. package/esm/class/SimpleTable.js +243 -23
  4. package/esm/helpers/graphRouteResultSchema.d.ts +1 -1
  5. package/esm/helpers/graphRouteResultSchema.d.ts.map +1 -1
  6. package/esm/helpers/graphRouteResultSchema.js +3 -2
  7. package/esm/helpers/graphRouteResultSelect.d.ts +1 -1
  8. package/esm/helpers/graphRouteResultSelect.d.ts.map +1 -1
  9. package/esm/helpers/graphRouteResultSelect.js +4 -1
  10. package/esm/helpers/prepareGraphMetricOptions.d.ts +14 -0
  11. package/esm/helpers/prepareGraphMetricOptions.d.ts.map +1 -0
  12. package/esm/helpers/prepareGraphMetricOptions.js +40 -0
  13. package/esm/helpers/prepareGraphTemporalSql.d.ts +3 -0
  14. package/esm/helpers/prepareGraphTemporalSql.d.ts.map +1 -1
  15. package/esm/helpers/prepareGraphTemporalSql.js +7 -0
  16. package/esm/methods/distances.d.ts +2 -0
  17. package/esm/methods/distances.d.ts.map +1 -1
  18. package/esm/methods/distances.js +98 -6
  19. package/esm/methods/findCycles.d.ts +1 -0
  20. package/esm/methods/findCycles.d.ts.map +1 -1
  21. package/esm/methods/findCycles.js +22 -15
  22. package/esm/methods/paths.d.ts +1 -0
  23. package/esm/methods/paths.d.ts.map +1 -1
  24. package/esm/methods/paths.js +21 -14
  25. package/esm/methods/shortestPath.d.ts +2 -0
  26. package/esm/methods/shortestPath.d.ts.map +1 -1
  27. package/esm/methods/shortestPath.js +125 -20
  28. package/llm.md +278 -53
  29. package/llms.txt +1 -1
  30. package/package.json +1 -1
  31. package/script/class/SimpleTable.d.ts +249 -23
  32. package/script/class/SimpleTable.d.ts.map +1 -1
  33. package/script/class/SimpleTable.js +243 -23
  34. package/script/helpers/graphRouteResultSchema.d.ts +1 -1
  35. package/script/helpers/graphRouteResultSchema.d.ts.map +1 -1
  36. package/script/helpers/graphRouteResultSchema.js +3 -2
  37. package/script/helpers/graphRouteResultSelect.d.ts +1 -1
  38. package/script/helpers/graphRouteResultSelect.d.ts.map +1 -1
  39. package/script/helpers/graphRouteResultSelect.js +4 -1
  40. package/script/helpers/prepareGraphMetricOptions.d.ts +14 -0
  41. package/script/helpers/prepareGraphMetricOptions.d.ts.map +1 -0
  42. package/script/helpers/prepareGraphMetricOptions.js +43 -0
  43. package/script/helpers/prepareGraphTemporalSql.d.ts +3 -0
  44. package/script/helpers/prepareGraphTemporalSql.d.ts.map +1 -1
  45. package/script/helpers/prepareGraphTemporalSql.js +7 -0
  46. package/script/methods/distances.d.ts +2 -0
  47. package/script/methods/distances.d.ts.map +1 -1
  48. package/script/methods/distances.js +98 -6
  49. package/script/methods/findCycles.d.ts +1 -0
  50. package/script/methods/findCycles.d.ts.map +1 -1
  51. package/script/methods/findCycles.js +22 -15
  52. package/script/methods/paths.d.ts +1 -0
  53. package/script/methods/paths.d.ts.map +1 -1
  54. package/script/methods/paths.js +21 -14
  55. package/script/methods/shortestPath.d.ts +2 -0
  56. package/script/methods/shortestPath.d.ts.map +1 -1
  57. package/script/methods/shortestPath.js +125 -20
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.6`
4
+ - Version: `2.1.7`
5
5
 
6
6
  To install the library with Deno, use:
7
7
 
@@ -3796,25 +3796,24 @@ await table
3796
3796
 
3797
3797
  #### `distances`
3798
3798
 
3799
- Finds the shortest distance from each starting node to every node it can reach
3800
- by following one or more connections. By default, distance is the number of
3801
- connections along the shortest route. Use the `weight` option to find the
3802
- smallest sum of values from a numeric column, such as travel time.
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.
3803
3803
 
3804
3804
  The `direction` option lets you follow connections from source to target, from
3805
3805
  target to source, or in either direction. The result has `start`, `node`, and
3806
- `distance` columns, sorted by `start`, then by increasing `distance`, then by
3807
- `node` to break ties. The closest nodes appear first for each start.
3806
+ `total` columns.
3808
3807
 
3809
- Each row gives the shortest distance from `start` to `node`. Intermediate steps
3810
- along the route are not returned. To get the steps between two different nodes,
3811
- use `shortestPath()` for the shortest routes or `paths()` for all routes without
3812
- repeated nodes.
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.
3813
3812
 
3814
3813
  A starting node appears in its own results only when a self-connection or a
3815
- route leads back to it. Its distance is the shortest actual return route, using
3816
- at least one connection. With `direction: "both"`, this can mean following the
3817
- same connection out and back.
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.
3818
3817
 
3819
3818
  Unknown starting IDs and starts with no connections to follow produce no rows.
3820
3819
  Empty start arrays and duplicate starting IDs throw an error. Weights must be
@@ -3845,7 +3844,7 @@ many connections are needed:
3845
3844
  ##### Signature
3846
3845
 
3847
3846
  ```typescript
3848
- distances(sourceColumn: string, targetColumn: string, startNodes: string | number | bigint | (string | number | bigint)[], options?: { direction?: "outgoing" | "incoming" | "both"; endTimeColumn?: string; minGapMs?: number; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean; weight?: string }): SimpleTable;
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;
3849
3848
  ```
3850
3849
 
3851
3850
  ##### Parameters
@@ -3874,6 +3873,12 @@ distances(sourceColumn: string, targetColumn: string, startNodes: string | numbe
3874
3873
  time column.
3875
3874
  - **`options.weight`**: The name of the numeric column used as the cost of each
3876
3875
  connection. If omitted, each connection costs one.
3876
+ - **`options.elapsedTime`**: Whether to add cumulative `elapsedTimeMs` in
3877
+ 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.
3877
3882
  - **`options.outputTable`**: If `true`, stores the result in a new table with a
3878
3883
  generated name. If a string, uses it as the new table's name. If `false` or
3879
3884
  omitted, overwrites the current table. Defaults to `false`.
@@ -3890,12 +3895,12 @@ await connections
3890
3895
  .log();
3891
3896
  ```
3892
3897
 
3893
- | start | node | distance |
3894
- | ----- | ---- | -------: |
3895
- | A | B | 1 |
3896
- | A | C | 2 |
3898
+ | start | node | total |
3899
+ | ----- | ---- | ----: |
3900
+ | A | B | 1 |
3901
+ | A | C | 2 |
3897
3902
 
3898
- With `weight: "minutes"`, distance is the shortest total travel time:
3903
+ With `weight: "minutes"`, `total` is the sum of travel times:
3899
3904
 
3900
3905
  ```ts
3901
3906
  await connections
@@ -3903,10 +3908,10 @@ await connections
3903
3908
  .log();
3904
3909
  ```
3905
3910
 
3906
- | start | node | distance |
3907
- | ----- | ---- | -------: |
3908
- | A | B | 4 |
3909
- | A | C | 5 |
3911
+ | start | node | total |
3912
+ | ----- | ---- | ----: |
3913
+ | A | B | 4 |
3914
+ | A | C | 5 |
3910
3915
 
3911
3916
  With `direction: "incoming"`, connections are followed from target to source.
3912
3917
  Starting at C:
@@ -3917,11 +3922,11 @@ await connections
3917
3922
  .log();
3918
3923
  ```
3919
3924
 
3920
- | start | node | distance |
3921
- | ----- | ---- | -------: |
3922
- | C | B | 1 |
3923
- | C | A | 2 |
3924
- | C | D | 2 |
3925
+ | start | node | total |
3926
+ | ----- | ---- | ----: |
3927
+ | C | B | 1 |
3928
+ | C | A | 2 |
3929
+ | C | D | 2 |
3925
3930
 
3926
3931
  With `direction: "both"`, connections can be followed in either direction:
3927
3932
 
@@ -3931,14 +3936,14 @@ await connections
3931
3936
  .log();
3932
3937
  ```
3933
3938
 
3934
- | start | node | distance |
3935
- | ----- | ---- | -------: |
3936
- | A | B | 1 |
3937
- | A | A | 2 |
3938
- | A | C | 2 |
3939
- | A | D | 2 |
3939
+ | start | node | total |
3940
+ | ----- | ---- | ----: |
3941
+ | A | B | 1 |
3942
+ | A | A | 2 |
3943
+ | A | C | 2 |
3944
+ | A | D | 2 |
3940
3945
 
3941
- A appears at distance 2 because A → B → A follows a connection out and back.
3946
+ A appears with a total of 2 because A → B → A follows a connection out and back.
3942
3947
 
3943
3948
  An array of starting nodes gives separate distances for each start:
3944
3949
 
@@ -3950,12 +3955,12 @@ await connections
3950
3955
  .log();
3951
3956
  ```
3952
3957
 
3953
- | start | node | distance |
3954
- | ----- | ---- | -------: |
3955
- | A | B | 4 |
3956
- | A | C | 5 |
3957
- | D | B | 2 |
3958
- | D | C | 3 |
3958
+ | start | node | total |
3959
+ | ----- | ---- | ----: |
3960
+ | A | B | 4 |
3961
+ | A | C | 5 |
3962
+ | D | B | 2 |
3963
+ | D | C | 3 |
3959
3964
 
3960
3965
  A direct self-connection and a longer return route can both lead back to the
3961
3966
  start. This example uses different data:
@@ -3975,10 +3980,10 @@ await connections
3975
3980
  .log();
3976
3981
  ```
3977
3982
 
3978
- | start | node | distance |
3979
- | ----- | ---- | -------: |
3980
- | A | B | 2 |
3981
- | A | A | 5 |
3983
+ | start | node | total |
3984
+ | ----- | ---- | ----: |
3985
+ | A | B | 2 |
3986
+ | A | A | 5 |
3982
3987
 
3983
3988
  Chronological options can rule out a cheaper sequence that departs too early.
3984
3989
  For this example, F2 leaves before F1 arrives, while F3 meets the one-hour
@@ -4001,10 +4006,64 @@ await scheduledFlights
4001
4006
  .log();
4002
4007
  ```
4003
4008
 
4004
- | start | node | distance |
4005
- | ----- | ---- | -------: |
4006
- | A | B | 2 |
4007
- | A | D | 5 |
4009
+ | start | node | total |
4010
+ | ----- | ---- | ----: |
4011
+ | A | B | 2 |
4012
+ | A | D | 5 |
4013
+
4014
+ For the next two examples, `flights` contains these rows, with departure and
4015
+ arrival stored as timestamps on the same day:
4016
+
4017
+ | flightId | origin | destination | departure | arrival | price |
4018
+ | -------- | ------ | ----------- | ---------------- | ---------------- | ----: |
4019
+ | F1 | A | B | 2025-01-01 09:00 | 2025-01-01 10:00 | 40 |
4020
+ | F2 | B | C | 2025-01-01 12:00 | 2025-01-01 13:00 | 40 |
4021
+ | F3 | A | C | 2025-01-01 09:00 | 2025-01-01 12:00 | 120 |
4022
+
4023
+ Find the fastest journey from A to each reachable destination, including
4024
+ layovers:
4025
+
4026
+ ```ts
4027
+ await flights
4028
+ .distances("origin", "destination", "A", {
4029
+ startTimeColumn: "departure",
4030
+ endTimeColumn: "arrival",
4031
+ minGapMs: 60 * 60 * 1000,
4032
+ elapsedTime: true,
4033
+ })
4034
+ .log();
4035
+ ```
4036
+
4037
+ | start | node | total | elapsedTimeMs |
4038
+ | ----- | ---- | ----: | ------------: |
4039
+ | A | B | 1 | 3600000 |
4040
+ | A | C | 1 | 10800000 |
4041
+
4042
+ The direct flight to C takes three hours (10,800,000 milliseconds). The route
4043
+ through B takes four hours including its layover.
4044
+
4045
+ Find the fastest journeys from A while also adding up their prices:
4046
+
4047
+ ```ts
4048
+ await flights
4049
+ .distances("origin", "destination", "A", {
4050
+ startTimeColumn: "departure",
4051
+ endTimeColumn: "arrival",
4052
+ minGapMs: 60 * 60 * 1000,
4053
+ elapsedTime: true,
4054
+ weight: "price",
4055
+ minimize: "elapsedTime",
4056
+ })
4057
+ .log();
4058
+ ```
4059
+
4060
+ | start | node | total | elapsedTimeMs |
4061
+ | ----- | ---- | ----: | ------------: |
4062
+ | A | B | 40 | 3600000 |
4063
+ | A | C | 120 | 10800000 |
4064
+
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.
4008
4067
 
4009
4068
  #### `shortestPath`
4010
4069
 
@@ -4071,7 +4130,7 @@ connections. Two routes from A to E tie at three connections each:
4071
4130
  ##### Signature
4072
4131
 
4073
4132
  ```typescript
4074
- shortestPath(sourceColumn: string, targetColumn: string, edgeId: string, start: string | number | bigint, end: string | number | bigint, options?: { direction?: "outgoing" | "incoming" | "both"; endTimeColumn?: string; minGapMs?: number; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean; weight?: string }): SimpleTable;
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;
4075
4134
  ```
4076
4135
 
4077
4136
  ##### Parameters
@@ -4102,6 +4161,12 @@ shortestPath(sourceColumn: string, targetColumn: string, edgeId: string, start:
4102
4161
  time column.
4103
4162
  - **`options.weight`**: The name of the numeric column used as the cost of each
4104
4163
  connection. If omitted, each connection costs one.
4164
+ - **`options.elapsedTime`**: Whether to add cumulative `elapsedTimeMs` in
4165
+ milliseconds, including connection gaps. Defaults to `false`. Requires both
4166
+ 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.
4105
4170
  - **`options.outputTable`**: If `true`, stores the result in a new table with a
4106
4171
  generated name. If a string, uses it as the new table's name. If `false` or
4107
4172
  omitted, overwrites the current table. Defaults to `false`.
@@ -4232,6 +4297,61 @@ await reverseExample
4232
4297
  | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4233
4298
  | 0 | 1 | 1 | 1 | F1 | A | B |
4234
4299
 
4300
+ For the next two examples, `flights` contains these rows, with departure and
4301
+ arrival stored as timestamps on the same day:
4302
+
4303
+ | flightId | origin | destination | departure | arrival | price |
4304
+ | -------- | ------ | ----------- | ---------------- | ---------------- | ----: |
4305
+ | F1 | A | B | 2025-01-01 09:00 | 2025-01-01 10:00 | 40 |
4306
+ | F2 | B | C | 2025-01-01 12:00 | 2025-01-01 13:00 | 40 |
4307
+ | F3 | A | C | 2025-01-01 09:00 | 2025-01-01 12:00 | 120 |
4308
+ | F4 | A | D | 2025-01-01 09:00 | 2025-01-01 09:30 | 60 |
4309
+ | F5 | D | C | 2025-01-01 10:30 | 2025-01-01 11:00 | 80 |
4310
+
4311
+ Find the fastest journey from A to C, including layovers:
4312
+
4313
+ ```ts
4314
+ await flights
4315
+ .shortestPath("origin", "destination", "flightId", "A", "C", {
4316
+ startTimeColumn: "departure",
4317
+ endTimeColumn: "arrival",
4318
+ minGapMs: 60 * 60 * 1000,
4319
+ elapsedTime: true,
4320
+ })
4321
+ .log();
4322
+ ```
4323
+
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 |
4328
+
4329
+ The route through D takes two hours (7,200,000 milliseconds), including a
4330
+ one-hour layover. The direct flight takes three hours.
4331
+
4332
+ Find the fastest journey while also adding up its price:
4333
+
4334
+ ```ts
4335
+ await flights
4336
+ .shortestPath("origin", "destination", "flightId", "A", "C", {
4337
+ startTimeColumn: "departure",
4338
+ endTimeColumn: "arrival",
4339
+ minGapMs: 60 * 60 * 1000,
4340
+ elapsedTime: true,
4341
+ weight: "price",
4342
+ minimize: "elapsedTime",
4343
+ })
4344
+ .log();
4345
+ ```
4346
+
4347
+ | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
4348
+ | -----: | ---: | -----: | ----: | ------------: | -------- | ------ | ----------- | ------------------- | ------------------- | ----: |
4349
+ | 0 | 1 | 60 | 60 | 1800000 | F4 | A | D | 2025-01-01 09:00:00 | 2025-01-01 09:30:00 | 60 |
4350
+ | 0 | 2 | 80 | 140 | 7200000 | F5 | D | C | 2025-01-01 10:30:00 | 2025-01-01 11:00:00 | 80 |
4351
+
4352
+ Use `minimize: "weight"` to find the cheapest journey instead. All ties on the
4353
+ chosen metric are returned.
4354
+
4235
4355
  #### `paths`
4236
4356
 
4237
4357
  Finds all routes between two different nodes. A route cannot visit the same node
@@ -4292,7 +4412,7 @@ to D are returned:
4292
4412
  ##### Signature
4293
4413
 
4294
4414
  ```typescript
4295
- paths(sourceColumn: string, targetColumn: string, edgeId: string, start: string | number | bigint, end: string | number | bigint, options?: { direction?: "outgoing" | "incoming" | "both"; endTimeColumn?: string; minGapMs?: number; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean; weight?: string }): SimpleTable;
4415
+ paths(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; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean; weight?: string }): SimpleTable;
4296
4416
  ```
4297
4417
 
4298
4418
  ##### Parameters
@@ -4323,6 +4443,9 @@ paths(sourceColumn: string, targetColumn: string, edgeId: string, start: string
4323
4443
  time column.
4324
4444
  - **`options.weight`**: The name of the numeric column used as the cost of each
4325
4445
  connection. If omitted, each connection costs one.
4446
+ - **`options.elapsedTime`**: Whether to add cumulative `elapsedTimeMs` in
4447
+ milliseconds, including connection gaps. Defaults to `false`. Requires both
4448
+ time columns.
4326
4449
  - **`options.outputTable`**: If `true`, stores the result in a new table with a
4327
4450
  generated name. If a string, uses it as the new table's name. If `false` or
4328
4451
  omitted, overwrites the current table. Defaults to `false`.
@@ -4473,6 +4596,57 @@ await scheduledFlights
4473
4596
  | 0 | 1 | 3 | 3 | F3 | B | D | 2025-01-01 11:00:00 | 2025-01-01 12:00:00 | 3 |
4474
4597
  | 0 | 2 | 2 | 5 | F1 | A | B | 2025-01-01 08:00:00 | 2025-01-01 10:00:00 | 2 |
4475
4598
 
4599
+ For the next two examples, `flights` contains these rows, with departure and
4600
+ arrival stored as timestamps on the same day:
4601
+
4602
+ | flightId | origin | destination | departure | arrival | price |
4603
+ | -------- | ------ | ----------- | ---------------- | ---------------- | ----: |
4604
+ | F1 | A | B | 2025-01-01 09:00 | 2025-01-01 10:00 | 40 |
4605
+ | F2 | B | C | 2025-01-01 12:00 | 2025-01-01 13:00 | 40 |
4606
+ | F3 | A | C | 2025-01-01 09:00 | 2025-01-01 12:00 | 120 |
4607
+
4608
+ Report elapsed time for every path, including layovers:
4609
+
4610
+ ```ts
4611
+ await flights
4612
+ .paths("origin", "destination", "flightId", "A", "C", {
4613
+ startTimeColumn: "departure",
4614
+ endTimeColumn: "arrival",
4615
+ minGapMs: 60 * 60 * 1000,
4616
+ elapsedTime: true,
4617
+ })
4618
+ .log();
4619
+ ```
4620
+
4621
+ | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
4622
+ | -----: | ---: | -----: | ----: | ------------: | -------- | ------ | ----------- | ------------------- | ------------------- | ----: |
4623
+ | 0 | 1 | 1 | 1 | 3600000 | F1 | A | B | 2025-01-01 09:00:00 | 2025-01-01 10:00:00 | 40 |
4624
+ | 0 | 2 | 1 | 2 | 14400000 | F2 | B | C | 2025-01-01 12:00:00 | 2025-01-01 13:00:00 | 40 |
4625
+ | 1 | 1 | 1 | 1 | 10800000 | F3 | A | C | 2025-01-01 09:00:00 | 2025-01-01 12:00:00 | 120 |
4626
+
4627
+ The route through B takes four hours (14,400,000 milliseconds), including its
4628
+ two-hour layover. The direct flight takes three hours.
4629
+
4630
+ Add up prices while continuing to report elapsed time for every path:
4631
+
4632
+ ```ts
4633
+ await flights
4634
+ .paths("origin", "destination", "flightId", "A", "C", {
4635
+ startTimeColumn: "departure",
4636
+ endTimeColumn: "arrival",
4637
+ minGapMs: 60 * 60 * 1000,
4638
+ elapsedTime: true,
4639
+ weight: "price",
4640
+ })
4641
+ .log();
4642
+ ```
4643
+
4644
+ | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
4645
+ | -----: | ---: | -----: | ----: | ------------: | -------- | ------ | ----------- | ------------------- | ------------------- | ----: |
4646
+ | 0 | 1 | 40 | 40 | 3600000 | F1 | A | B | 2025-01-01 09:00:00 | 2025-01-01 10:00:00 | 40 |
4647
+ | 0 | 2 | 40 | 80 | 14400000 | F2 | B | C | 2025-01-01 12:00:00 | 2025-01-01 13:00:00 | 40 |
4648
+ | 1 | 1 | 120 | 120 | 10800000 | F3 | A | C | 2025-01-01 09:00:00 | 2025-01-01 12:00:00 | 120 |
4649
+
4476
4650
  #### `findCycles`
4477
4651
 
4478
4652
  Finds all cycles starting and ending at each node in `startNodes`. Pass one node
@@ -4546,7 +4720,7 @@ By default, connections are followed from source to target:
4546
4720
  ##### Signature
4547
4721
 
4548
4722
  ```typescript
4549
- findCycles(sourceColumn: string, targetColumn: string, edgeId: string, startNodes: string | number | bigint | (string | number | bigint)[], options?: { direction?: "outgoing" | "incoming" | "both"; endTimeColumn?: string; minGapMs?: number; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean; weight?: string }): SimpleTable;
4723
+ findCycles(sourceColumn: string, targetColumn: string, edgeId: string, startNodes: string | number | bigint | (string | number | bigint)[], options?: { direction?: "outgoing" | "incoming" | "both"; elapsedTime?: boolean; endTimeColumn?: string; minGapMs?: number; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean; weight?: string }): SimpleTable;
4550
4724
  ```
4551
4725
 
4552
4726
  ##### Parameters
@@ -4577,6 +4751,9 @@ findCycles(sourceColumn: string, targetColumn: string, edgeId: string, startNode
4577
4751
  time column.
4578
4752
  - **`options.weight`**: The name of the numeric column used as the cost of each
4579
4753
  connection. If omitted, each connection costs one.
4754
+ - **`options.elapsedTime`**: Whether to add cumulative `elapsedTimeMs` in
4755
+ milliseconds, including connection gaps. Defaults to `false`. Requires both
4756
+ time columns.
4580
4757
  - **`options.outputTable`**: If `true`, stores the result in a new table with a
4581
4758
  generated name. If a string, uses it as the new table's name. If `false` or
4582
4759
  omitted, overwrites the current table. Defaults to `false`.
@@ -4755,6 +4932,54 @@ await timedFlights
4755
4932
  | B | 0 | 2 | 1 | 2 | F2 | C | A | 2025-01-01 10:00:00 |
4756
4933
  | B | 0 | 3 | 1 | 3 | F1 | B | C | 2025-01-01 09:00:00 |
4757
4934
 
4935
+ For the next two examples, `flights` contains these rows, with departure and
4936
+ arrival stored as timestamps on the same day:
4937
+
4938
+ | flightId | origin | destination | departure | arrival | price |
4939
+ | -------- | ------ | ----------- | ---------------- | ---------------- | ----: |
4940
+ | F1 | A | B | 2025-01-01 09:00 | 2025-01-01 10:00 | 40 |
4941
+ | F2 | B | A | 2025-01-01 12:00 | 2025-01-01 13:00 | 60 |
4942
+
4943
+ Report elapsed time for every cycle, including layovers:
4944
+
4945
+ ```ts
4946
+ await flights
4947
+ .findCycles("origin", "destination", "flightId", "A", {
4948
+ startTimeColumn: "departure",
4949
+ endTimeColumn: "arrival",
4950
+ minGapMs: 60 * 60 * 1000,
4951
+ elapsedTime: true,
4952
+ })
4953
+ .log();
4954
+ ```
4955
+
4956
+ | start | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
4957
+ | ----- | -----: | ---: | -----: | ----: | ------------: | -------- | ------ | ----------- | ------------------- | ------------------- | ----: |
4958
+ | A | 0 | 1 | 1 | 1 | 3600000 | F1 | A | B | 2025-01-01 09:00:00 | 2025-01-01 10:00:00 | 40 |
4959
+ | A | 0 | 2 | 1 | 2 | 14400000 | F2 | B | A | 2025-01-01 12:00:00 | 2025-01-01 13:00:00 | 60 |
4960
+
4961
+ The return journey takes four hours (14,400,000 milliseconds), including the
4962
+ two-hour layover at B.
4963
+
4964
+ Add up prices while continuing to report elapsed time for every cycle:
4965
+
4966
+ ```ts
4967
+ await flights
4968
+ .findCycles("origin", "destination", "flightId", "A", {
4969
+ startTimeColumn: "departure",
4970
+ endTimeColumn: "arrival",
4971
+ minGapMs: 60 * 60 * 1000,
4972
+ elapsedTime: true,
4973
+ weight: "price",
4974
+ })
4975
+ .log();
4976
+ ```
4977
+
4978
+ | start | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
4979
+ | ----- | -----: | ---: | -----: | ----: | ------------: | -------- | ------ | ----------- | ------------------- | ------------------- | ----: |
4980
+ | A | 0 | 1 | 40 | 40 | 3600000 | F1 | A | B | 2025-01-01 09:00:00 | 2025-01-01 10:00:00 | 40 |
4981
+ | A | 0 | 2 | 60 | 100 | 14400000 | F2 | B | A | 2025-01-01 12:00:00 | 2025-01-01 13:00:00 | 60 |
4982
+
4758
4983
  #### `extractDatePart`
4759
4984
 
4760
4985
  Extracts one or more components from a temporal column into new columns. Pass a
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.6`
6
+ - Version: `2.1.7`
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.6",
3
+ "version": "2.1.7",
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",