@nshiab/simple-data-analysis-core 2.0.9 → 2.1.1

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 (459) hide show
  1. package/esm/class/SDAError.d.ts +6 -6
  2. package/esm/class/SDAError.js +6 -6
  3. package/esm/class/Simple.d.ts +9 -9
  4. package/esm/class/Simple.js +9 -9
  5. package/esm/class/SimpleDB.d.ts +80 -76
  6. package/esm/class/SimpleDB.d.ts.map +1 -1
  7. package/esm/class/SimpleDB.js +80 -76
  8. package/esm/class/SimpleTable.d.ts +2806 -1139
  9. package/esm/class/SimpleTable.d.ts.map +1 -1
  10. package/esm/class/SimpleTable.js +2792 -1149
  11. package/esm/helpers/buildApproximateMutualReachabilityMst.d.ts +45 -0
  12. package/esm/helpers/buildApproximateMutualReachabilityMst.d.ts.map +1 -0
  13. package/esm/helpers/buildApproximateMutualReachabilityMst.js +212 -0
  14. package/esm/helpers/buildChronologicalGraphComponentsSql.d.ts +14 -0
  15. package/esm/helpers/buildChronologicalGraphComponentsSql.d.ts.map +1 -0
  16. package/esm/helpers/buildChronologicalGraphComponentsSql.js +167 -0
  17. package/esm/helpers/buildExactMutualReachabilityMst.d.ts +28 -0
  18. package/esm/helpers/buildExactMutualReachabilityMst.d.ts.map +1 -0
  19. package/esm/helpers/buildExactMutualReachabilityMst.js +97 -0
  20. package/esm/helpers/buildGraphTemporalCostStateSql.d.ts +12 -0
  21. package/esm/helpers/buildGraphTemporalCostStateSql.d.ts.map +1 -0
  22. package/esm/helpers/buildGraphTemporalCostStateSql.js +86 -0
  23. package/esm/helpers/buildGraphTemporalReachabilitySql.d.ts +13 -0
  24. package/esm/helpers/buildGraphTemporalReachabilitySql.d.ts.map +1 -0
  25. package/esm/helpers/buildGraphTemporalReachabilitySql.js +70 -0
  26. package/esm/helpers/buildSparseMutualReachabilityMst.d.ts +10 -0
  27. package/esm/helpers/buildSparseMutualReachabilityMst.d.ts.map +1 -0
  28. package/esm/helpers/buildSparseMutualReachabilityMst.js +47 -0
  29. package/esm/helpers/buildUmapGraph.d.ts +2 -5
  30. package/esm/helpers/buildUmapGraph.d.ts.map +1 -1
  31. package/esm/helpers/buildUmapGraph.js +6 -100
  32. package/esm/helpers/buildVectorNeighbors.d.ts +45 -0
  33. package/esm/helpers/buildVectorNeighbors.d.ts.map +1 -0
  34. package/esm/helpers/buildVectorNeighbors.js +170 -0
  35. package/esm/helpers/buildWeakGraphComponentsSql.d.ts +3 -0
  36. package/esm/helpers/buildWeakGraphComponentsSql.d.ts.map +1 -0
  37. package/esm/helpers/buildWeakGraphComponentsSql.js +32 -0
  38. package/esm/helpers/camelCase.d.ts +7 -5
  39. package/esm/helpers/camelCase.d.ts.map +1 -1
  40. package/esm/helpers/camelCase.js +7 -5
  41. package/esm/helpers/capitalize.d.ts +6 -4
  42. package/esm/helpers/capitalize.d.ts.map +1 -1
  43. package/esm/helpers/capitalize.js +6 -4
  44. package/esm/helpers/clusterHdbscan.d.ts +18 -0
  45. package/esm/helpers/clusterHdbscan.d.ts.map +1 -0
  46. package/esm/helpers/clusterHdbscan.js +342 -0
  47. package/esm/helpers/computeCovariance.d.ts +16 -0
  48. package/esm/helpers/computeCovariance.d.ts.map +1 -0
  49. package/esm/helpers/computeCovariance.js +99 -0
  50. package/esm/helpers/computeMahalanobisDistances.d.ts +14 -0
  51. package/esm/helpers/computeMahalanobisDistances.d.ts.map +1 -0
  52. package/esm/helpers/computeMahalanobisDistances.js +87 -0
  53. package/esm/helpers/createDirectory.d.ts +4 -3
  54. package/esm/helpers/createDirectory.d.ts.map +1 -1
  55. package/esm/helpers/createDirectory.js +4 -3
  56. package/esm/helpers/dataToArrays.d.ts +6 -4
  57. package/esm/helpers/dataToArrays.d.ts.map +1 -1
  58. package/esm/helpers/dataToArrays.js +6 -4
  59. package/esm/helpers/extractTypes.d.ts +1 -1
  60. package/esm/helpers/extractTypes.js +4 -9
  61. package/esm/helpers/factorCovariance.d.ts +17 -0
  62. package/esm/helpers/factorCovariance.d.ts.map +1 -0
  63. package/esm/helpers/factorCovariance.js +189 -0
  64. package/esm/helpers/findGeoColumn.d.ts +6 -4
  65. package/esm/helpers/findGeoColumn.d.ts.map +1 -1
  66. package/esm/helpers/findGeoColumn.js +6 -4
  67. package/esm/helpers/findGeoColumnFromSchema.d.ts +8 -5
  68. package/esm/helpers/findGeoColumnFromSchema.d.ts.map +1 -1
  69. package/esm/helpers/findGeoColumnFromSchema.js +8 -5
  70. package/esm/helpers/formatDate.d.ts +12 -6
  71. package/esm/helpers/formatDate.d.ts.map +1 -1
  72. package/esm/helpers/formatDate.js +12 -6
  73. package/esm/helpers/formatMissingTables.d.ts +8 -5
  74. package/esm/helpers/formatMissingTables.d.ts.map +1 -1
  75. package/esm/helpers/formatMissingTables.js +8 -5
  76. package/esm/helpers/formatNumber.d.ts +19 -10
  77. package/esm/helpers/formatNumber.d.ts.map +1 -1
  78. package/esm/helpers/formatNumber.js +32 -17
  79. package/esm/helpers/getGraphEdgeIdColumn.d.ts +9 -0
  80. package/esm/helpers/getGraphEdgeIdColumn.d.ts.map +1 -0
  81. package/esm/helpers/getGraphEdgeIdColumn.js +25 -0
  82. package/esm/helpers/getGraphEndpointColumns.d.ts +11 -0
  83. package/esm/helpers/getGraphEndpointColumns.d.ts.map +1 -0
  84. package/esm/helpers/getGraphEndpointColumns.js +160 -0
  85. package/esm/helpers/getGraphWeightColumn.d.ts +10 -0
  86. package/esm/helpers/getGraphWeightColumn.d.ts.map +1 -0
  87. package/esm/helpers/getGraphWeightColumn.js +40 -0
  88. package/esm/helpers/graphRouteResultSchema.d.ts +4 -0
  89. package/esm/helpers/graphRouteResultSchema.d.ts.map +1 -0
  90. package/esm/helpers/graphRouteResultSchema.js +12 -0
  91. package/esm/helpers/graphRouteResultSelect.d.ts +4 -0
  92. package/esm/helpers/graphRouteResultSelect.d.ts.map +1 -0
  93. package/esm/helpers/graphRouteResultSelect.js +22 -0
  94. package/esm/helpers/hasGeometryColumn.d.ts +4 -3
  95. package/esm/helpers/hasGeometryColumn.d.ts.map +1 -1
  96. package/esm/helpers/hasGeometryColumn.js +4 -3
  97. package/esm/helpers/inspectGraphConnectivity.d.ts +10 -0
  98. package/esm/helpers/inspectGraphConnectivity.d.ts.map +1 -0
  99. package/esm/helpers/inspectGraphConnectivity.js +55 -0
  100. package/esm/helpers/mergeOptions.d.ts +24 -13
  101. package/esm/helpers/mergeOptions.d.ts.map +1 -1
  102. package/esm/helpers/mergeOptions.js +24 -13
  103. package/esm/helpers/parseValue.d.ts +6 -4
  104. package/esm/helpers/parseValue.d.ts.map +1 -1
  105. package/esm/helpers/parseValue.js +6 -4
  106. package/esm/helpers/prepareGraphRouteSql.d.ts +31 -0
  107. package/esm/helpers/prepareGraphRouteSql.d.ts.map +1 -0
  108. package/esm/helpers/prepareGraphRouteSql.js +86 -0
  109. package/esm/helpers/prepareGraphStarts.d.ts +9 -0
  110. package/esm/helpers/prepareGraphStarts.d.ts.map +1 -0
  111. package/esm/helpers/prepareGraphStarts.js +68 -0
  112. package/esm/helpers/prepareGraphTemporalSql.d.ts +28 -0
  113. package/esm/helpers/prepareGraphTemporalSql.d.ts.map +1 -0
  114. package/esm/helpers/prepareGraphTemporalSql.js +154 -0
  115. package/esm/helpers/prepareGraphTraversal.d.ts +19 -0
  116. package/esm/helpers/prepareGraphTraversal.d.ts.map +1 -0
  117. package/esm/helpers/prepareGraphTraversal.js +79 -0
  118. package/esm/helpers/prepareNumericFeatures.d.ts +41 -0
  119. package/esm/helpers/prepareNumericFeatures.d.ts.map +1 -0
  120. package/esm/helpers/prepareNumericFeatures.js +210 -0
  121. package/esm/helpers/prettyDuration.d.ts +14 -8
  122. package/esm/helpers/prettyDuration.d.ts.map +1 -1
  123. package/esm/helpers/prettyDuration.js +14 -8
  124. package/esm/helpers/printTable.d.ts +18 -13
  125. package/esm/helpers/printTable.d.ts.map +1 -1
  126. package/esm/helpers/printTable.js +18 -13
  127. package/esm/helpers/publishPreparedColumns.d.ts +37 -0
  128. package/esm/helpers/publishPreparedColumns.d.ts.map +1 -0
  129. package/esm/helpers/publishPreparedColumns.js +113 -0
  130. package/esm/helpers/queryDB.d.ts +24 -13
  131. package/esm/helpers/queryDB.d.ts.map +1 -1
  132. package/esm/helpers/queryDB.js +24 -13
  133. package/esm/helpers/queueAsyncBarrier.d.ts +12 -7
  134. package/esm/helpers/queueAsyncBarrier.d.ts.map +1 -1
  135. package/esm/helpers/queueAsyncBarrier.js +12 -7
  136. package/esm/helpers/queueGraphResult.d.ts +18 -0
  137. package/esm/helpers/queueGraphResult.d.ts.map +1 -0
  138. package/esm/helpers/queueGraphResult.js +39 -0
  139. package/esm/helpers/quoteIdentifier.d.ts +4 -3
  140. package/esm/helpers/quoteIdentifier.d.ts.map +1 -1
  141. package/esm/helpers/quoteIdentifier.js +4 -3
  142. package/esm/helpers/quoteQualifiedIdentifier.d.ts +6 -4
  143. package/esm/helpers/quoteQualifiedIdentifier.d.ts.map +1 -1
  144. package/esm/helpers/quoteQualifiedIdentifier.js +6 -4
  145. package/esm/helpers/runQuery.d.ts.map +1 -1
  146. package/esm/helpers/runQuery.js +17 -3
  147. package/esm/helpers/selectFuzzyReplacements.d.ts +11 -0
  148. package/esm/helpers/selectFuzzyReplacements.d.ts.map +1 -0
  149. package/esm/helpers/selectFuzzyReplacements.js +124 -0
  150. package/esm/helpers/stabilizeCosineVectors.d.ts +14 -0
  151. package/esm/helpers/stabilizeCosineVectors.d.ts.map +1 -0
  152. package/esm/helpers/stabilizeCosineVectors.js +34 -0
  153. package/esm/helpers/stringToArray.d.ts +4 -3
  154. package/esm/helpers/stringToArray.d.ts.map +1 -1
  155. package/esm/helpers/stringToArray.js +4 -3
  156. package/esm/helpers/updateColumnsWithJS.d.ts +12 -6
  157. package/esm/helpers/updateColumnsWithJS.d.ts.map +1 -1
  158. package/esm/helpers/updateColumnsWithJS.js +12 -6
  159. package/esm/helpers/validateGraphRouteResultSchema.d.ts +4 -0
  160. package/esm/helpers/validateGraphRouteResultSchema.d.ts.map +1 -0
  161. package/esm/helpers/validateGraphRouteResultSchema.js +13 -0
  162. package/esm/helpers/validateGraphTemporalEvents.d.ts +7 -0
  163. package/esm/helpers/validateGraphTemporalEvents.d.ts.map +1 -0
  164. package/esm/helpers/validateGraphTemporalEvents.js +47 -0
  165. package/esm/helpers/validateNumericalAnalysis.d.ts +10 -6
  166. package/esm/helpers/validateNumericalAnalysis.d.ts.map +1 -1
  167. package/esm/helpers/validateNumericalAnalysis.js +10 -6
  168. package/esm/helpers/validateVectorRowIds.d.ts +4 -0
  169. package/esm/helpers/validateVectorRowIds.d.ts.map +1 -0
  170. package/esm/helpers/validateVectorRowIds.js +16 -0
  171. package/esm/helpers/vectorDistanceExpression.d.ts +6 -0
  172. package/esm/helpers/vectorDistanceExpression.d.ts.map +1 -0
  173. package/esm/helpers/vectorDistanceExpression.js +11 -0
  174. package/esm/helpers/wrapString.d.ts +10 -7
  175. package/esm/helpers/wrapString.d.ts.map +1 -1
  176. package/esm/helpers/wrapString.js +10 -7
  177. package/esm/methods/addId.d.ts +5 -0
  178. package/esm/methods/addId.d.ts.map +1 -0
  179. package/esm/methods/addId.js +38 -0
  180. package/esm/methods/commonNeighbors.d.ts +10 -0
  181. package/esm/methods/commonNeighbors.d.ts.map +1 -0
  182. package/esm/methods/commonNeighbors.js +101 -0
  183. package/esm/methods/connectedComponents.d.ts +9 -0
  184. package/esm/methods/connectedComponents.d.ts.map +1 -0
  185. package/esm/methods/connectedComponents.js +147 -0
  186. package/esm/methods/degree.d.ts +9 -0
  187. package/esm/methods/degree.d.ts.map +1 -0
  188. package/esm/methods/degree.js +135 -0
  189. package/esm/methods/distances.d.ts +12 -0
  190. package/esm/methods/distances.d.ts.map +1 -0
  191. package/esm/methods/distances.js +164 -0
  192. package/esm/methods/findCycles.d.ts +12 -0
  193. package/esm/methods/findCycles.d.ts.map +1 -0
  194. package/esm/methods/findCycles.js +330 -0
  195. package/esm/methods/fuzzyClean.d.ts.map +1 -1
  196. package/esm/methods/fuzzyClean.js +17 -136
  197. package/esm/methods/fuzzyJoin.js +70 -16
  198. package/esm/methods/getTypes.d.ts +1 -1
  199. package/esm/methods/hdbscan.d.ts +5 -0
  200. package/esm/methods/hdbscan.d.ts.map +1 -0
  201. package/esm/methods/hdbscan.js +208 -0
  202. package/esm/methods/mahalanobis.d.ts +5 -0
  203. package/esm/methods/mahalanobis.d.ts.map +1 -0
  204. package/esm/methods/mahalanobis.js +92 -0
  205. package/esm/methods/neighbors.d.ts +9 -0
  206. package/esm/methods/neighbors.d.ts.map +1 -0
  207. package/esm/methods/neighbors.js +81 -0
  208. package/esm/methods/normalizeVector.d.ts +5 -0
  209. package/esm/methods/normalizeVector.d.ts.map +1 -0
  210. package/esm/methods/normalizeVector.js +132 -0
  211. package/esm/methods/paths.d.ts +12 -0
  212. package/esm/methods/paths.d.ts.map +1 -0
  213. package/esm/methods/paths.js +287 -0
  214. package/esm/methods/reachable.d.ts +11 -0
  215. package/esm/methods/reachable.d.ts.map +1 -0
  216. package/esm/methods/reachable.js +131 -0
  217. package/esm/methods/rowToVector.d.ts +5 -0
  218. package/esm/methods/rowToVector.d.ts.map +1 -0
  219. package/esm/methods/rowToVector.js +77 -0
  220. package/esm/methods/shortestPath.d.ts +12 -0
  221. package/esm/methods/shortestPath.d.ts.map +1 -0
  222. package/esm/methods/shortestPath.js +337 -0
  223. package/esm/methods/topologicalSort.d.ts +7 -0
  224. package/esm/methods/topologicalSort.d.ts.map +1 -0
  225. package/esm/methods/topologicalSort.js +164 -0
  226. package/esm/methods/trim.d.ts +1 -1
  227. package/esm/methods/trim.d.ts.map +1 -1
  228. package/esm/methods/trim.js +17 -8
  229. package/llm.md +2146 -173
  230. package/llms.txt +1 -1
  231. package/package.json +1 -1
  232. package/script/class/SDAError.d.ts +6 -6
  233. package/script/class/SDAError.js +6 -6
  234. package/script/class/Simple.d.ts +9 -9
  235. package/script/class/Simple.js +9 -9
  236. package/script/class/SimpleDB.d.ts +80 -76
  237. package/script/class/SimpleDB.d.ts.map +1 -1
  238. package/script/class/SimpleDB.js +80 -76
  239. package/script/class/SimpleTable.d.ts +2806 -1139
  240. package/script/class/SimpleTable.d.ts.map +1 -1
  241. package/script/class/SimpleTable.js +2792 -1149
  242. package/script/helpers/buildApproximateMutualReachabilityMst.d.ts +45 -0
  243. package/script/helpers/buildApproximateMutualReachabilityMst.d.ts.map +1 -0
  244. package/script/helpers/buildApproximateMutualReachabilityMst.js +219 -0
  245. package/script/helpers/buildChronologicalGraphComponentsSql.d.ts +14 -0
  246. package/script/helpers/buildChronologicalGraphComponentsSql.d.ts.map +1 -0
  247. package/script/helpers/buildChronologicalGraphComponentsSql.js +174 -0
  248. package/script/helpers/buildExactMutualReachabilityMst.d.ts +28 -0
  249. package/script/helpers/buildExactMutualReachabilityMst.d.ts.map +1 -0
  250. package/script/helpers/buildExactMutualReachabilityMst.js +103 -0
  251. package/script/helpers/buildGraphTemporalCostStateSql.d.ts +12 -0
  252. package/script/helpers/buildGraphTemporalCostStateSql.d.ts.map +1 -0
  253. package/script/helpers/buildGraphTemporalCostStateSql.js +92 -0
  254. package/script/helpers/buildGraphTemporalReachabilitySql.d.ts +13 -0
  255. package/script/helpers/buildGraphTemporalReachabilitySql.d.ts.map +1 -0
  256. package/script/helpers/buildGraphTemporalReachabilitySql.js +76 -0
  257. package/script/helpers/buildSparseMutualReachabilityMst.d.ts +10 -0
  258. package/script/helpers/buildSparseMutualReachabilityMst.d.ts.map +1 -0
  259. package/script/helpers/buildSparseMutualReachabilityMst.js +50 -0
  260. package/script/helpers/buildUmapGraph.d.ts +2 -5
  261. package/script/helpers/buildUmapGraph.d.ts.map +1 -1
  262. package/script/helpers/buildUmapGraph.js +6 -100
  263. package/script/helpers/buildVectorNeighbors.d.ts +45 -0
  264. package/script/helpers/buildVectorNeighbors.d.ts.map +1 -0
  265. package/script/helpers/buildVectorNeighbors.js +176 -0
  266. package/script/helpers/buildWeakGraphComponentsSql.d.ts +3 -0
  267. package/script/helpers/buildWeakGraphComponentsSql.d.ts.map +1 -0
  268. package/script/helpers/buildWeakGraphComponentsSql.js +38 -0
  269. package/script/helpers/camelCase.d.ts +7 -5
  270. package/script/helpers/camelCase.d.ts.map +1 -1
  271. package/script/helpers/camelCase.js +7 -5
  272. package/script/helpers/capitalize.d.ts +6 -4
  273. package/script/helpers/capitalize.d.ts.map +1 -1
  274. package/script/helpers/capitalize.js +6 -4
  275. package/script/helpers/clusterHdbscan.d.ts +18 -0
  276. package/script/helpers/clusterHdbscan.d.ts.map +1 -0
  277. package/script/helpers/clusterHdbscan.js +346 -0
  278. package/script/helpers/computeCovariance.d.ts +16 -0
  279. package/script/helpers/computeCovariance.d.ts.map +1 -0
  280. package/script/helpers/computeCovariance.js +105 -0
  281. package/script/helpers/computeMahalanobisDistances.d.ts +14 -0
  282. package/script/helpers/computeMahalanobisDistances.d.ts.map +1 -0
  283. package/script/helpers/computeMahalanobisDistances.js +93 -0
  284. package/script/helpers/createDirectory.d.ts +4 -3
  285. package/script/helpers/createDirectory.d.ts.map +1 -1
  286. package/script/helpers/createDirectory.js +4 -3
  287. package/script/helpers/dataToArrays.d.ts +6 -4
  288. package/script/helpers/dataToArrays.d.ts.map +1 -1
  289. package/script/helpers/dataToArrays.js +6 -4
  290. package/script/helpers/extractTypes.d.ts +1 -1
  291. package/script/helpers/extractTypes.js +4 -9
  292. package/script/helpers/factorCovariance.d.ts +17 -0
  293. package/script/helpers/factorCovariance.d.ts.map +1 -0
  294. package/script/helpers/factorCovariance.js +194 -0
  295. package/script/helpers/findGeoColumn.d.ts +6 -4
  296. package/script/helpers/findGeoColumn.d.ts.map +1 -1
  297. package/script/helpers/findGeoColumn.js +6 -4
  298. package/script/helpers/findGeoColumnFromSchema.d.ts +8 -5
  299. package/script/helpers/findGeoColumnFromSchema.d.ts.map +1 -1
  300. package/script/helpers/findGeoColumnFromSchema.js +8 -5
  301. package/script/helpers/formatDate.d.ts +12 -6
  302. package/script/helpers/formatDate.d.ts.map +1 -1
  303. package/script/helpers/formatDate.js +12 -6
  304. package/script/helpers/formatMissingTables.d.ts +8 -5
  305. package/script/helpers/formatMissingTables.d.ts.map +1 -1
  306. package/script/helpers/formatMissingTables.js +8 -5
  307. package/script/helpers/formatNumber.d.ts +19 -10
  308. package/script/helpers/formatNumber.d.ts.map +1 -1
  309. package/script/helpers/formatNumber.js +32 -17
  310. package/script/helpers/getGraphEdgeIdColumn.d.ts +9 -0
  311. package/script/helpers/getGraphEdgeIdColumn.d.ts.map +1 -0
  312. package/script/helpers/getGraphEdgeIdColumn.js +31 -0
  313. package/script/helpers/getGraphEndpointColumns.d.ts +11 -0
  314. package/script/helpers/getGraphEndpointColumns.d.ts.map +1 -0
  315. package/script/helpers/getGraphEndpointColumns.js +166 -0
  316. package/script/helpers/getGraphWeightColumn.d.ts +10 -0
  317. package/script/helpers/getGraphWeightColumn.d.ts.map +1 -0
  318. package/script/helpers/getGraphWeightColumn.js +46 -0
  319. package/script/helpers/graphRouteResultSchema.d.ts +4 -0
  320. package/script/helpers/graphRouteResultSchema.d.ts.map +1 -0
  321. package/script/helpers/graphRouteResultSchema.js +18 -0
  322. package/script/helpers/graphRouteResultSelect.d.ts +4 -0
  323. package/script/helpers/graphRouteResultSelect.d.ts.map +1 -0
  324. package/script/helpers/graphRouteResultSelect.js +28 -0
  325. package/script/helpers/hasGeometryColumn.d.ts +4 -3
  326. package/script/helpers/hasGeometryColumn.d.ts.map +1 -1
  327. package/script/helpers/hasGeometryColumn.js +4 -3
  328. package/script/helpers/inspectGraphConnectivity.d.ts +10 -0
  329. package/script/helpers/inspectGraphConnectivity.d.ts.map +1 -0
  330. package/script/helpers/inspectGraphConnectivity.js +58 -0
  331. package/script/helpers/mergeOptions.d.ts +24 -13
  332. package/script/helpers/mergeOptions.d.ts.map +1 -1
  333. package/script/helpers/mergeOptions.js +24 -13
  334. package/script/helpers/parseValue.d.ts +6 -4
  335. package/script/helpers/parseValue.d.ts.map +1 -1
  336. package/script/helpers/parseValue.js +6 -4
  337. package/script/helpers/prepareGraphRouteSql.d.ts +31 -0
  338. package/script/helpers/prepareGraphRouteSql.d.ts.map +1 -0
  339. package/script/helpers/prepareGraphRouteSql.js +127 -0
  340. package/script/helpers/prepareGraphStarts.d.ts +9 -0
  341. package/script/helpers/prepareGraphStarts.d.ts.map +1 -0
  342. package/script/helpers/prepareGraphStarts.js +71 -0
  343. package/script/helpers/prepareGraphTemporalSql.d.ts +28 -0
  344. package/script/helpers/prepareGraphTemporalSql.d.ts.map +1 -0
  345. package/script/helpers/prepareGraphTemporalSql.js +161 -0
  346. package/script/helpers/prepareGraphTraversal.d.ts +19 -0
  347. package/script/helpers/prepareGraphTraversal.d.ts.map +1 -0
  348. package/script/helpers/prepareGraphTraversal.js +87 -0
  349. package/script/helpers/prepareNumericFeatures.d.ts +41 -0
  350. package/script/helpers/prepareNumericFeatures.d.ts.map +1 -0
  351. package/script/helpers/prepareNumericFeatures.js +217 -0
  352. package/script/helpers/prettyDuration.d.ts +14 -8
  353. package/script/helpers/prettyDuration.d.ts.map +1 -1
  354. package/script/helpers/prettyDuration.js +14 -8
  355. package/script/helpers/printTable.d.ts +18 -13
  356. package/script/helpers/printTable.d.ts.map +1 -1
  357. package/script/helpers/printTable.js +18 -13
  358. package/script/helpers/publishPreparedColumns.d.ts +37 -0
  359. package/script/helpers/publishPreparedColumns.d.ts.map +1 -0
  360. package/script/helpers/publishPreparedColumns.js +119 -0
  361. package/script/helpers/queryDB.d.ts +24 -13
  362. package/script/helpers/queryDB.d.ts.map +1 -1
  363. package/script/helpers/queryDB.js +24 -13
  364. package/script/helpers/queueAsyncBarrier.d.ts +12 -7
  365. package/script/helpers/queueAsyncBarrier.d.ts.map +1 -1
  366. package/script/helpers/queueAsyncBarrier.js +12 -7
  367. package/script/helpers/queueGraphResult.d.ts +18 -0
  368. package/script/helpers/queueGraphResult.d.ts.map +1 -0
  369. package/script/helpers/queueGraphResult.js +45 -0
  370. package/script/helpers/quoteIdentifier.d.ts +4 -3
  371. package/script/helpers/quoteIdentifier.d.ts.map +1 -1
  372. package/script/helpers/quoteIdentifier.js +4 -3
  373. package/script/helpers/quoteQualifiedIdentifier.d.ts +6 -4
  374. package/script/helpers/quoteQualifiedIdentifier.d.ts.map +1 -1
  375. package/script/helpers/quoteQualifiedIdentifier.js +6 -4
  376. package/script/helpers/runQuery.d.ts.map +1 -1
  377. package/script/helpers/runQuery.js +17 -3
  378. package/script/helpers/selectFuzzyReplacements.d.ts +11 -0
  379. package/script/helpers/selectFuzzyReplacements.d.ts.map +1 -0
  380. package/script/helpers/selectFuzzyReplacements.js +127 -0
  381. package/script/helpers/stabilizeCosineVectors.d.ts +14 -0
  382. package/script/helpers/stabilizeCosineVectors.d.ts.map +1 -0
  383. package/script/helpers/stabilizeCosineVectors.js +40 -0
  384. package/script/helpers/stringToArray.d.ts +4 -3
  385. package/script/helpers/stringToArray.d.ts.map +1 -1
  386. package/script/helpers/stringToArray.js +4 -3
  387. package/script/helpers/updateColumnsWithJS.d.ts +12 -6
  388. package/script/helpers/updateColumnsWithJS.d.ts.map +1 -1
  389. package/script/helpers/updateColumnsWithJS.js +12 -6
  390. package/script/helpers/validateGraphRouteResultSchema.d.ts +4 -0
  391. package/script/helpers/validateGraphRouteResultSchema.d.ts.map +1 -0
  392. package/script/helpers/validateGraphRouteResultSchema.js +19 -0
  393. package/script/helpers/validateGraphTemporalEvents.d.ts +7 -0
  394. package/script/helpers/validateGraphTemporalEvents.d.ts.map +1 -0
  395. package/script/helpers/validateGraphTemporalEvents.js +53 -0
  396. package/script/helpers/validateNumericalAnalysis.d.ts +10 -6
  397. package/script/helpers/validateNumericalAnalysis.d.ts.map +1 -1
  398. package/script/helpers/validateNumericalAnalysis.js +10 -6
  399. package/script/helpers/validateVectorRowIds.d.ts +4 -0
  400. package/script/helpers/validateVectorRowIds.d.ts.map +1 -0
  401. package/script/helpers/validateVectorRowIds.js +19 -0
  402. package/script/helpers/vectorDistanceExpression.d.ts +6 -0
  403. package/script/helpers/vectorDistanceExpression.d.ts.map +1 -0
  404. package/script/helpers/vectorDistanceExpression.js +14 -0
  405. package/script/helpers/wrapString.d.ts +10 -7
  406. package/script/helpers/wrapString.d.ts.map +1 -1
  407. package/script/helpers/wrapString.js +10 -7
  408. package/script/methods/addId.d.ts +5 -0
  409. package/script/methods/addId.d.ts.map +1 -0
  410. package/script/methods/addId.js +44 -0
  411. package/script/methods/commonNeighbors.d.ts +10 -0
  412. package/script/methods/commonNeighbors.d.ts.map +1 -0
  413. package/script/methods/commonNeighbors.js +140 -0
  414. package/script/methods/connectedComponents.d.ts +9 -0
  415. package/script/methods/connectedComponents.d.ts.map +1 -0
  416. package/script/methods/connectedComponents.js +186 -0
  417. package/script/methods/degree.d.ts +9 -0
  418. package/script/methods/degree.d.ts.map +1 -0
  419. package/script/methods/degree.js +141 -0
  420. package/script/methods/distances.d.ts +12 -0
  421. package/script/methods/distances.d.ts.map +1 -0
  422. package/script/methods/distances.js +203 -0
  423. package/script/methods/findCycles.d.ts +12 -0
  424. package/script/methods/findCycles.d.ts.map +1 -0
  425. package/script/methods/findCycles.js +369 -0
  426. package/script/methods/fuzzyClean.d.ts.map +1 -1
  427. package/script/methods/fuzzyClean.js +17 -136
  428. package/script/methods/fuzzyJoin.js +70 -16
  429. package/script/methods/getTypes.d.ts +1 -1
  430. package/script/methods/hdbscan.d.ts +5 -0
  431. package/script/methods/hdbscan.d.ts.map +1 -0
  432. package/script/methods/hdbscan.js +214 -0
  433. package/script/methods/mahalanobis.d.ts +5 -0
  434. package/script/methods/mahalanobis.d.ts.map +1 -0
  435. package/script/methods/mahalanobis.js +98 -0
  436. package/script/methods/neighbors.d.ts +9 -0
  437. package/script/methods/neighbors.d.ts.map +1 -0
  438. package/script/methods/neighbors.js +120 -0
  439. package/script/methods/normalizeVector.d.ts +5 -0
  440. package/script/methods/normalizeVector.d.ts.map +1 -0
  441. package/script/methods/normalizeVector.js +138 -0
  442. package/script/methods/paths.d.ts +12 -0
  443. package/script/methods/paths.d.ts.map +1 -0
  444. package/script/methods/paths.js +326 -0
  445. package/script/methods/reachable.d.ts +11 -0
  446. package/script/methods/reachable.d.ts.map +1 -0
  447. package/script/methods/reachable.js +170 -0
  448. package/script/methods/rowToVector.d.ts +5 -0
  449. package/script/methods/rowToVector.d.ts.map +1 -0
  450. package/script/methods/rowToVector.js +83 -0
  451. package/script/methods/shortestPath.d.ts +12 -0
  452. package/script/methods/shortestPath.d.ts.map +1 -0
  453. package/script/methods/shortestPath.js +376 -0
  454. package/script/methods/topologicalSort.d.ts +7 -0
  455. package/script/methods/topologicalSort.d.ts.map +1 -0
  456. package/script/methods/topologicalSort.js +170 -0
  457. package/script/methods/trim.d.ts +1 -1
  458. package/script/methods/trim.d.ts.map +1 -1
  459. package/script/methods/trim.js +17 -8
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.0.9`
4
+ - Version: `2.1.1`
5
5
 
6
6
  To install the library with Deno, use:
7
7
 
@@ -1530,6 +1530,80 @@ await table.umap("embedding", {
1530
1530
  }).selectColumns(["label", "umapX", "umapY"]).log();
1531
1531
  ```
1532
1532
 
1533
+ #### `hdbscan`
1534
+
1535
+ Groups rows with similar numeric features using HDBSCAN, without requiring a
1536
+ predefined number of clusters. Adds a VARCHAR column containing `"cluster-0"`,
1537
+ `"cluster-1"`, etc., or `"noise"` for rows outside clusters. Labels identify
1538
+ groups, not their rank.
1539
+
1540
+ Accepts a numeric vector column or several numeric scalar columns. Features are
1541
+ used as supplied. If their scales differ, consider preparing them with
1542
+ `normalize()`, `zScore()`, or `normalizeVector()` before clustering.
1543
+
1544
+ Exact clustering is the default and can be expensive for large datasets. Set
1545
+ `approximate: true` to use approximate clustering, which can produce different
1546
+ results, including between repeated runs.
1547
+
1548
+ ##### Signature
1549
+
1550
+ ```typescript
1551
+ hdbscan(columns: string | string[], newColumn: string, options?: { minClusterSize?: number; minSamples?: number; metric?: "euclidean" | "cosine"; allowSingleCluster?: boolean; approximate?: boolean; membershipScoreColumn?: string; outlierScoreColumn?: string }): this;
1552
+ ```
1553
+
1554
+ ##### Parameters
1555
+
1556
+ - **`columns`**: A numeric vector column, or numeric scalar columns in
1557
+ feature-dimension order.
1558
+ - **`newColumn`**: The cluster-label column to create.
1559
+ - **`options`**: HDBSCAN clustering and output settings.
1560
+ - **`options.minClusterSize`**: Minimum cluster size, from `2` through the row
1561
+ count. Defaults to `5`.
1562
+ - **`options.minSamples`**: Number of neighbors used to estimate local density,
1563
+ excluding the point itself. Higher values make clustering more conservative,
1564
+ generally labeling more rows as noise. Set this separately to adjust density
1565
+ sensitivity independently of minimum cluster size. Defaults to
1566
+ `minClusterSize`.
1567
+ - **`options.metric`**: Use `"euclidean"` to compare feature values, or
1568
+ `"cosine"` to compare vector direction regardless of overall magnitude.
1569
+ Defaults to `"euclidean"`.
1570
+ - **`options.allowSingleCluster`**: Allow a result with just one cluster,
1571
+ possibly alongside noise. Defaults to `false`. Setting this to `true` can
1572
+ favor one broad group, even when there is little meaningful structure.
1573
+ - **`options.approximate`**: Use approximate clustering. Defaults to `false`.
1574
+ - **`options.membershipScoreColumn`**: Optional DOUBLE column for membership
1575
+ strength from `0` to `1`. Higher values indicate stronger membership in the
1576
+ assigned cluster; noise scores `0`.
1577
+ - **`options.outlierScoreColumn`**: Optional DOUBLE column for outlier scores
1578
+ from `0` to `1`. Higher values indicate more unusual rows relative to their
1579
+ surroundings, including within clusters. This is not necessarily
1580
+ `1 - membershipScore`.
1581
+
1582
+ ##### Returns
1583
+
1584
+ The table, so methods can be chained.
1585
+
1586
+ ##### Examples
1587
+
1588
+ ```ts
1589
+ // Cluster numeric columns and add membership and outlier scores.
1590
+ await table
1591
+ .hdbscan(["height", "weight"], "cluster", {
1592
+ minClusterSize: 5,
1593
+ membershipScoreColumn: "membership",
1594
+ outlierScoreColumn: "outlierScore",
1595
+ })
1596
+ .log();
1597
+ ```
1598
+
1599
+ ```ts
1600
+ // Scale vector dimensions before clustering.
1601
+ await table
1602
+ .normalizeVector("features", "scaledFeatures")
1603
+ .hdbscan("scaledFeatures", "cluster")
1604
+ .log();
1605
+ ```
1606
+
1533
1607
  #### `bm25`
1534
1608
 
1535
1609
  Searches a text column using DuckDB's BM25 ranking function, which scores
@@ -2336,17 +2410,20 @@ await table.removeMissing({ columns: "age", missingValues: [-1] }).log();
2336
2410
  #### `trim`
2337
2411
 
2338
2412
  Trims specified characters from the beginning, end, or both sides of string
2339
- values in the given columns.
2413
+ values in the given columns. Pass `"all"` to trim every string (VARCHAR) column,
2414
+ leaving other types unchanged. If there are no string columns, `"all"` leaves
2415
+ the table unchanged. Use `["all"]` to trim a column literally named `all`.
2340
2416
 
2341
2417
  ##### Signature
2342
2418
 
2343
2419
  ```typescript
2344
- trim(columns: string | string[], options?: { character?: string; side?: "left" | "right" | "both" }): this;
2420
+ trim(columns: "all" | string | string[], options?: { character?: string; side?: "left" | "right" | "both" }): this;
2345
2421
  ```
2346
2422
 
2347
2423
  ##### Parameters
2348
2424
 
2349
- - **`columns`**: The column name or an array of column names to trim.
2425
+ - **`columns`**: The column name, an array of column names, or `"all"` to trim
2426
+ every string (VARCHAR) column.
2350
2427
  - **`options`**: An optional object with configuration options:
2351
2428
  - **`options.character`**: The string to trim. Defaults to whitespace
2352
2429
  characters.
@@ -2365,6 +2442,11 @@ The table, so methods can be chained.
2365
2442
  await table.trim("column1").log();
2366
2443
  ```
2367
2444
 
2445
+ ```ts
2446
+ // Trim whitespace from every string column
2447
+ await table.trim("all").log();
2448
+ ```
2449
+
2368
2450
  ```ts
2369
2451
  // Trim leading and trailing asterisks from 'productCode'
2370
2452
  await table.trim("productCode", { character: "*" }).log();
@@ -2928,31 +3010,28 @@ await table.loadArray([{ count: 3 }])
2928
3010
  .log();
2929
3011
  ```
2930
3012
 
2931
- #### `extractDatePart`
3013
+ #### `addId`
2932
3014
 
2933
- Extracts one or more components from a temporal column into new columns. Pass a
2934
- single part to create a column with that part's name, or pass an object mapping
2935
- custom new-column names to parts. Existing columns are not overwritten.
3015
+ Adds a unique, non-null ID for each row in the current table. IDs start at `0`
3016
+ and identify rows within this table, including rows with identical contents.
3017
+ Without a prefix, the new column contains numbers. When a prefix is supplied,
3018
+ the new column contains strings with the exact prefix followed by the row
3019
+ number. An empty prefix therefore creates the strings `"0"`, `"1"`, and so on.
2936
3020
 
2937
- `dayOfWeek` uses Sunday as `0` through Saturday as `6`. `week` follows ISO week
2938
- numbering, and `dayOfYear` starts at `1`. DuckDB `DATE`, `TIME`, `TIMESTAMP`,
2939
- and `TIMESTAMP WITH TIME ZONE` columns are supported when the requested
2940
- component applies to that type: date parts apply to dates and timestamps, while
2941
- time parts apply to times and timestamps. `NULL` input values produce `NULL`
2942
- extracted values. Parts extracted from `TIMESTAMP WITH TIME ZONE` values use
2943
- UTC.
3021
+ IDs are not globally unique: separate tables can generate the same IDs.
2944
3022
 
2945
3023
  ##### Signature
2946
3024
 
2947
3025
  ```typescript
2948
- extractDatePart(column: string, parts: "year" | "quarter" | "month" | "week" | "day" | "dayOfWeek" | "dayOfYear" | "hour" | "minute" | "second" | Record<string, "year" | "quarter" | "month" | "week" | "day" | "dayOfWeek" | "dayOfYear" | "hour" | "minute" | "second">): this;
3026
+ addId(newColumn: string, options?: { prefix?: string }): this;
2949
3027
  ```
2950
3028
 
2951
3029
  ##### Parameters
2952
3030
 
2953
- - **`column`**: The temporal column from which to extract components.
2954
- - **`parts`**: A part to extract using its name as the new column, or an object
2955
- mapping each custom new-column name to the part it should contain.
3031
+ - **`newColumn`**: The name of the new ID column.
3032
+ - **`options`**: An optional object with configuration options.
3033
+ - **`options.prefix`**: Text to place before each row number. Supplying this
3034
+ option, including an empty string, creates string IDs.
2956
3035
 
2957
3036
  ##### Returns
2958
3037
 
@@ -2961,260 +3040,2006 @@ The table, so methods can be chained.
2961
3040
  ##### Examples
2962
3041
 
2963
3042
  ```ts
2964
- // Add a column named 'year' from the 'publishedAt' timestamp
2965
- await table.extractDatePart("publishedAt", "year").log();
3043
+ // Add numeric IDs: 0, 1, 2, ...
3044
+ await table
3045
+ .addId("edgeId")
3046
+ .log();
2966
3047
  ```
2967
3048
 
2968
3049
  ```ts
2969
- // Extract multiple components with custom column names
2970
- await table.extractDatePart("publishedAt", {
2971
- publicationYear: "year",
2972
- publicationMonth: "month",
2973
- }).log();
3050
+ // Add string IDs: "flight-0", "flight-1", "flight-2", ...
3051
+ await flights
3052
+ .addId("edgeId", { prefix: "flight-" })
3053
+ .log();
2974
3054
  ```
2975
3055
 
2976
- #### `addRowNumber`
3056
+ #### `neighbors`
2977
3057
 
2978
- Adds a new column to the table containing the row number, starting at 0 (like an
2979
- index).
3058
+ Finds the distinct nodes directly connected to one or more starting nodes. The
3059
+ `direction` option lets you find neighbors from source to target, from target to
3060
+ source, or in either direction. The result has `start` and `node` columns,
3061
+ sorted in ascending order by `start`, then `node`.
3062
+
3063
+ Unknown starting IDs and starts with no neighbors in the selected direction
3064
+ produce no rows. A self-connection includes the starting node once. Empty start
3065
+ arrays and duplicate starting IDs throw an error.
3066
+
3067
+ The next three examples each start with this data:
3068
+
3069
+ | origin | destination |
3070
+ | ------ | ----------- |
3071
+ | A | B |
3072
+ | A | B |
3073
+ | C | A |
3074
+
3075
+ By default, the method finds neighbors from source to target:
2980
3076
 
2981
3077
  ##### Signature
2982
3078
 
2983
3079
  ```typescript
2984
- addRowNumber(newColumn: string, options?: { by?: string | string[] }): this;
3080
+ neighbors(sourceColumn: string, targetColumn: string, startNodes: string | number | bigint | (string | number | bigint)[], options?: { direction?: "outgoing" | "incoming" | "both"; outputTable?: string | boolean }): SimpleTable;
2985
3081
  ```
2986
3082
 
2987
3083
  ##### Parameters
2988
3084
 
2989
- - **`newColumn`**: The name of the new column that will store the row number.
2990
- - **`options`**: An optional object with configuration options:
2991
- - **`options.by`**: A column name or an array of column names to partition by.
2992
- The row number restarts at 0 within each group.
3085
+ - **`sourceColumn`**: The name of the column containing each connection's source
3086
+ node ID.
3087
+ - **`targetColumn`**: The name of the column containing each connection's target
3088
+ node ID.
3089
+ - **`startNodes`**: One starting node ID or an array of distinct starting node
3090
+ IDs.
3091
+ - **`options`**: An optional object with direction and result configuration.
3092
+ - **`options.direction`**: The direction in which to follow connections.
3093
+ Defaults to `"outgoing"`.
3094
+ - **`options.outputTable`**: If `true`, stores the result in a new table with a
3095
+ generated name. If a string, uses it as the new table's name. If `false` or
3096
+ omitted, overwrites the current table. Defaults to `false`.
2993
3097
 
2994
3098
  ##### Returns
2995
3099
 
2996
- The table, so methods can be chained.
3100
+ The result table, so methods can be chained.
2997
3101
 
2998
3102
  ##### Examples
2999
3103
 
3000
3104
  ```ts
3001
- // Add a new column named 'rowNumber' with the row number for each row
3002
- await table.addRowNumber("rowNumber").log();
3003
- ```
3004
-
3005
- ```ts
3006
- // Add a new column named 'rowNumber' with the row number for each 'category'
3007
- await table.addRowNumber("rowNumber", { by: "category" }).log();
3105
+ await table
3106
+ .neighbors("origin", "destination", "A")
3107
+ .log();
3008
3108
  ```
3009
3109
 
3010
- #### `crossJoin`
3110
+ | start | node |
3111
+ | ----- | ---- |
3112
+ | A | B |
3011
3113
 
3012
- Performs a cross join operation with another table. A cross join returns the
3013
- Cartesian product of the rows from both tables, meaning all possible pairs of
3014
- rows will be in the resulting table. This means that if the left table has `n`
3015
- rows and the right table has `m` rows, the result will have `n * m` rows.
3114
+ B appears only once, even though the input has two connections from A to B.
3016
3115
 
3017
- ##### Signature
3116
+ With `direction: "incoming"`, the method finds neighbors from target to source.
3117
+ Here, C connects to A:
3018
3118
 
3019
- ```typescript
3020
- crossJoin(rightTable: SimpleTable, options?: { outputTable?: string | boolean }): this;
3119
+ ```ts
3120
+ await table
3121
+ .neighbors("origin", "destination", "A", { direction: "incoming" })
3122
+ .log();
3021
3123
  ```
3022
3124
 
3023
- ##### Parameters
3125
+ | start | node |
3126
+ | ----- | ---- |
3127
+ | A | C |
3024
3128
 
3025
- - **`rightTable`**: The SimpleTable instance to cross join with.
3026
- - **`options`**: An optional object with configuration options:
3027
- - **`options.outputTable`**: If `true`, the results will be stored in a new
3028
- table with a generated name. If a string, it will be used as the name for the
3029
- new table. If `false` or omitted, the current table will be overwritten.
3030
- Defaults to `false`.
3129
+ With `direction: "both"`, the method finds neighbors in either direction:
3031
3130
 
3032
- ##### Returns
3131
+ ```ts
3132
+ await table
3133
+ .neighbors("origin", "destination", "A", { direction: "both" })
3134
+ .log();
3135
+ ```
3033
3136
 
3034
- A table instance containing the cross-joined data (either the current table or a
3035
- new table), so methods can be chained.
3137
+ | start | node |
3138
+ | ----- | ---- |
3139
+ | A | B |
3140
+ | A | C |
3036
3141
 
3037
- ##### Examples
3142
+ Multiple starts are evaluated independently. For this input:
3038
3143
 
3039
- ```ts
3040
- // Perform a cross join with 'tableB', overwriting the current table (tableA)
3041
- await tableA.crossJoin(tableB).log();
3042
- ```
3144
+ | source | target | cost |
3145
+ | -------- | ------- | ---: |
3146
+ | Montreal | Ottawa | 2 |
3147
+ | Ottawa | Toronto | 3 |
3043
3148
 
3044
3149
  ```ts
3045
- // Perform a cross join with 'tableB' and store the results in a new table with a generated name
3046
- const tableC = await tableA.crossJoin(tableB, { outputTable: true }).log();
3150
+ await table
3151
+ .neighbors("source", "target", ["Montreal", "Ottawa"])
3152
+ .log();
3047
3153
  ```
3048
3154
 
3049
- ```ts
3050
- // Perform a cross join with 'tableB' and store the results in a new table named 'tableC'
3051
- const tableC = await tableA.crossJoin(tableB, { outputTable: "tableC" }).log();
3052
- ```
3155
+ | start | node |
3156
+ | -------- | ------- |
3157
+ | Montreal | Ottawa |
3158
+ | Ottawa | Toronto |
3053
3159
 
3054
- #### `join`
3160
+ #### `degree`
3055
3161
 
3056
- Merges the data of this table (considered the left table) with another table
3057
- (the right table) based on a common column or multiple columns. Note that the
3058
- order of rows in the returned data is not guaranteed to be the same as in the
3059
- original tables. This operation might create temporary files in a `.tmp` folder;
3060
- consider adding `.tmp` to your `.gitignore`.
3162
+ Counts the incoming and outgoing connections for every node found in the source
3163
+ and target columns. By default, each input row is counted separately, even when
3164
+ several rows connect the same two nodes. Set the `count` option to `"neighbors"`
3165
+ to count distinct neighboring nodes instead. Use the `weight` option to sum
3166
+ values from a numeric column instead of counting connections. The `weight`
3167
+ option cannot be combined with `count: "neighbors"`.
3168
+
3169
+ The result has `node`, `incoming`, `outgoing`, and `total` columns. The `total`
3170
+ is the sum of `incoming` and `outgoing`. Results are sorted by highest total
3171
+ first, then by node in ascending order when totals are equal. A self-connection
3172
+ contributes once to incoming and once to outgoing, so it contributes twice to
3173
+ the total. With `count: "neighbors"`, a neighbor connected in both directions
3174
+ also contributes once in each direction. Endpoint IDs must be non-null strings
3175
+ or whole numbers in compatible columns. Supplied weights must be non-null,
3176
+ finite, and non-negative.
3177
+
3178
+ The next three examples each start with these flights:
3179
+
3180
+ | origin | destination | passengers |
3181
+ | -------- | ----------- | ---------: |
3182
+ | Montreal | Toronto | 100 |
3183
+ | Montreal | Toronto | 200 |
3184
+ | Montreal | Vancouver | 50 |
3185
+ | Toronto | Montreal | 150 |
3186
+
3187
+ By default, the method counts connections and overwrites the input table:
3061
3188
 
3062
3189
  ##### Signature
3063
3190
 
3064
3191
  ```typescript
3065
- join(rightTable: SimpleTable, options?: { on?: string | string[]; type?: "inner" | "left" | "right" | "full"; outputTable?: string | boolean }): this;
3192
+ degree(sourceColumn: string, targetColumn: string, options?: { count?: "edges" | "neighbors"; weight?: string; outputTable?: string | boolean }): SimpleTable;
3066
3193
  ```
3067
3194
 
3068
3195
  ##### Parameters
3069
3196
 
3070
- - **`rightTable`**: The SimpleTable instance to be joined with this table.
3071
- - **`options`**: An optional object with configuration options:
3072
- - **`options.on`**: The column(s) to join on. If omitted, the method
3073
- automatically searches for a column name that exists in both tables. Can be a
3074
- single string or an array of strings for multiple join keys.
3075
- - **`options.type`**: The type of join operation to perform. Possible values are
3076
- `"inner"`, `"left"` (default), `"right"`, or `"full"`.
3077
- - **`options.outputTable`**: If `true`, the results will be stored in a new
3078
- table with a generated name. If a string, it will be used as the name for the
3079
- new table. If `false` or omitted, the current table will be overwritten.
3080
- Defaults to `false`.
3197
+ - **`sourceColumn`**: The name of the column containing each connection's source
3198
+ node ID.
3199
+ - **`targetColumn`**: The name of the column containing each connection's target
3200
+ node ID.
3201
+ - **`options`**: An optional object with counting and result configuration.
3202
+ - **`options.count`**: Whether to count connection rows (`"edges"`) or distinct
3203
+ adjacent nodes (`"neighbors"`). Defaults to `"edges"`.
3204
+ - **`options.weight`**: The name of the numeric edge-weight column to sum. This
3205
+ requires edge counting.
3206
+ - **`options.outputTable`**: If `true`, stores the result in a new table with a
3207
+ generated name. If a string, uses it as the new table's name. If `false` or
3208
+ omitted, overwrites the current table. Defaults to `false`.
3081
3209
 
3082
3210
  ##### Returns
3083
3211
 
3084
- A table instance containing the joined data (either the current table or a new
3085
- table), so methods can be chained.
3212
+ The result table, so methods can be chained.
3086
3213
 
3087
3214
  ##### Examples
3088
3215
 
3089
3216
  ```ts
3090
- // Perform a left join with 'tableB' on a common column (auto-detected), overwriting tableA
3091
- await tableA.join(tableB).log();
3217
+ await flights
3218
+ .degree("origin", "destination")
3219
+ .log();
3092
3220
  ```
3093
3221
 
3222
+ | node | incoming | outgoing | total |
3223
+ | --------- | -------: | -------: | ----: |
3224
+ | Montreal | 1 | 3 | 4 |
3225
+ | Toronto | 2 | 1 | 3 |
3226
+ | Vancouver | 1 | 0 | 1 |
3227
+
3228
+ With `count: "neighbors"`, the two Montreal-to-Toronto flights count as one
3229
+ outgoing neighbor for Montreal:
3230
+
3094
3231
  ```ts
3095
- // Perform an inner join with 'tableB' on the 'id' column, storing results in a new table named 'tableC'
3096
- const tableC = await tableA.join(tableB, {
3097
- on: "id",
3098
- type: "inner",
3099
- outputTable: "tableC",
3100
- }).log();
3232
+ await flights
3233
+ .degree("origin", "destination", { count: "neighbors" })
3234
+ .log();
3101
3235
  ```
3102
3236
 
3237
+ | node | incoming | outgoing | total |
3238
+ | --------- | -------: | -------: | ----: |
3239
+ | Montreal | 1 | 2 | 3 |
3240
+ | Toronto | 1 | 1 | 2 |
3241
+ | Vancouver | 1 | 0 | 1 |
3242
+
3243
+ With `weight: "passengers"`, the method adds passenger counts for each city's
3244
+ incoming and outgoing flights:
3245
+
3103
3246
  ```ts
3104
- // Perform a join on multiple columns ('name' and 'category')
3105
- await tableA.join(tableB, { on: ["name", "category"] }).log();
3247
+ await flights
3248
+ .degree("origin", "destination", { weight: "passengers" })
3249
+ .log();
3106
3250
  ```
3107
3251
 
3108
- #### `fuzzyJoin`
3252
+ | node | incoming | outgoing | total |
3253
+ | --------- | -------: | -------: | ----: |
3254
+ | Montreal | 150 | 350 | 500 |
3255
+ | Toronto | 300 | 150 | 450 |
3256
+ | Vancouver | 50 | 0 | 50 |
3109
3257
 
3110
- Performs a fuzzy left join between this table (considered the left table) and
3111
- another table (the right table) based on string similarity between two text
3112
- columns. Uses the [rapidfuzz](https://query.farm/duckdb_extension_rapidfuzz)
3113
- DuckDB community extension.
3258
+ A self-connection is counted once in each direction. For this input:
3114
3259
 
3115
- If a similarity score column is added to the results, the rows will be ordered
3116
- alphabetically by the left column, and then by descending similarity score
3117
- within each group of identical left column values. Otherwise, the rows will be
3118
- order alphabetically by the left column and then by the right column.
3260
+ | source | target |
3261
+ | ------ | ------ |
3262
+ | A | A |
3263
+ | A | B |
3119
3264
 
3120
- This operation might create temporary files in a `.tmp` folder; consider adding
3121
- `.tmp` to your `.gitignore`.
3265
+ ```ts
3266
+ await connections
3267
+ .degree("source", "target")
3268
+ .log();
3269
+ ```
3270
+
3271
+ | node | incoming | outgoing | total |
3272
+ | ---- | -------: | -------: | ----: |
3273
+ | A | 1 | 2 | 3 |
3274
+ | B | 1 | 0 | 1 |
3275
+
3276
+ #### `commonNeighbors`
3277
+
3278
+ Finds the neighbors shared by two different nodes. The `direction` option lets
3279
+ you find neighbors from source to target, from target to source, or in either
3280
+ direction. The result has one `node` column, sorted in ascending order.
3281
+
3282
+ If either node ID is unknown, or the nodes have no shared neighbors, the result
3283
+ has no rows. Each shared neighbor appears once, even if connections are
3284
+ repeated. A self-connection can make one of the requested nodes a shared
3285
+ neighbor. Using the same ID for both requested nodes throws an error.
3286
+
3287
+ The next three examples each start with this data:
3288
+
3289
+ | origin | destination |
3290
+ | ------ | ----------- |
3291
+ | A | C |
3292
+ | A | C |
3293
+ | B | C |
3294
+ | B | C |
3295
+ | D | A |
3296
+ | D | B |
3297
+
3298
+ By default, the method finds shared neighbors from source to target. Both A and
3299
+ B connect to C:
3122
3300
 
3123
3301
  ##### Signature
3124
3302
 
3125
3303
  ```typescript
3126
- fuzzyJoin(rightTable: SimpleTable, leftColumn: string, rightColumn: string, threshold: number, options?: { method?: "ratio" | "partial_ratio" | "token_sort_ratio" | "token_set_ratio"; similarityColumn?: string; outputTable?: string | boolean; prefilterPrefixLength?: number }): this;
3304
+ commonNeighbors(sourceColumn: string, targetColumn: string, nodeA: string | number | bigint, nodeB: string | number | bigint, options?: { direction?: "outgoing" | "incoming" | "both"; outputTable?: string | boolean }): SimpleTable;
3127
3305
  ```
3128
3306
 
3129
3307
  ##### Parameters
3130
3308
 
3131
- - **`rightTable`**: The SimpleTable instance to be joined with this table.
3132
- - **`leftColumn`**: The name of the column in this (left) table containing the
3133
- text to compare.
3134
- - **`rightColumn`**: The name of the column in the right table containing the
3135
- text to compare.
3136
- - **`threshold`**: The minimum similarity score (0–100) required for two rows to
3137
- be joined. For `method: "ratio"`, a length-based pre-filter is automatically
3138
- applied based on the threshold to improve performance without losing accuracy.
3139
- - **`options`**: An optional object with configuration options:
3140
- - **`options.method`**: The rapidfuzz similarity algorithm to use. Defaults to
3141
- `"ratio"`. - `"ratio"`: Overall similarity (Levenshtein-based). -
3142
- `"partial_ratio"`: Best partial/substring similarity. - `"token_sort_ratio"`:
3143
- Similarity after sorting tokens (words), useful for reordered words. -
3144
- `"token_set_ratio"`: Similarity based on sets of tokens, ignoring duplicates
3145
- and word order.
3146
- - **`options.similarityColumn`**: If provided, a column with this name is added
3147
- to the result containing the similarity score (0–100). If omitted, the score
3148
- is not included in the output.
3149
- - **`options.outputTable`**: If `true`, the results will be stored in a new
3150
- table with a generated name. If a string, it will be used as the name for the
3151
- new table. If `false` or omitted, the current table will be overwritten.
3152
- Defaults to `false`.
3153
- - **`options.prefilterPrefixLength`**: An optional prefix length. Only strings
3154
- sharing the same first N characters are compared. Note that prefix filtering
3155
- is lossy (e.g. "John" vs. "Phon" will not match despite high similarity).
3309
+ - **`sourceColumn`**: The name of the column containing each connection's source
3310
+ node ID.
3311
+ - **`targetColumn`**: The name of the column containing each connection's target
3312
+ node ID.
3313
+ - **`nodeA`**: The first node ID.
3314
+ - **`nodeB`**: The second node ID, which must differ from `nodeA`.
3315
+ - **`options`**: An optional object with direction and result configuration.
3316
+ - **`options.direction`**: The direction in which to follow connections.
3317
+ Defaults to `"outgoing"`.
3318
+ - **`options.outputTable`**: If `true`, stores the result in a new table with a
3319
+ generated name. If a string, uses it as the new table's name. If `false` or
3320
+ omitted, overwrites the current table. Defaults to `false`.
3156
3321
 
3157
3322
  ##### Returns
3158
3323
 
3159
- A table instance containing the fuzzy-joined data (either the current table or a
3160
- new table), so methods can be chained.
3324
+ The result table, so methods can be chained.
3161
3325
 
3162
3326
  ##### Examples
3163
3327
 
3164
3328
  ```ts
3165
- // Fuzzy left join tableA with tableB on 'name' (left) and 'standardName' (right) with a threshold of 80
3166
- // A length-based pre-filter is automatically applied.
3167
- await tableA.fuzzyJoin(tableB, "name", "standardName", 80).log();
3329
+ await connections
3330
+ .commonNeighbors("origin", "destination", "A", "B")
3331
+ .log();
3168
3332
  ```
3169
3333
 
3334
+ | node |
3335
+ | ---- |
3336
+ | C |
3337
+
3338
+ C appears only once, even though the input repeats the connections.
3339
+
3340
+ With `direction: "incoming"`, the method follows connections from target to
3341
+ source. D connects to both A and B:
3342
+
3170
3343
  ```ts
3171
- // Fuzzy join with a prefix-based pre-filter and a threshold of 80
3172
- await tableA.fuzzyJoin(tableB, "name", "standardName", 80, {
3173
- prefilterPrefixLength: 3, // Must share the same first 3 characters
3174
- }).log();
3344
+ await connections
3345
+ .commonNeighbors("origin", "destination", "A", "B", { direction: "incoming" })
3346
+ .log();
3175
3347
  ```
3176
3348
 
3349
+ | node |
3350
+ | ---- |
3351
+ | D |
3352
+
3353
+ With `direction: "both"`, the method finds shared neighbors in either direction:
3354
+
3177
3355
  ```ts
3178
- // Fuzzy join with a custom threshold and method, storing results in a new table
3179
- const tableC = await tableA.fuzzyJoin(tableB, "name", "standardName", 90, {
3180
- method: "token_sort_ratio",
3181
- outputTable: "tableC",
3182
- }).log();
3356
+ await connections
3357
+ .commonNeighbors("origin", "destination", "A", "B", { direction: "both" })
3358
+ .log();
3183
3359
  ```
3184
3360
 
3361
+ | node |
3362
+ | ---- |
3363
+ | C |
3364
+ | D |
3365
+
3366
+ A self-connection can make a requested node a shared neighbor. For this input, A
3367
+ is a neighbor of both itself and B:
3368
+
3369
+ | source | target |
3370
+ | ------ | ------ |
3371
+ | A | A |
3372
+ | B | A |
3373
+
3185
3374
  ```ts
3186
- // Fuzzy join with a custom similarity column name and a threshold of 80
3187
- await tableA.fuzzyJoin(tableB, "name", "standardName", 80, {
3188
- similarityColumn: "matchScore",
3189
- }).log();
3375
+ await connections
3376
+ .commonNeighbors("source", "target", "A", "B")
3377
+ .log();
3190
3378
  ```
3191
3379
 
3192
- #### `fuzzyClean`
3380
+ | node |
3381
+ | ---- |
3382
+ | A |
3193
3383
 
3194
- Normalizes string values in a column by detecting fuzzy duplicates and replacing
3195
- them with a single canonical value.
3384
+ #### `reachable`
3196
3385
 
3197
- Similar strings are grouped into clusters. Matching is transitive: if
3198
- `"New York"` is similar to `"New Yorke"` and `"New Yorke"` is similar to
3199
- `"New Yorkk"`, all three land in the same cluster even if `"New York"` and
3200
- `"New Yorkk"` would not match directly. Each cluster is then collapsed to one
3201
- representative value based on the `strategy` option.
3386
+ Finds all nodes you can reach from one or more starting nodes, following one or
3387
+ more connections. The `direction` option lets you follow connections from source
3388
+ to target, from target to source, or in either direction. The result has `start`
3389
+ and `node` columns, sorted by `start`, then `node`.
3202
3390
 
3203
- Similarity is computed using the
3204
- [rapidfuzz](https://query.farm/duckdb_extension_rapidfuzz) DuckDB community
3205
- extension, which is installed and loaded automatically.
3391
+ A starting node appears in its own results only if following connections leads
3392
+ back to it, such as a self-connection or a cycle. Each reachable node appears
3393
+ only once per start. With `direction: "both"`, following the same connection out
3394
+ and back also reaches the starting node.
3395
+
3396
+ Unknown starting IDs and starts with no connections to follow produce no rows.
3397
+ Empty start arrays and duplicate starting IDs throw an error.
3398
+
3399
+ Use the `startTimeColumn` or `endTimeColumn` options to follow connections in
3400
+ chronological order. The `minGapMs` option sets the minimum gap between
3401
+ consecutive connections, in milliseconds. With both time columns, gaps are
3402
+ measured from one connection's end to the next connection's start; with one
3403
+ column, between their timestamps. The `strictOrdering` option defaults to
3404
+ `true`, rejecting zero-duration gaps. These options only work with
3405
+ `direction: "outgoing"` or `direction: "incoming"`.
3406
+
3407
+ The next four examples each start with this data:
3408
+
3409
+ | origin | destination |
3410
+ | ------ | ----------- |
3411
+ | A | B |
3412
+ | A | C |
3413
+ | B | D |
3414
+ | C | D |
3415
+ | D | A |
3416
+
3417
+ By default, the method follows connections from source to target. A appears in
3418
+ its own results because A → B → D → A leads back to it:
3206
3419
 
3207
3420
  ##### Signature
3208
3421
 
3209
3422
  ```typescript
3210
- fuzzyClean(column: string, newColumn: string, threshold: number, options?: { method?: "ratio" | "partial_ratio" | "token_sort_ratio" | "token_set_ratio"; strategy?: "mostCommon" | "longestString" | "shortestString" | "mostCentral" | "maxScore"; prefilterPrefixLength?: number }): this;
3423
+ reachable(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 }): SimpleTable;
3211
3424
  ```
3212
3425
 
3213
3426
  ##### Parameters
3214
3427
 
3215
- - **`column`**: The name of the column containing the strings to normalize.
3216
- - **`newColumn`**: The name of the column to write the normalized values to. Use
3217
- the same name as `column` to normalize in-place.
3428
+ - **`sourceColumn`**: The name of the column containing each connection's source
3429
+ node ID.
3430
+ - **`targetColumn`**: The name of the column containing each connection's target
3431
+ node ID.
3432
+ - **`startNodes`**: One starting node ID or an array of distinct starting node
3433
+ IDs.
3434
+ - **`options`**: An optional object with direction, time, and result
3435
+ configuration.
3436
+ - **`options.direction`**: The direction in which to follow connections.
3437
+ Defaults to `"outgoing"`.
3438
+ - **`options.startTimeColumn`**: The name of the column containing each
3439
+ connection's start time. Use this or `endTimeColumn` to follow connections in
3440
+ chronological order.
3441
+ - **`options.endTimeColumn`**: The name of the column containing each
3442
+ connection's end time. Use this or `startTimeColumn` to follow connections in
3443
+ chronological order.
3444
+ - **`options.minGapMs`**: The minimum gap between consecutive connections, in
3445
+ milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time
3446
+ column.
3447
+ - **`options.strictOrdering`**: Whether to reject zero-duration gaps between
3448
+ consecutive connections (equal timestamps). Defaults to `true`. Requires a
3449
+ time column.
3450
+ - **`options.outputTable`**: If `true`, stores the result in a new table with a
3451
+ generated name. If a string, uses it as the new table's name. If `false` or
3452
+ omitted, overwrites the current table. Defaults to `false`.
3453
+
3454
+ ##### Returns
3455
+
3456
+ The result table, so methods can be chained.
3457
+
3458
+ ##### Examples
3459
+
3460
+ ```ts
3461
+ await connections
3462
+ .reachable("origin", "destination", "A")
3463
+ .log();
3464
+ ```
3465
+
3466
+ | start | node |
3467
+ | ----- | ---- |
3468
+ | A | A |
3469
+ | A | B |
3470
+ | A | C |
3471
+ | A | D |
3472
+
3473
+ With `direction: "incoming"`, connections are followed from target to source.
3474
+ Starting at B:
3475
+
3476
+ ```ts
3477
+ await connections
3478
+ .reachable("origin", "destination", "B", { direction: "incoming" })
3479
+ .log();
3480
+ ```
3481
+
3482
+ | start | node |
3483
+ | ----- | ---- |
3484
+ | B | A |
3485
+ | B | B |
3486
+ | B | C |
3487
+ | B | D |
3488
+
3489
+ With `direction: "both"`, connections can be followed in either direction:
3490
+
3491
+ ```ts
3492
+ await connections
3493
+ .reachable("origin", "destination", "B", { direction: "both" })
3494
+ .log();
3495
+ ```
3496
+
3497
+ | start | node |
3498
+ | ----- | ---- |
3499
+ | B | A |
3500
+ | B | B |
3501
+ | B | C |
3502
+ | B | D |
3503
+
3504
+ With multiple starting nodes, each has its own results:
3505
+
3506
+ ```ts
3507
+ await connections
3508
+ .reachable("origin", "destination", ["B", "A"])
3509
+ .log();
3510
+ ```
3511
+
3512
+ | start | node |
3513
+ | ----- | ---- |
3514
+ | A | A |
3515
+ | A | B |
3516
+ | A | C |
3517
+ | A | D |
3518
+ | B | A |
3519
+ | B | B |
3520
+ | B | C |
3521
+ | B | D |
3522
+
3523
+ Chronological options retain only journeys with valid connection times. Here, A
3524
+ → B arrives at 10:00, so the 09:00 connection to C is unavailable, while the
3525
+ 11:00 connection to D meets the one-hour minimum gap:
3526
+
3527
+ | origin | destination | departureTime | arrivalTime |
3528
+ | ------ | ----------- | ---------------- | ---------------- |
3529
+ | A | B | 2025-01-01 08:00 | 2025-01-01 10:00 |
3530
+ | B | C | 2025-01-01 09:00 | 2025-01-01 10:00 |
3531
+ | B | D | 2025-01-01 11:00 | 2025-01-01 12:00 |
3532
+
3533
+ The departure and arrival columns are timestamps:
3534
+
3535
+ ```ts
3536
+ await flights
3537
+ .reachable("origin", "destination", "A", {
3538
+ startTimeColumn: "departureTime",
3539
+ endTimeColumn: "arrivalTime",
3540
+ minGapMs: 60 * 60 * 1000,
3541
+ })
3542
+ .log();
3543
+ ```
3544
+
3545
+ | start | node |
3546
+ | ----- | ---- |
3547
+ | A | B |
3548
+ | A | D |
3549
+
3550
+ #### `connectedComponents`
3551
+
3552
+ Groups nodes that are connected to one another, directly or through other nodes.
3553
+ By default, connection direction is ignored. With the `mode` option set to
3554
+ "strong", nodes belong to the same group only if each can reach all the others
3555
+ by following connections from source to target.
3556
+
3557
+ The result has `componentId` and `node` columns. Without `startTimeColumn` or
3558
+ `endTimeColumn`, each node appears once, and rows are sorted by node. Groups are
3559
+ numbered from zero in order of their smallest node ID.
3560
+
3561
+ Use the `startTimeColumn` or `endTimeColumn` options to follow connections in
3562
+ chronological order. The `minGapMs` option sets the minimum gap between
3563
+ consecutive connections, in milliseconds. With both time columns, gaps are
3564
+ measured from one connection's end to the next connection's start; with one
3565
+ column, between their timestamps. The `strictOrdering` option defaults to
3566
+ `true`, rejecting zero-duration gaps. These options require an explicitly
3567
+ supplied `mode: "strong"`.
3568
+
3569
+ With these options, nodes are grouped when each can reach all the others in
3570
+ chronological order. Groups can overlap, so a node may appear in several rows
3571
+ with different `componentId` values.
3572
+
3573
+ For the first example, we start with this data:
3574
+
3575
+ | origin | destination |
3576
+ | ------ | ----------- |
3577
+ | A | B |
3578
+ | C | D |
3579
+
3580
+ By default, the method groups connected nodes without considering direction. B
3581
+ and D are included even though they only appear as destinations:
3582
+
3583
+ ##### Signature
3584
+
3585
+ ```typescript
3586
+ connectedComponents(sourceColumn: string, targetColumn: string, options?: { endTimeColumn?: string; minGapMs?: number; mode?: "weak" | "strong"; outputTable?: string | boolean; startTimeColumn?: string; strictOrdering?: boolean }): SimpleTable;
3587
+ ```
3588
+
3589
+ ##### Parameters
3590
+
3591
+ - **`sourceColumn`**: The name of the column containing each connection's source
3592
+ node ID.
3593
+ - **`targetColumn`**: The name of the column containing each connection's target
3594
+ node ID.
3595
+ - **`options`**: An optional object with component, time, and result
3596
+ configuration.
3597
+ - **`options.mode`**: Whether to find `"weak"` or `"strong"` components.
3598
+ Defaults to `"weak"`. Using `startTimeColumn` or `endTimeColumn` requires
3599
+ explicitly setting `mode: "strong"`.
3600
+ - **`options.startTimeColumn`**: The name of the column containing each
3601
+ connection's start time. Use this or `endTimeColumn` to follow connections in
3602
+ chronological order.
3603
+ - **`options.endTimeColumn`**: The name of the column containing each
3604
+ connection's end time. Use this or `startTimeColumn` to follow connections in
3605
+ chronological order.
3606
+ - **`options.minGapMs`**: The minimum gap between consecutive connections, in
3607
+ milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time
3608
+ column.
3609
+ - **`options.strictOrdering`**: Whether to reject zero-duration gaps between
3610
+ consecutive connections (equal timestamps). Defaults to `true`. Requires a
3611
+ time column.
3612
+ - **`options.outputTable`**: If `true`, stores the result in a new table with a
3613
+ generated name. If a string, uses it as the new table's name. If `false` or
3614
+ omitted, overwrites the current table. Defaults to `false`.
3615
+
3616
+ ##### Returns
3617
+
3618
+ The result table, so methods can be chained.
3619
+
3620
+ ##### Examples
3621
+
3622
+ ```ts
3623
+ await table
3624
+ .connectedComponents("origin", "destination")
3625
+ .log();
3626
+ ```
3627
+
3628
+ | componentId | node |
3629
+ | ----------: | ---- |
3630
+ | 0 | A |
3631
+ | 0 | B |
3632
+ | 1 | C |
3633
+ | 1 | D |
3634
+
3635
+ The next two examples each start with this chain of connections:
3636
+
3637
+ | source | target |
3638
+ | ------ | ------ |
3639
+ | A | B |
3640
+ | B | C |
3641
+
3642
+ By default, all three nodes belong to the same group:
3643
+
3644
+ ```ts
3645
+ await graph
3646
+ .connectedComponents("source", "target")
3647
+ .log();
3648
+ ```
3649
+
3650
+ | componentId | node |
3651
+ | ----------: | ---- |
3652
+ | 0 | A |
3653
+ | 0 | B |
3654
+ | 0 | C |
3655
+
3656
+ With the `mode` option set to "strong", each node forms its own group. A can
3657
+ reach B and C, but neither can get back to A:
3658
+
3659
+ ```ts
3660
+ await graph
3661
+ .connectedComponents("source", "target", {
3662
+ mode: "strong",
3663
+ })
3664
+ .log();
3665
+ ```
3666
+
3667
+ | componentId | node |
3668
+ | ----------: | ---- |
3669
+ | 0 | A |
3670
+ | 1 | B |
3671
+ | 2 | C |
3672
+
3673
+ Adding C -> A would let every node reach the others, so all three would belong
3674
+ to the same group in "strong" mode too.
3675
+
3676
+ Chronological strong groups can overlap. The next example uses one instantaneous
3677
+ timestamp column:
3678
+
3679
+ | time | source | target |
3680
+ | ---------------- | ------ | ------ |
3681
+ | 2025-01-01 08:00 | B | C |
3682
+ | 2025-01-01 09:00 | C | B |
3683
+ | 2025-01-01 10:00 | A | B |
3684
+ | 2025-01-01 11:00 | B | A |
3685
+
3686
+ A and B can reach each other, as can B and C, but A cannot reach C after its
3687
+ first event. This produces the maximal groups `{A, B}` and `{B, C}`:
3688
+
3689
+ ```ts
3690
+ await transactions
3691
+ .connectedComponents("source", "target", {
3692
+ mode: "strong",
3693
+ startTimeColumn: "time",
3694
+ })
3695
+ .log();
3696
+ ```
3697
+
3698
+ | componentId | node |
3699
+ | ----------: | ---- |
3700
+ | 0 | A |
3701
+ | 0 | B |
3702
+ | 1 | B |
3703
+ | 1 | C |
3704
+
3705
+ #### `topologicalSort`
3706
+
3707
+ Orders nodes so each prerequisite comes before the nodes that depend on it. Each
3708
+ input row means the source node must come before the target node. For example, A
3709
+ → B means A must come before B.
3710
+
3711
+ The result has `node`, `componentId`, and `order` columns, sorted by
3712
+ `componentId`, then `order`. Nodes connected directly or through other nodes
3713
+ belong to the same group, ignoring connection direction. Groups are numbered
3714
+ from zero, with the group containing the smallest node ID first.
3715
+
3716
+ Within each group, `order` starts at one. When several nodes are ready, the
3717
+ method chooses the smallest node ID first: numeric order for numbers and
3718
+ character order for strings. All nodes in the source and target columns are
3719
+ included.
3720
+
3721
+ If dependencies form a loop, there is no valid order and the method throws an
3722
+ error. A node depending on itself also causes an error. An empty input produces
3723
+ no rows.
3724
+
3725
+ For this example, we start with these connections:
3726
+
3727
+ | source | target |
3728
+ | ------ | ------ |
3729
+ | A | B |
3730
+ | B | C |
3731
+ | D | C |
3732
+
3733
+ A must come before B, and both B and D must come before C:
3734
+
3735
+ ##### Signature
3736
+
3737
+ ```typescript
3738
+ topologicalSort(sourceColumn: string, targetColumn: string, options?: { outputTable?: string | boolean }): SimpleTable;
3739
+ ```
3740
+
3741
+ ##### Parameters
3742
+
3743
+ - **`sourceColumn`**: The name of the column containing each prerequisite node
3744
+ ID.
3745
+ - **`targetColumn`**: The name of the column containing each dependent node ID.
3746
+ - **`options`**: An optional object with result configuration.
3747
+ - **`options.outputTable`**: If `true`, stores the result in a new table with a
3748
+ generated name. If a string, uses it as the new table's name. If `false` or
3749
+ omitted, overwrites the current table. Defaults to `false`.
3750
+
3751
+ ##### Returns
3752
+
3753
+ The result table, so methods can be chained.
3754
+
3755
+ ##### Examples
3756
+
3757
+ ```ts
3758
+ await table
3759
+ .topologicalSort("source", "target")
3760
+ .log();
3761
+ ```
3762
+
3763
+ | node | componentId | order |
3764
+ | ---- | ----------: | ----: |
3765
+ | A | 0 | 1 |
3766
+ | B | 0 | 2 |
3767
+ | D | 0 | 3 |
3768
+ | C | 0 | 4 |
3769
+
3770
+ C comes last because it depends on both B and D. A comes before D because both
3771
+ are initially ready and A has the smaller ID. After A, B is ready and comes
3772
+ before D for the same reason.
3773
+
3774
+ With two independent groups, each has its own order starting at one. This
3775
+ example starts with different data:
3776
+
3777
+ | source | target |
3778
+ | ------ | ------ |
3779
+ | A | D |
3780
+ | B | C |
3781
+
3782
+ ```ts
3783
+ await table
3784
+ .topologicalSort("source", "target")
3785
+ .log();
3786
+ ```
3787
+
3788
+ | node | componentId | order |
3789
+ | ---- | ----------: | ----: |
3790
+ | A | 0 | 1 |
3791
+ | D | 0 | 2 |
3792
+ | B | 1 | 1 |
3793
+ | C | 1 | 2 |
3794
+
3795
+ #### `distances`
3796
+
3797
+ Finds the shortest distance from each starting node to every node it can reach
3798
+ by following one or more connections. By default, distance is the number of
3799
+ connections along the shortest route. Use the `weight` option to find the
3800
+ smallest sum of values from a numeric column, such as travel time.
3801
+
3802
+ The `direction` option lets you follow connections from source to target, from
3803
+ target to source, or in either direction. The result has `start`, `node`, and
3804
+ `distance` columns, sorted by `start`, then by increasing `distance`, then by
3805
+ `node` to break ties. The closest nodes appear first for each start.
3806
+
3807
+ Each row gives the shortest distance from `start` to `node`. Intermediate steps
3808
+ along the route are not returned. To get the steps between two different nodes,
3809
+ use `shortestPath()` for the shortest routes or `paths()` for all routes without
3810
+ repeated nodes.
3811
+
3812
+ A starting node appears in its own results only when a self-connection or a
3813
+ route leads back to it. Its distance is the shortest actual return route, using
3814
+ at least one connection. With `direction: "both"`, this can mean following the
3815
+ same connection out and back.
3816
+
3817
+ Unknown starting IDs and starts with no connections to follow produce no rows.
3818
+ Empty start arrays and duplicate starting IDs throw an error. Weights must be
3819
+ non-null, finite, and non-negative.
3820
+
3821
+ Use the `startTimeColumn` or `endTimeColumn` options to follow connections in
3822
+ chronological order. The `minGapMs` option sets the minimum gap between
3823
+ consecutive connections, in milliseconds. With both time columns, gaps are
3824
+ measured from one connection's end to the next connection's start; with one
3825
+ column, between their timestamps. The `strictOrdering` option defaults to
3826
+ `true`, rejecting zero-duration gaps. These options only work with
3827
+ `direction: "outgoing"` or `direction: "incoming"`.
3828
+
3829
+ The minimum gap applies only between consecutive connections, not before the
3830
+ first connection.
3831
+
3832
+ The next five examples each start with this data:
3833
+
3834
+ | origin | destination | minutes |
3835
+ | ------ | ----------- | ------: |
3836
+ | A | B | 4 |
3837
+ | B | C | 1 |
3838
+ | D | B | 2 |
3839
+
3840
+ By default, the method follows connections from source to target and counts how
3841
+ many connections are needed:
3842
+
3843
+ ##### Signature
3844
+
3845
+ ```typescript
3846
+ 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
+ ```
3848
+
3849
+ ##### Parameters
3850
+
3851
+ - **`sourceColumn`**: The name of the column containing each connection's source
3852
+ node ID.
3853
+ - **`targetColumn`**: The name of the column containing each connection's target
3854
+ node ID.
3855
+ - **`startNodes`**: One starting node ID or an array of distinct starting node
3856
+ IDs.
3857
+ - **`options`**: An optional object with direction, time, and result
3858
+ configuration.
3859
+ - **`options.direction`**: The direction in which to follow connections.
3860
+ Defaults to `"outgoing"`.
3861
+ - **`options.startTimeColumn`**: The name of the column containing each
3862
+ connection's start time. Use this or `endTimeColumn` to follow connections in
3863
+ chronological order.
3864
+ - **`options.endTimeColumn`**: The name of the column containing each
3865
+ connection's end time. Use this or `startTimeColumn` to follow connections in
3866
+ chronological order.
3867
+ - **`options.minGapMs`**: The minimum gap between consecutive connections, in
3868
+ milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time
3869
+ column.
3870
+ - **`options.strictOrdering`**: Whether to reject zero-duration gaps between
3871
+ consecutive connections (equal timestamps). Defaults to `true`. Requires a
3872
+ time column.
3873
+ - **`options.weight`**: The name of the numeric column used as the cost of each
3874
+ connection. If omitted, each connection costs one.
3875
+ - **`options.outputTable`**: If `true`, stores the result in a new table with a
3876
+ generated name. If a string, uses it as the new table's name. If `false` or
3877
+ omitted, overwrites the current table. Defaults to `false`.
3878
+
3879
+ ##### Returns
3880
+
3881
+ The result table, so methods can be chained.
3882
+
3883
+ ##### Examples
3884
+
3885
+ ```ts
3886
+ await connections
3887
+ .distances("origin", "destination", "A")
3888
+ .log();
3889
+ ```
3890
+
3891
+ | start | node | distance |
3892
+ | ----- | ---- | -------: |
3893
+ | A | B | 1 |
3894
+ | A | C | 2 |
3895
+
3896
+ With `weight: "minutes"`, distance is the shortest total travel time:
3897
+
3898
+ ```ts
3899
+ await connections
3900
+ .distances("origin", "destination", "A", { weight: "minutes" })
3901
+ .log();
3902
+ ```
3903
+
3904
+ | start | node | distance |
3905
+ | ----- | ---- | -------: |
3906
+ | A | B | 4 |
3907
+ | A | C | 5 |
3908
+
3909
+ With `direction: "incoming"`, connections are followed from target to source.
3910
+ Starting at C:
3911
+
3912
+ ```ts
3913
+ await connections
3914
+ .distances("origin", "destination", "C", { direction: "incoming" })
3915
+ .log();
3916
+ ```
3917
+
3918
+ | start | node | distance |
3919
+ | ----- | ---- | -------: |
3920
+ | C | B | 1 |
3921
+ | C | A | 2 |
3922
+ | C | D | 2 |
3923
+
3924
+ With `direction: "both"`, connections can be followed in either direction:
3925
+
3926
+ ```ts
3927
+ await connections
3928
+ .distances("origin", "destination", "A", { direction: "both" })
3929
+ .log();
3930
+ ```
3931
+
3932
+ | start | node | distance |
3933
+ | ----- | ---- | -------: |
3934
+ | A | B | 1 |
3935
+ | A | A | 2 |
3936
+ | A | C | 2 |
3937
+ | A | D | 2 |
3938
+
3939
+ A appears at distance 2 because A → B → A follows a connection out and back.
3940
+
3941
+ An array of starting nodes gives separate distances for each start:
3942
+
3943
+ ```ts
3944
+ await connections
3945
+ .distances("origin", "destination", ["D", "A"], {
3946
+ weight: "minutes",
3947
+ })
3948
+ .log();
3949
+ ```
3950
+
3951
+ | start | node | distance |
3952
+ | ----- | ---- | -------: |
3953
+ | A | B | 4 |
3954
+ | A | C | 5 |
3955
+ | D | B | 2 |
3956
+ | D | C | 3 |
3957
+
3958
+ A direct self-connection and a longer return route can both lead back to the
3959
+ start. This example uses different data:
3960
+
3961
+ | origin | destination | minutes |
3962
+ | ------ | ----------- | ------: |
3963
+ | A | A | 10 |
3964
+ | A | B | 2 |
3965
+ | B | A | 3 |
3966
+
3967
+ The shortest return to A takes 5 minutes through B, compared with 10 minutes for
3968
+ the direct self-connection:
3969
+
3970
+ ```ts
3971
+ await connections
3972
+ .distances("origin", "destination", "A", { weight: "minutes" })
3973
+ .log();
3974
+ ```
3975
+
3976
+ | start | node | distance |
3977
+ | ----- | ---- | -------: |
3978
+ | A | B | 2 |
3979
+ | A | A | 5 |
3980
+
3981
+ Chronological options can rule out a cheaper sequence that departs too early.
3982
+ For this example, F2 leaves before F1 arrives, while F3 meets the one-hour
3983
+ minimum exactly:
3984
+
3985
+ | origin | destination | departureTime | arrivalTime | minutes |
3986
+ | ------ | ----------- | ---------------- | ---------------- | ------: |
3987
+ | A | B | 2025-01-01 08:00 | 2025-01-01 10:00 | 2 |
3988
+ | B | C | 2025-01-01 09:00 | 2025-01-01 10:00 | 1 |
3989
+ | B | D | 2025-01-01 11:00 | 2025-01-01 12:00 | 3 |
3990
+
3991
+ ```ts
3992
+ await scheduledFlights
3993
+ .distances("origin", "destination", "A", {
3994
+ startTimeColumn: "departureTime",
3995
+ endTimeColumn: "arrivalTime",
3996
+ minGapMs: 60 * 60 * 1000,
3997
+ weight: "minutes",
3998
+ })
3999
+ .log();
4000
+ ```
4001
+
4002
+ | start | node | distance |
4003
+ | ----- | ---- | -------: |
4004
+ | A | B | 2 |
4005
+ | A | D | 5 |
4006
+
4007
+ #### `shortestPath`
4008
+
4009
+ Finds the shortest route between two different nodes. If several routes tie for
4010
+ shortest, all of them are returned. By default, the shortest route uses the
4011
+ fewest connections. Use the `weight` option to find the route with the smallest
4012
+ sum of values from a numeric column, such as travel time. A route cannot visit
4013
+ the same node twice, to avoid loops. Different routes can still share the same
4014
+ nodes.
4015
+
4016
+ The `direction` option lets you follow connections from source to target, from
4017
+ target to source, or in either direction.
4018
+
4019
+ Each connection needs a unique, non-null ID. Pass the name of the column
4020
+ containing these IDs as the `edgeId` argument. If your table is missing an ID
4021
+ column, you can easily create one with `addId()`.
4022
+
4023
+ The result starts with the `pathId`, `step`, `weight`, and `total` columns,
4024
+ followed by all original columns. Steps start at one and follow the search
4025
+ direction. The `weight` column is the connection cost, and `total` is the sum of
4026
+ those costs up to and including the current step. Without the `weight` option,
4027
+ each connection costs one.
4028
+
4029
+ If an input column is already named `pathId`, `step`, `weight`, or `total`
4030
+ (regardless of capitalization), the method throws an error. Rename it with
4031
+ `renameColumns()` first.
4032
+
4033
+ Each row is one connection along a route.
4034
+
4035
+ Use the `startTimeColumn` or `endTimeColumn` options to follow connections in
4036
+ chronological order. The `minGapMs` option sets the minimum gap between
4037
+ consecutive connections, in milliseconds. With both time columns, gaps are
4038
+ measured from one connection's end to the next connection's start; with one
4039
+ column, between their timestamps. The `strictOrdering` option defaults to
4040
+ `true`, rejecting zero-duration gaps. These options only work with
4041
+ `direction: "outgoing"` or `direction: "incoming"`.
4042
+
4043
+ The minimum gap applies only between consecutive connections, not before the
4044
+ first connection.
4045
+
4046
+ Routes are numbered from zero by comparing their sequences of connection IDs,
4047
+ element by element. Rows are sorted by `pathId`, then `step`.
4048
+
4049
+ Unknown IDs or nodes with no route between them produce no rows. The start and
4050
+ end must differ. Self-connections are ignored. Weights must be non-null, finite,
4051
+ and non-negative.
4052
+
4053
+ There is no limit on route length or the number of tied routes returned. Finding
4054
+ many tied routes can take a long time and use substantial memory.
4055
+
4056
+ The first example uses this table:
4057
+
4058
+ | edgeId | source | target |
4059
+ | ------ | ------ | ------ |
4060
+ | E1 | A | B |
4061
+ | E2 | A | C |
4062
+ | E3 | B | D |
4063
+ | E4 | C | D |
4064
+ | E5 | D | E |
4065
+
4066
+ By default, the method finds routes from source to target with the fewest
4067
+ connections. Two routes from A to E tie at three connections each:
4068
+
4069
+ ##### Signature
4070
+
4071
+ ```typescript
4072
+ 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;
4073
+ ```
4074
+
4075
+ ##### Parameters
4076
+
4077
+ - **`sourceColumn`**: The name of the column containing each connection's source
4078
+ node ID.
4079
+ - **`targetColumn`**: The name of the column containing each connection's target
4080
+ node ID.
4081
+ - **`edgeId`**: The name of the column uniquely identifying each connection
4082
+ (edge).
4083
+ - **`start`**: The starting node ID.
4084
+ - **`end`**: The ending node ID, which must differ from `start`.
4085
+ - **`options`**: An optional object with direction, time, and result
4086
+ configuration.
4087
+ - **`options.direction`**: The direction in which to follow connections.
4088
+ Defaults to `"outgoing"`.
4089
+ - **`options.startTimeColumn`**: The name of the column containing each
4090
+ connection's start time. Use this or `endTimeColumn` to follow connections in
4091
+ chronological order.
4092
+ - **`options.endTimeColumn`**: The name of the column containing each
4093
+ connection's end time. Use this or `startTimeColumn` to follow connections in
4094
+ chronological order.
4095
+ - **`options.minGapMs`**: The minimum gap between consecutive connections, in
4096
+ milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time
4097
+ column.
4098
+ - **`options.strictOrdering`**: Whether to reject zero-duration gaps between
4099
+ consecutive connections (equal timestamps). Defaults to `true`. Requires a
4100
+ time column.
4101
+ - **`options.weight`**: The name of the numeric column used as the cost of each
4102
+ connection. If omitted, each connection costs one.
4103
+ - **`options.outputTable`**: If `true`, stores the result in a new table with a
4104
+ generated name. If a string, uses it as the new table's name. If `false` or
4105
+ omitted, overwrites the current table. Defaults to `false`.
4106
+
4107
+ ##### Returns
4108
+
4109
+ The result table, so methods can be chained.
4110
+
4111
+ ##### Examples
4112
+
4113
+ ```ts
4114
+ await connections
4115
+ .shortestPath("source", "target", "edgeId", "A", "E")
4116
+ .log();
4117
+ ```
4118
+
4119
+ | pathId | step | weight | total | edgeId | source | target |
4120
+ | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4121
+ | 0 | 1 | 1 | 1 | E1 | A | B |
4122
+ | 0 | 2 | 1 | 2 | E3 | B | D |
4123
+ | 0 | 3 | 1 | 3 | E5 | D | E |
4124
+ | 1 | 1 | 1 | 1 | E2 | A | C |
4125
+ | 1 | 2 | 1 | 2 | E4 | C | D |
4126
+ | 1 | 3 | 1 | 3 | E5 | D | E |
4127
+
4128
+ For an input without connection IDs, use `addId()` first:
4129
+
4130
+ | source | target |
4131
+ | ------ | ------ |
4132
+ | A | B |
4133
+ | B | E |
4134
+
4135
+ The generated IDs identify the connections in the result:
4136
+
4137
+ ```ts
4138
+ await unnumberedConnections
4139
+ .addId("edgeId", { prefix: "edge-" })
4140
+ .shortestPath("source", "target", "edgeId", "A", "E")
4141
+ .log();
4142
+ ```
4143
+
4144
+ | pathId | step | weight | total | source | target | edgeId |
4145
+ | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4146
+ | 0 | 1 | 1 | 1 | A | B | edge-0 |
4147
+ | 0 | 2 | 1 | 2 | B | E | edge-1 |
4148
+
4149
+ The next two examples each start with these flights. The direct flight takes ten
4150
+ minutes; the route through B and D takes three:
4151
+
4152
+ | flightId | origin | destination | minutes |
4153
+ | -------- | ------ | ----------- | ------: |
4154
+ | F1 | A | E | 10 |
4155
+ | F2 | A | B | 1 |
4156
+ | F3 | B | D | 1 |
4157
+ | F4 | D | E | 1 |
4158
+
4159
+ With `weight: "minutes"`, the route with the shortest travel time is chosen:
4160
+
4161
+ ```ts
4162
+ await flights
4163
+ .shortestPath("origin", "destination", "flightId", "A", "E", {
4164
+ weight: "minutes",
4165
+ })
4166
+ .log();
4167
+ ```
4168
+
4169
+ | pathId | step | weight | total | flightId | origin | destination | minutes |
4170
+ | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------: |
4171
+ | 0 | 1 | 1 | 1 | F2 | A | B | 1 |
4172
+ | 0 | 2 | 1 | 2 | F3 | B | D | 1 |
4173
+ | 0 | 3 | 1 | 3 | F4 | D | E | 1 |
4174
+
4175
+ Without the `weight` option, the direct flight is shortest because it uses only
4176
+ one connection:
4177
+
4178
+ ```ts
4179
+ await flights
4180
+ .shortestPath("origin", "destination", "flightId", "A", "E")
4181
+ .log();
4182
+ ```
4183
+
4184
+ | pathId | step | weight | total | flightId | origin | destination | minutes |
4185
+ | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------: |
4186
+ | 0 | 1 | 1 | 1 | F1 | A | E | 10 |
4187
+
4188
+ With time options, the cheaper route through B is ruled out because F2 leaves
4189
+ before F1 arrives. The route through C meets the one-hour minimum gap:
4190
+
4191
+ | flightId | origin | destination | departureTime | arrivalTime | cost |
4192
+ | -------- | ------ | ----------- | ---------------- | ---------------- | ---: |
4193
+ | F1 | A | B | 2025-01-01 08:00 | 2025-01-01 10:00 | 1 |
4194
+ | F2 | B | E | 2025-01-01 09:00 | 2025-01-01 10:00 | 1 |
4195
+ | F3 | A | C | 2025-01-01 08:00 | 2025-01-01 09:00 | 2 |
4196
+ | F4 | C | E | 2025-01-01 10:00 | 2025-01-01 11:00 | 2 |
4197
+
4198
+ ```ts
4199
+ await scheduledFlights
4200
+ .shortestPath("origin", "destination", "flightId", "A", "E", {
4201
+ startTimeColumn: "departureTime",
4202
+ endTimeColumn: "arrivalTime",
4203
+ minGapMs: 60 * 60 * 1000,
4204
+ weight: "cost",
4205
+ })
4206
+ .log();
4207
+ ```
4208
+
4209
+ | pathId | step | weight | total | flightId | origin | destination | departureTime | arrivalTime | cost |
4210
+ | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------------------- | ------------------- | ---: |
4211
+ | 0 | 1 | 2 | 2 | F3 | A | C | 2025-01-01 08:00:00 | 2025-01-01 09:00:00 | 2 |
4212
+ | 0 | 2 | 2 | 4 | F4 | C | E | 2025-01-01 10:00:00 | 2025-01-01 11:00:00 | 2 |
4213
+
4214
+ With `direction: "incoming"`, connections are followed from target to source.
4215
+ The original source and target values remain unchanged. For this input:
4216
+
4217
+ | edgeId | source | target |
4218
+ | ------ | ------ | ------ |
4219
+ | F1 | A | B |
4220
+
4221
+ ```ts
4222
+ await reverseExample
4223
+ .shortestPath("source", "target", "edgeId", "B", "A", {
4224
+ direction: "incoming",
4225
+ })
4226
+ .log();
4227
+ ```
4228
+
4229
+ | pathId | step | weight | total | edgeId | source | target |
4230
+ | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4231
+ | 0 | 1 | 1 | 1 | F1 | A | B |
4232
+
4233
+ #### `paths`
4234
+
4235
+ Finds all routes between two different nodes. A route cannot visit the same node
4236
+ twice, to avoid loops. Different routes can still share the same nodes.
4237
+
4238
+ The `direction` option lets you follow connections from source to target, from
4239
+ target to source, or in either direction.
4240
+
4241
+ Each connection needs a unique, non-null ID. Pass the name of the column
4242
+ containing these IDs as the `edgeId` argument. If your table is missing an ID
4243
+ column, you can easily create one with `addId()`.
4244
+
4245
+ The result starts with the `pathId`, `step`, `weight`, and `total` columns,
4246
+ followed by all original columns. Steps start at one and follow the search
4247
+ direction. The `weight` column is the connection cost, and `total` is the sum of
4248
+ those costs up to and including the current step. Without the `weight` option,
4249
+ each connection costs one.
4250
+
4251
+ If an input column is already named `pathId`, `step`, `weight`, or `total`
4252
+ (regardless of capitalization), the method throws an error. Rename it with
4253
+ `renameColumns()` first.
4254
+
4255
+ Each row is one connection along a route.
4256
+
4257
+ Use the `startTimeColumn` or `endTimeColumn` options to follow connections in
4258
+ chronological order. The `minGapMs` option sets the minimum gap between
4259
+ consecutive connections, in milliseconds. With both time columns, gaps are
4260
+ measured from one connection's end to the next connection's start; with one
4261
+ column, between their timestamps. The `strictOrdering` option defaults to
4262
+ `true`, rejecting zero-duration gaps. These options only work with
4263
+ `direction: "outgoing"` or `direction: "incoming"`.
4264
+
4265
+ The minimum gap applies only between consecutive connections, not before the
4266
+ first connection.
4267
+
4268
+ Routes are numbered from zero by comparing their sequences of connection IDs,
4269
+ element by element. Rows are sorted by `pathId`, then `step`.
4270
+
4271
+ Unknown IDs or nodes with no route between them produce no rows. The start and
4272
+ end must differ. Self-connections are ignored. Weights must be non-null, finite,
4273
+ and non-negative.
4274
+
4275
+ There is no limit on route length or the number of routes returned. Finding all
4276
+ routes can take a long time and use substantial memory.
4277
+
4278
+ For the first example, we start with these connections:
4279
+
4280
+ | edgeId | source | target |
4281
+ | ------ | ------ | ------ |
4282
+ | E1 | A | B |
4283
+ | E2 | A | C |
4284
+ | E3 | B | D |
4285
+ | E4 | C | D |
4286
+
4287
+ By default, connections are followed from source to target. Both routes from A
4288
+ to D are returned:
4289
+
4290
+ ##### Signature
4291
+
4292
+ ```typescript
4293
+ 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;
4294
+ ```
4295
+
4296
+ ##### Parameters
4297
+
4298
+ - **`sourceColumn`**: The name of the column containing each connection's source
4299
+ node ID.
4300
+ - **`targetColumn`**: The name of the column containing each connection's target
4301
+ node ID.
4302
+ - **`edgeId`**: The name of the column uniquely identifying each connection
4303
+ (edge).
4304
+ - **`start`**: The starting node ID.
4305
+ - **`end`**: The ending node ID, which must differ from `start`.
4306
+ - **`options`**: An optional object with direction, time, and result
4307
+ configuration.
4308
+ - **`options.direction`**: The direction in which to follow connections.
4309
+ Defaults to `"outgoing"`.
4310
+ - **`options.startTimeColumn`**: The name of the column containing each
4311
+ connection's start time. Use this or `endTimeColumn` to follow connections in
4312
+ chronological order.
4313
+ - **`options.endTimeColumn`**: The name of the column containing each
4314
+ connection's end time. Use this or `startTimeColumn` to follow connections in
4315
+ chronological order.
4316
+ - **`options.minGapMs`**: The minimum gap between consecutive connections, in
4317
+ milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time
4318
+ column.
4319
+ - **`options.strictOrdering`**: Whether to reject zero-duration gaps between
4320
+ consecutive connections (equal timestamps). Defaults to `true`. Requires a
4321
+ time column.
4322
+ - **`options.weight`**: The name of the numeric column used as the cost of each
4323
+ connection. If omitted, each connection costs one.
4324
+ - **`options.outputTable`**: If `true`, stores the result in a new table with a
4325
+ generated name. If a string, uses it as the new table's name. If `false` or
4326
+ omitted, overwrites the current table. Defaults to `false`.
4327
+
4328
+ ##### Returns
4329
+
4330
+ The result table, so methods can be chained.
4331
+
4332
+ ##### Examples
4333
+
4334
+ ```ts
4335
+ await connections
4336
+ .paths("source", "target", "edgeId", "A", "D")
4337
+ .log();
4338
+ ```
4339
+
4340
+ | pathId | step | weight | total | edgeId | source | target |
4341
+ | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4342
+ | 0 | 1 | 1 | 1 | E1 | A | B |
4343
+ | 0 | 2 | 1 | 2 | E3 | B | D |
4344
+ | 1 | 1 | 1 | 1 | E2 | A | C |
4345
+ | 1 | 2 | 1 | 2 | E4 | C | D |
4346
+
4347
+ For an input without connection IDs, use `addId()` first:
4348
+
4349
+ | source | target |
4350
+ | ------ | ------ |
4351
+ | A | B |
4352
+ | B | D |
4353
+
4354
+ The generated IDs identify the connections in the result:
4355
+
4356
+ ```ts
4357
+ await unnumberedConnections
4358
+ .addId("edgeId", { prefix: "edge-" })
4359
+ .paths("source", "target", "edgeId", "A", "D")
4360
+ .log();
4361
+ ```
4362
+
4363
+ | pathId | step | weight | total | source | target | edgeId |
4364
+ | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4365
+ | 0 | 1 | 1 | 1 | A | B | edge-0 |
4366
+ | 0 | 2 | 1 | 2 | B | D | edge-1 |
4367
+
4368
+ The next three examples each start with these flights. The direct flight takes
4369
+ ten minutes; the route through B takes three:
4370
+
4371
+ | flightId | origin | destination | minutes |
4372
+ | -------- | ------ | ----------- | ------: |
4373
+ | F1 | A | D | 10 |
4374
+ | F2 | A | B | 1 |
4375
+ | F3 | B | D | 2 |
4376
+
4377
+ With `weight: "minutes"`, both routes are returned with their travel times:
4378
+
4379
+ ```ts
4380
+ await flights
4381
+ .paths("origin", "destination", "flightId", "A", "D", {
4382
+ weight: "minutes",
4383
+ })
4384
+ .log();
4385
+ ```
4386
+
4387
+ | pathId | step | weight | total | flightId | origin | destination | minutes |
4388
+ | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------: |
4389
+ | 0 | 1 | 10 | 10 | F1 | A | D | 10 |
4390
+ | 1 | 1 | 1 | 1 | F2 | A | B | 1 |
4391
+ | 1 | 2 | 2 | 3 | F3 | B | D | 2 |
4392
+
4393
+ Without the `weight` option, the same routes are returned and total counts
4394
+ connections:
4395
+
4396
+ ```ts
4397
+ await flights
4398
+ .paths("origin", "destination", "flightId", "A", "D")
4399
+ .log();
4400
+ ```
4401
+
4402
+ | pathId | step | weight | total | flightId | origin | destination | minutes |
4403
+ | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------: |
4404
+ | 0 | 1 | 1 | 1 | F1 | A | D | 10 |
4405
+ | 1 | 1 | 1 | 1 | F2 | A | B | 1 |
4406
+ | 1 | 2 | 1 | 2 | F3 | B | D | 2 |
4407
+
4408
+ With `direction: "incoming"`, the search runs from D to A. Steps follow that
4409
+ direction, while the original origin and destination values stay unchanged:
4410
+
4411
+ ```ts
4412
+ await flights
4413
+ .paths("origin", "destination", "flightId", "D", "A", {
4414
+ direction: "incoming",
4415
+ weight: "minutes",
4416
+ })
4417
+ .log();
4418
+ ```
4419
+
4420
+ | pathId | step | weight | total | flightId | origin | destination | minutes |
4421
+ | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------: |
4422
+ | 0 | 1 | 10 | 10 | F1 | A | D | 10 |
4423
+ | 1 | 1 | 2 | 2 | F3 | B | D | 2 |
4424
+ | 1 | 2 | 1 | 3 | F2 | A | B | 1 |
4425
+
4426
+ Chronological routes enforce the connection time between every pair of steps.
4427
+ For the next two examples, the 09:00 flight leaves before F1 arrives, while F3
4428
+ meets the one-hour minimum exactly:
4429
+
4430
+ | flightId | origin | destination | departureTime | arrivalTime | cost |
4431
+ | -------- | ------ | ----------- | ---------------- | ---------------- | ---: |
4432
+ | F1 | A | B | 2025-01-01 08:00 | 2025-01-01 10:00 | 2 |
4433
+ | F2 | B | C | 2025-01-01 09:00 | 2025-01-01 10:00 | 9 |
4434
+ | F3 | B | D | 2025-01-01 11:00 | 2025-01-01 12:00 | 3 |
4435
+
4436
+ The route from A to D contains F1 and F3:
4437
+
4438
+ ```ts
4439
+ await scheduledFlights
4440
+ .paths("origin", "destination", "flightId", "A", "D", {
4441
+ startTimeColumn: "departureTime",
4442
+ endTimeColumn: "arrivalTime",
4443
+ minGapMs: 60 * 60 * 1000,
4444
+ weight: "cost",
4445
+ })
4446
+ .log();
4447
+ ```
4448
+
4449
+ | pathId | step | weight | total | flightId | origin | destination | departureTime | arrivalTime | cost |
4450
+ | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------------------- | ------------------- | ---: |
4451
+ | 0 | 1 | 2 | 2 | F1 | A | B | 2025-01-01 08:00:00 | 2025-01-01 10:00:00 | 2 |
4452
+ | 0 | 2 | 3 | 5 | F3 | B | D | 2025-01-01 11:00:00 | 2025-01-01 12:00:00 | 3 |
4453
+
4454
+ Searching backward from D finds the same physical journey. The steps and
4455
+ cumulative totals follow the incoming search from D to A:
4456
+
4457
+ ```ts
4458
+ await scheduledFlights
4459
+ .paths("origin", "destination", "flightId", "D", "A", {
4460
+ direction: "incoming",
4461
+ startTimeColumn: "departureTime",
4462
+ endTimeColumn: "arrivalTime",
4463
+ minGapMs: 60 * 60 * 1000,
4464
+ weight: "cost",
4465
+ })
4466
+ .log();
4467
+ ```
4468
+
4469
+ | pathId | step | weight | total | flightId | origin | destination | departureTime | arrivalTime | cost |
4470
+ | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------------------- | ------------------- | ---: |
4471
+ | 0 | 1 | 3 | 3 | F3 | B | D | 2025-01-01 11:00:00 | 2025-01-01 12:00:00 | 3 |
4472
+ | 0 | 2 | 2 | 5 | F1 | A | B | 2025-01-01 08:00:00 | 2025-01-01 10:00:00 | 2 |
4473
+
4474
+ #### `findCycles`
4475
+
4476
+ Finds all cycles starting and ending at each node in `startNodes`. Pass one node
4477
+ ID or an array of node IDs. A cycle cannot visit the same node twice, except to
4478
+ return to its start, or reuse a connection. Different cycles can share nodes.
4479
+ The `direction` option lets you follow connections from source to target, from
4480
+ target to source, or in either direction. By default, connections are followed
4481
+ from source to target.
4482
+
4483
+ Each connection needs a unique, non-null ID. Pass the name of the column
4484
+ containing these IDs as the `edgeId` argument. If your table is missing an ID
4485
+ column, you can easily create one with `addId()`.
4486
+
4487
+ The result starts with the `start`, `pathId`, `step`, `weight`, and `total`
4488
+ columns, followed by all original columns. The `start` column identifies the
4489
+ requested starting node. Steps start at one and follow the search direction. The
4490
+ `weight` column is the connection cost, and `total` is the sum of those costs up
4491
+ to and including the current step. Without the `weight` option, each connection
4492
+ costs one.
4493
+
4494
+ If an input column is already named `start`, `pathId`, `step`, `weight`, or
4495
+ `total` (regardless of capitalization), the method throws an error. Rename it
4496
+ with `renameColumns()` first.
4497
+
4498
+ Each row is one connection, including the final connection back to the start.
4499
+ Weights must be non-null, finite, and non-negative.
4500
+
4501
+ If a cycle can start at several requested nodes, each starting node produces a
4502
+ separate result. The `pathId` starts at zero for each starting node; `start` and
4503
+ `pathId` together identify a cycle. Passing an empty array or duplicate IDs in
4504
+ `startNodes` throws an error. Unknown IDs or starts with no cycles produce no
4505
+ rows.
4506
+
4507
+ With `direction: "both"`, a cycle and its reverse are returned once per starting
4508
+ node, choosing the smaller sequence of connection IDs. Within each start, cycles
4509
+ are numbered by connection-ID sequence. Rows are sorted by `start`, then
4510
+ `pathId`, then `step`.
4511
+
4512
+ Use the `startTimeColumn` or `endTimeColumn` options to follow connections in
4513
+ chronological order. The `minGapMs` option sets the minimum gap between
4514
+ consecutive connections, in milliseconds. With both time columns, gaps are
4515
+ measured from one connection's end to the next connection's start; with one
4516
+ column, between their timestamps. The `strictOrdering` option defaults to
4517
+ `true`, rejecting zero-duration gaps. These options only work with
4518
+ `direction: "outgoing"` or `direction: "incoming"`.
4519
+
4520
+ Time rules are checked from each requested starting node. A cycle may therefore
4521
+ work from one starting node but not another. No gap is checked from the final
4522
+ connection back to the first. Incoming searches follow connections backward in
4523
+ chronological order.
4524
+
4525
+ A self-connection forms a one-step cycle. With `direction: "both"`, two separate
4526
+ connections between the same nodes can form a two-step cycle. A single
4527
+ connection cannot be followed out and back to create a cycle. Cycles using
4528
+ different connections remain separate, even if they visit the same nodes. If
4529
+ there are no cycles, the result has no rows.
4530
+
4531
+ There is no limit on cycle length or the number of cycles returned. Finding all
4532
+ cycles can take a long time and use substantial memory.
4533
+
4534
+ The next four examples each start with these connections:
4535
+
4536
+ | edgeId | source | target |
4537
+ | ------ | ------ | ------ |
4538
+ | E1 | A | B |
4539
+ | E2 | B | C |
4540
+ | E3 | C | A |
4541
+
4542
+ By default, connections are followed from source to target:
4543
+
4544
+ ##### Signature
4545
+
4546
+ ```typescript
4547
+ 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;
4548
+ ```
4549
+
4550
+ ##### Parameters
4551
+
4552
+ - **`sourceColumn`**: The name of the column containing each connection's source
4553
+ node ID.
4554
+ - **`targetColumn`**: The name of the column containing each connection's target
4555
+ node ID.
4556
+ - **`edgeId`**: The name of the column uniquely identifying each connection
4557
+ (edge).
4558
+ - **`startNodes`**: One starting node ID or an array of IDs. Finds cycles that
4559
+ start and end at each requested node.
4560
+ - **`options`**: An optional object with direction, time, cost, and result
4561
+ configuration.
4562
+ - **`options.direction`**: The direction in which to follow connections.
4563
+ Defaults to `"outgoing"`.
4564
+ - **`options.startTimeColumn`**: The name of the column containing each
4565
+ connection's start time. Use this or `endTimeColumn` to follow connections in
4566
+ chronological order.
4567
+ - **`options.endTimeColumn`**: The name of the column containing each
4568
+ connection's end time. Use this or `startTimeColumn` to follow connections in
4569
+ chronological order.
4570
+ - **`options.minGapMs`**: The minimum gap between consecutive connections, in
4571
+ milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time
4572
+ column.
4573
+ - **`options.strictOrdering`**: Whether to reject zero-duration gaps between
4574
+ consecutive connections (equal timestamps). Defaults to `true`. Requires a
4575
+ time column.
4576
+ - **`options.weight`**: The name of the numeric column used as the cost of each
4577
+ connection. If omitted, each connection costs one.
4578
+ - **`options.outputTable`**: If `true`, stores the result in a new table with a
4579
+ generated name. If a string, uses it as the new table's name. If `false` or
4580
+ omitted, overwrites the current table. Defaults to `false`.
4581
+
4582
+ ##### Returns
4583
+
4584
+ The result table, so methods can be chained.
4585
+
4586
+ ##### Examples
4587
+
4588
+ ```ts
4589
+ await triangle
4590
+ .findCycles("source", "target", "edgeId", "A")
4591
+ .log();
4592
+ ```
4593
+
4594
+ | start | pathId | step | weight | total | edgeId | source | target |
4595
+ | ----- | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4596
+ | A | 0 | 1 | 1 | 1 | E1 | A | B |
4597
+ | A | 0 | 2 | 1 | 2 | E2 | B | C |
4598
+ | A | 0 | 3 | 1 | 3 | E3 | C | A |
4599
+
4600
+ Requesting both A and B returns the cycle separately for each start:
4601
+
4602
+ ```ts
4603
+ await triangle
4604
+ .findCycles("source", "target", "edgeId", ["A", "B"])
4605
+ .log();
4606
+ ```
4607
+
4608
+ | start | pathId | step | weight | total | edgeId | source | target |
4609
+ | ----- | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4610
+ | A | 0 | 1 | 1 | 1 | E1 | A | B |
4611
+ | A | 0 | 2 | 1 | 2 | E2 | B | C |
4612
+ | A | 0 | 3 | 1 | 3 | E3 | C | A |
4613
+ | B | 0 | 1 | 1 | 1 | E2 | B | C |
4614
+ | B | 0 | 2 | 1 | 2 | E3 | C | A |
4615
+ | B | 0 | 3 | 1 | 3 | E1 | A | B |
4616
+
4617
+ With `direction: "incoming"`, connections are followed from target to source:
4618
+
4619
+ ```ts
4620
+ await triangle
4621
+ .findCycles("source", "target", "edgeId", "A", { direction: "incoming" })
4622
+ .log();
4623
+ ```
4624
+
4625
+ | start | pathId | step | weight | total | edgeId | source | target |
4626
+ | ----- | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4627
+ | A | 0 | 1 | 1 | 1 | E3 | C | A |
4628
+ | A | 0 | 2 | 1 | 2 | E2 | B | C |
4629
+ | A | 0 | 3 | 1 | 3 | E1 | A | B |
4630
+
4631
+ With `direction: "both"`, either direction is allowed. This cycle appears once,
4632
+ in the direction that starts with E1:
4633
+
4634
+ ```ts
4635
+ await triangle
4636
+ .findCycles("source", "target", "edgeId", "A", { direction: "both" })
4637
+ .log();
4638
+ ```
4639
+
4640
+ | start | pathId | step | weight | total | edgeId | source | target |
4641
+ | ----- | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4642
+ | A | 0 | 1 | 1 | 1 | E1 | A | B |
4643
+ | A | 0 | 2 | 1 | 2 | E2 | B | C |
4644
+ | A | 0 | 3 | 1 | 3 | E3 | C | A |
4645
+
4646
+ Two separate connections between A and B form a cycle with `direction:
4647
+ "both"`.
4648
+ The self-connection at C forms another cycle. For this input:
4649
+
4650
+ | edgeId | source | target | cost |
4651
+ | ------ | ------ | ------ | ---: |
4652
+ | P1 | A | B | 1 |
4653
+ | P2 | A | B | 2 |
4654
+ | L1 | C | C | 4 |
4655
+
4656
+ ```ts
4657
+ await parallelAndLoop
4658
+ .findCycles("source", "target", "edgeId", ["A", "C"], {
4659
+ direction: "both",
4660
+ weight: "cost",
4661
+ })
4662
+ .log();
4663
+ ```
4664
+
4665
+ | start | pathId | step | weight | total | edgeId | source | target | cost |
4666
+ | ----- | -----: | ---: | -----: | ----: | ------ | ------ | ------ | ---: |
4667
+ | A | 0 | 1 | 1 | 1 | P1 | A | B | 1 |
4668
+ | A | 0 | 2 | 2 | 3 | P2 | A | B | 2 |
4669
+ | C | 0 | 1 | 4 | 4 | L1 | C | C | 4 |
4670
+
4671
+ With the `weight` option, total is a running total of the selected values. For
4672
+ these flights:
4673
+
4674
+ | flightId | origin | destination | minutes |
4675
+ | -------- | ------ | ----------- | ------: |
4676
+ | F1 | A | B | 1 |
4677
+ | F2 | B | C | 2 |
4678
+ | F3 | C | A | 3 |
4679
+
4680
+ ```ts
4681
+ await flights
4682
+ .findCycles("origin", "destination", "flightId", "A", {
4683
+ weight: "minutes",
4684
+ })
4685
+ .log();
4686
+ ```
4687
+
4688
+ | start | pathId | step | weight | total | flightId | origin | destination | minutes |
4689
+ | ----- | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------: |
4690
+ | A | 0 | 1 | 1 | 1 | F1 | A | B | 1 |
4691
+ | A | 0 | 2 | 2 | 3 | F2 | B | C | 2 |
4692
+ | A | 0 | 3 | 3 | 6 | F3 | C | A | 3 |
4693
+
4694
+ For an input without connection IDs, use `addId()` first:
4695
+
4696
+ | source | target |
4697
+ | ------ | ------ |
4698
+ | A | B |
4699
+ | B | C |
4700
+ | C | A |
4701
+
4702
+ ```ts
4703
+ await unnumberedConnections
4704
+ .addId("edgeId", { prefix: "edge-" })
4705
+ .findCycles("source", "target", "edgeId", "A")
4706
+ .log();
4707
+ ```
4708
+
4709
+ | start | pathId | step | weight | total | source | target | edgeId |
4710
+ | ----- | -----: | ---: | -----: | ----: | ------ | ------ | ------ |
4711
+ | A | 0 | 1 | 1 | 1 | A | B | edge-0 |
4712
+ | A | 0 | 2 | 1 | 2 | B | C | edge-1 |
4713
+ | A | 0 | 3 | 1 | 3 | C | A | edge-2 |
4714
+
4715
+ For these instantaneous events, requesting A and B as starting nodes returns
4716
+ only the cycle B → C → A → B. Starting at A would break chronological order:
4717
+
4718
+ | flightId | origin | destination | departureTime |
4719
+ | -------- | ------ | ----------- | ---------------- |
4720
+ | F1 | B | C | 2025-01-01 09:00 |
4721
+ | F2 | C | A | 2025-01-01 10:00 |
4722
+ | F3 | A | B | 2025-01-01 11:00 |
4723
+
4724
+ ```ts
4725
+ await timedFlights
4726
+ .findCycles("origin", "destination", "flightId", ["A", "B"], {
4727
+ startTimeColumn: "departureTime",
4728
+ })
4729
+ .log();
4730
+ ```
4731
+
4732
+ | start | pathId | step | weight | total | flightId | origin | destination | departureTime |
4733
+ | ----- | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------------------- |
4734
+ | B | 0 | 1 | 1 | 1 | F1 | B | C | 2025-01-01 09:00:00 |
4735
+ | B | 0 | 2 | 1 | 2 | F2 | C | A | 2025-01-01 10:00:00 |
4736
+ | B | 0 | 3 | 1 | 3 | F3 | A | B | 2025-01-01 11:00:00 |
4737
+
4738
+ Searching the same events from B in the incoming direction follows connections
4739
+ backward, from the latest to the earliest:
4740
+
4741
+ ```ts
4742
+ await timedFlights
4743
+ .findCycles("origin", "destination", "flightId", "B", {
4744
+ direction: "incoming",
4745
+ startTimeColumn: "departureTime",
4746
+ })
4747
+ .log();
4748
+ ```
4749
+
4750
+ | start | pathId | step | weight | total | flightId | origin | destination | departureTime |
4751
+ | ----- | -----: | ---: | -----: | ----: | -------- | ------ | ----------- | ------------------- |
4752
+ | B | 0 | 1 | 1 | 1 | F3 | A | B | 2025-01-01 11:00:00 |
4753
+ | B | 0 | 2 | 1 | 2 | F2 | C | A | 2025-01-01 10:00:00 |
4754
+ | B | 0 | 3 | 1 | 3 | F1 | B | C | 2025-01-01 09:00:00 |
4755
+
4756
+ #### `extractDatePart`
4757
+
4758
+ Extracts one or more components from a temporal column into new columns. Pass a
4759
+ single part to create a column with that part's name, or pass an object mapping
4760
+ custom new-column names to parts. Existing columns are not overwritten.
4761
+
4762
+ `dayOfWeek` uses Sunday as `0` through Saturday as `6`. `week` follows ISO week
4763
+ numbering, and `dayOfYear` starts at `1`. DuckDB `DATE`, `TIME`, `TIMESTAMP`,
4764
+ and `TIMESTAMP WITH TIME ZONE` columns are supported when the requested
4765
+ component applies to that type: date parts apply to dates and timestamps, while
4766
+ time parts apply to times and timestamps. `NULL` input values produce `NULL`
4767
+ extracted values. Parts extracted from `TIMESTAMP WITH TIME ZONE` values use
4768
+ UTC.
4769
+
4770
+ ##### Signature
4771
+
4772
+ ```typescript
4773
+ extractDatePart(column: string, parts: "year" | "quarter" | "month" | "week" | "day" | "dayOfWeek" | "dayOfYear" | "hour" | "minute" | "second" | Record<string, "year" | "quarter" | "month" | "week" | "day" | "dayOfWeek" | "dayOfYear" | "hour" | "minute" | "second">): this;
4774
+ ```
4775
+
4776
+ ##### Parameters
4777
+
4778
+ - **`column`**: The temporal column from which to extract components.
4779
+ - **`parts`**: A part to extract using its name as the new column, or an object
4780
+ mapping each custom new-column name to the part it should contain.
4781
+
4782
+ ##### Returns
4783
+
4784
+ The table, so methods can be chained.
4785
+
4786
+ ##### Examples
4787
+
4788
+ ```ts
4789
+ // Add a column named 'year' from the 'publishedAt' timestamp
4790
+ await table.extractDatePart("publishedAt", "year").log();
4791
+ ```
4792
+
4793
+ ```ts
4794
+ // Extract multiple components with custom column names
4795
+ await table.extractDatePart("publishedAt", {
4796
+ publicationYear: "year",
4797
+ publicationMonth: "month",
4798
+ }).log();
4799
+ ```
4800
+
4801
+ #### `addRowNumber`
4802
+
4803
+ Adds a new column to the table containing the row number, starting at 0 (like an
4804
+ index).
4805
+
4806
+ ##### Signature
4807
+
4808
+ ```typescript
4809
+ addRowNumber(newColumn: string, options?: { by?: string | string[] }): this;
4810
+ ```
4811
+
4812
+ ##### Parameters
4813
+
4814
+ - **`newColumn`**: The name of the new column that will store the row number.
4815
+ - **`options`**: An optional object with configuration options:
4816
+ - **`options.by`**: A column name or an array of column names to partition by.
4817
+ The row number restarts at 0 within each group.
4818
+
4819
+ ##### Returns
4820
+
4821
+ The table, so methods can be chained.
4822
+
4823
+ ##### Examples
4824
+
4825
+ ```ts
4826
+ // Add a new column named 'rowNumber' with the row number for each row
4827
+ await table.addRowNumber("rowNumber").log();
4828
+ ```
4829
+
4830
+ ```ts
4831
+ // Add a new column named 'rowNumber' with the row number for each 'category'
4832
+ await table.addRowNumber("rowNumber", { by: "category" }).log();
4833
+ ```
4834
+
4835
+ #### `crossJoin`
4836
+
4837
+ Performs a cross join operation with another table. A cross join returns the
4838
+ Cartesian product of the rows from both tables, meaning all possible pairs of
4839
+ rows will be in the resulting table. This means that if the left table has `n`
4840
+ rows and the right table has `m` rows, the result will have `n * m` rows.
4841
+
4842
+ ##### Signature
4843
+
4844
+ ```typescript
4845
+ crossJoin(rightTable: SimpleTable, options?: { outputTable?: string | boolean }): this;
4846
+ ```
4847
+
4848
+ ##### Parameters
4849
+
4850
+ - **`rightTable`**: The SimpleTable instance to cross join with.
4851
+ - **`options`**: An optional object with configuration options:
4852
+ - **`options.outputTable`**: If `true`, the results will be stored in a new
4853
+ table with a generated name. If a string, it will be used as the name for the
4854
+ new table. If `false` or omitted, the current table will be overwritten.
4855
+ Defaults to `false`.
4856
+
4857
+ ##### Returns
4858
+
4859
+ A table instance containing the cross-joined data (either the current table or a
4860
+ new table), so methods can be chained.
4861
+
4862
+ ##### Examples
4863
+
4864
+ ```ts
4865
+ // Perform a cross join with 'tableB', overwriting the current table (tableA)
4866
+ await tableA.crossJoin(tableB).log();
4867
+ ```
4868
+
4869
+ ```ts
4870
+ // Perform a cross join with 'tableB' and store the results in a new table with a generated name
4871
+ const tableC = await tableA.crossJoin(tableB, { outputTable: true }).log();
4872
+ ```
4873
+
4874
+ ```ts
4875
+ // Perform a cross join with 'tableB' and store the results in a new table named 'tableC'
4876
+ const tableC = await tableA.crossJoin(tableB, { outputTable: "tableC" }).log();
4877
+ ```
4878
+
4879
+ #### `join`
4880
+
4881
+ Merges the data of this table (considered the left table) with another table
4882
+ (the right table) based on a common column or multiple columns. Note that the
4883
+ order of rows in the returned data is not guaranteed to be the same as in the
4884
+ original tables. This operation might create temporary files in a `.tmp` folder;
4885
+ consider adding `.tmp` to your `.gitignore`.
4886
+
4887
+ ##### Signature
4888
+
4889
+ ```typescript
4890
+ join(rightTable: SimpleTable, options?: { on?: string | string[]; type?: "inner" | "left" | "right" | "full"; outputTable?: string | boolean }): this;
4891
+ ```
4892
+
4893
+ ##### Parameters
4894
+
4895
+ - **`rightTable`**: The SimpleTable instance to be joined with this table.
4896
+ - **`options`**: An optional object with configuration options:
4897
+ - **`options.on`**: The column(s) to join on. If omitted, the method
4898
+ automatically searches for a column name that exists in both tables. Can be a
4899
+ single string or an array of strings for multiple join keys.
4900
+ - **`options.type`**: The type of join operation to perform. Possible values are
4901
+ `"inner"`, `"left"` (default), `"right"`, or `"full"`.
4902
+ - **`options.outputTable`**: If `true`, the results will be stored in a new
4903
+ table with a generated name. If a string, it will be used as the name for the
4904
+ new table. If `false` or omitted, the current table will be overwritten.
4905
+ Defaults to `false`.
4906
+
4907
+ ##### Returns
4908
+
4909
+ A table instance containing the joined data (either the current table or a new
4910
+ table), so methods can be chained.
4911
+
4912
+ ##### Examples
4913
+
4914
+ ```ts
4915
+ // Perform a left join with 'tableB' on a common column (auto-detected), overwriting tableA
4916
+ await tableA.join(tableB).log();
4917
+ ```
4918
+
4919
+ ```ts
4920
+ // Perform an inner join with 'tableB' on the 'id' column, storing results in a new table named 'tableC'
4921
+ const tableC = await tableA.join(tableB, {
4922
+ on: "id",
4923
+ type: "inner",
4924
+ outputTable: "tableC",
4925
+ }).log();
4926
+ ```
4927
+
4928
+ ```ts
4929
+ // Perform a join on multiple columns ('name' and 'category')
4930
+ await tableA.join(tableB, { on: ["name", "category"] }).log();
4931
+ ```
4932
+
4933
+ #### `fuzzyJoin`
4934
+
4935
+ Performs a fuzzy left join between this table (considered the left table) and
4936
+ another table (the right table) based on string similarity between two text
4937
+ columns. Uses the [rapidfuzz](https://query.farm/duckdb_extension_rapidfuzz)
4938
+ DuckDB community extension.
4939
+
4940
+ If a similarity score column is added to the results, the rows will be ordered
4941
+ alphabetically by the left column, and then by descending similarity score
4942
+ within each group of identical left column values. Otherwise, the rows will be
4943
+ order alphabetically by the left column and then by the right column.
4944
+
4945
+ This operation might create temporary files in a `.tmp` folder; consider adding
4946
+ `.tmp` to your `.gitignore`.
4947
+
4948
+ ##### Signature
4949
+
4950
+ ```typescript
4951
+ fuzzyJoin(rightTable: SimpleTable, leftColumn: string, rightColumn: string, threshold: number, options?: { method?: "ratio" | "partial_ratio" | "token_sort_ratio" | "token_set_ratio"; similarityColumn?: string; outputTable?: string | boolean; prefilterPrefixLength?: number }): this;
4952
+ ```
4953
+
4954
+ ##### Parameters
4955
+
4956
+ - **`rightTable`**: The SimpleTable instance to be joined with this table.
4957
+ - **`leftColumn`**: The name of the column in this (left) table containing the
4958
+ text to compare.
4959
+ - **`rightColumn`**: The name of the column in the right table containing the
4960
+ text to compare.
4961
+ - **`threshold`**: The minimum similarity score (0–100) required for two rows to
4962
+ be joined. For `method: "ratio"`, a length-based pre-filter is automatically
4963
+ applied based on the threshold to improve performance without losing accuracy.
4964
+ - **`options`**: An optional object with configuration options:
4965
+ - **`options.method`**: The rapidfuzz similarity algorithm to use. Defaults to
4966
+ `"ratio"`. - `"ratio"`: Overall similarity (Levenshtein-based). -
4967
+ `"partial_ratio"`: Best partial/substring similarity. - `"token_sort_ratio"`:
4968
+ Similarity after sorting tokens (words), useful for reordered words. -
4969
+ `"token_set_ratio"`: Similarity based on sets of tokens, ignoring duplicates
4970
+ and word order.
4971
+ - **`options.similarityColumn`**: If provided, a column with this name is added
4972
+ to the result containing the similarity score (0–100). If omitted, the score
4973
+ is not included in the output.
4974
+ - **`options.outputTable`**: If `true`, the results will be stored in a new
4975
+ table with a generated name. If a string, it will be used as the name for the
4976
+ new table. If `false` or omitted, the current table will be overwritten.
4977
+ Defaults to `false`.
4978
+ - **`options.prefilterPrefixLength`**: An optional prefix length. Only strings
4979
+ sharing the same first N characters are compared. Note that prefix filtering
4980
+ is lossy (e.g. "John" vs. "Phon" will not match despite high similarity).
4981
+
4982
+ ##### Returns
4983
+
4984
+ A table instance containing the fuzzy-joined data (either the current table or a
4985
+ new table), so methods can be chained.
4986
+
4987
+ ##### Examples
4988
+
4989
+ ```ts
4990
+ // Fuzzy left join tableA with tableB on 'name' (left) and 'standardName' (right) with a threshold of 80
4991
+ // A length-based pre-filter is automatically applied.
4992
+ await tableA.fuzzyJoin(tableB, "name", "standardName", 80).log();
4993
+ ```
4994
+
4995
+ ```ts
4996
+ // Fuzzy join with a prefix-based pre-filter and a threshold of 80
4997
+ await tableA.fuzzyJoin(tableB, "name", "standardName", 80, {
4998
+ prefilterPrefixLength: 3, // Must share the same first 3 characters
4999
+ }).log();
5000
+ ```
5001
+
5002
+ ```ts
5003
+ // Fuzzy join with a custom threshold and method, storing results in a new table
5004
+ const tableC = await tableA.fuzzyJoin(tableB, "name", "standardName", 90, {
5005
+ method: "token_sort_ratio",
5006
+ outputTable: "tableC",
5007
+ }).log();
5008
+ ```
5009
+
5010
+ ```ts
5011
+ // Fuzzy join with a custom similarity column name and a threshold of 80
5012
+ await tableA.fuzzyJoin(tableB, "name", "standardName", 80, {
5013
+ similarityColumn: "matchScore",
5014
+ }).log();
5015
+ ```
5016
+
5017
+ #### `fuzzyClean`
5018
+
5019
+ Normalizes string values in a column by detecting fuzzy duplicates and replacing
5020
+ them with a single canonical value.
5021
+
5022
+ Similar strings are grouped into clusters. Matching is transitive: if
5023
+ `"New York"` is similar to `"New Yorke"` and `"New Yorke"` is similar to
5024
+ `"New Yorkk"`, all three land in the same cluster even if `"New York"` and
5025
+ `"New Yorkk"` would not match directly. Each cluster is then collapsed to one
5026
+ representative value based on the `strategy` option.
5027
+
5028
+ Similarity is computed using the
5029
+ [rapidfuzz](https://query.farm/duckdb_extension_rapidfuzz) DuckDB community
5030
+ extension, which is installed and loaded automatically.
5031
+
5032
+ ##### Signature
5033
+
5034
+ ```typescript
5035
+ fuzzyClean(column: string, newColumn: string, threshold: number, options?: { method?: "ratio" | "partial_ratio" | "token_sort_ratio" | "token_set_ratio"; strategy?: "mostCommon" | "longestString" | "shortestString" | "mostCentral" | "maxScore"; prefilterPrefixLength?: number }): this;
5036
+ ```
5037
+
5038
+ ##### Parameters
5039
+
5040
+ - **`column`**: The name of the column containing the strings to normalize.
5041
+ - **`newColumn`**: The name of the column to write the normalized values to. Use
5042
+ the same name as `column` to normalize in-place.
3218
5043
  - **`threshold`**: The minimum similarity score (0–100) for two strings to be
3219
5044
  considered duplicates. For `method: "ratio"`, a length-based pre-filter is
3220
5045
  automatically applied based on the threshold to improve performance without
@@ -3273,7 +5098,8 @@ await table.fuzzyClean("category", "category", 80, {
3273
5098
 
3274
5099
  #### `replace`
3275
5100
 
3276
- Replaces specified strings in the selected columns.
5101
+ Replaces specified strings in the selected columns. Use `["all"]` to target a
5102
+ column literally named `all`.
3277
5103
 
3278
5104
  ##### Signature
3279
5105
 
@@ -3656,7 +5482,8 @@ await table.lastChars("productCode", 2).log();
3656
5482
 
3657
5483
  #### `replaceNulls`
3658
5484
 
3659
- Replaces `NULL` values in the specified columns with a given value.
5485
+ Replaces `NULL` values in the specified columns with a given value. Use
5486
+ `["all"]` to target a column literally named `all`.
3660
5487
 
3661
5488
  ##### Signature
3662
5489
 
@@ -3796,6 +5623,152 @@ await table
3796
5623
  .rowToText(["name", "age", "salary"], "profile").log();
3797
5624
  ```
3798
5625
 
5626
+ #### `rowToVector`
5627
+
5628
+ Combines numeric scalar columns into a fixed-size vector. The input column order
5629
+ determines the vector dimension order, and null values remain null vector
5630
+ elements.
5631
+
5632
+ When all input columns have the same numeric type, that type is preserved. Mixed
5633
+ numeric types require an explicit `type` option. Casting exact decimals or large
5634
+ integers to FLOAT or DOUBLE can lose precision.
5635
+
5636
+ ##### Signature
5637
+
5638
+ ```typescript
5639
+ rowToVector(columns: string[], newColumn: string, options?: { type?: "float" | "double" }): this;
5640
+ ```
5641
+
5642
+ ##### Parameters
5643
+
5644
+ - **`columns`**: Numeric scalar columns to combine, in vector dimension order.
5645
+ - **`newColumn`**: The name of the vector column to create.
5646
+ - **`options`**: Optional vector element type settings.
5647
+ - **`options.type`**: Cast every element to `"float"` or `"double"`. Required
5648
+ when the input column types differ.
5649
+
5650
+ ##### Returns
5651
+
5652
+ The table, so methods can be chained.
5653
+
5654
+ ##### Examples
5655
+
5656
+ ```ts
5657
+ await table
5658
+ .rowToVector(["height", "weight"], "measurements")
5659
+ .log();
5660
+ ```
5661
+
5662
+ ```ts
5663
+ await table
5664
+ .rowToVector(["count", "score"], "features", { type: "double" })
5665
+ .log();
5666
+ ```
5667
+
5668
+ #### `normalizeVector`
5669
+
5670
+ Normalizes a numeric vector column. By default, each dimension is scaled
5671
+ independently to `[0, 1]` across rows: all first elements together, all second
5672
+ elements together, and so on. With `normalization: "rowL2"`, each row is scaled
5673
+ to Euclidean unit length while preserving its direction; zero vectors remain
5674
+ zero.
5675
+
5676
+ The input may be a numeric LIST or fixed-size ARRAY. The output is a fixed-size
5677
+ DOUBLE ARRAY. Converting large integers and exact decimals to DOUBLE can lose
5678
+ precision. With `"dimensionMinMax"`, a dimension whose converted values are all
5679
+ equal cannot be normalized.
5680
+
5681
+ ##### Signature
5682
+
5683
+ ```typescript
5684
+ normalizeVector(column: string, newColumn: string, options?: { normalization?: "dimensionMinMax" | "rowL2" }): this;
5685
+ ```
5686
+
5687
+ ##### Parameters
5688
+
5689
+ - **`column`**: The numeric vector column to normalize.
5690
+ - **`newColumn`**: The output column. Use the source column's name to replace
5691
+ the source column with the normalized DOUBLE vector.
5692
+ - **`options`**: Normalization settings.
5693
+ - **`options.normalization`**: `"dimensionMinMax"` scales each dimension across
5694
+ rows; `"rowL2"` scales each row to unit length. Defaults to
5695
+ `"dimensionMinMax"`.
5696
+
5697
+ ##### Returns
5698
+
5699
+ The table, so methods can be chained.
5700
+
5701
+ ##### Examples
5702
+
5703
+ ```ts
5704
+ // Scale each dimension across rows to [0, 1] in a new column.
5705
+ await table
5706
+ .normalizeVector("features", "scaledFeatures")
5707
+ .log();
5708
+ ```
5709
+
5710
+ ```ts
5711
+ // Replace each vector with its unit-length version; zero vectors stay zero.
5712
+ await table
5713
+ .normalizeVector("features", "features", { normalization: "rowL2" })
5714
+ .log();
5715
+ ```
5716
+
5717
+ #### `mahalanobis`
5718
+
5719
+ Calculates each row's Mahalanobis distance from a supplied reference point and
5720
+ stores it in a new DOUBLE column. Sample covariance (`n - 1`) is estimated from
5721
+ the dataset, independently of the reference point.
5722
+
5723
+ Pass one numeric LIST or ARRAY column, or an array of numeric scalar columns.
5724
+ Reference values follow the same dimension order. Inputs are converted privately
5725
+ to DOUBLE, which can lose precision for large integers and exact decimals;
5726
+ source columns and types remain unchanged.
5727
+
5728
+ Requires more rows than dimensions and finite, non-null, consistent features
5729
+ with invertible, numerically stable covariance. Invalid inputs leave the source
5730
+ unchanged.
5731
+
5732
+ ##### Signature
5733
+
5734
+ ```typescript
5735
+ mahalanobis(columns: string | string[], referencePoint: number[], newColumn: string, options?: { similarityScoreColumn?: string }): this;
5736
+ ```
5737
+
5738
+ ##### Parameters
5739
+
5740
+ - **`columns`**: A numeric vector column, or numeric scalar columns in feature
5741
+ order.
5742
+ - **`referencePoint`**: One finite number per feature dimension; may be outside
5743
+ the dataset.
5744
+ - **`newColumn`**: The name of the new DOUBLE distance column.
5745
+ - **`options`**: Optional output settings.
5746
+ - **`options.similarityScoreColumn`**: A new DOUBLE column for the
5747
+ dataset-relative score `1 - distance / maxDistance`. Exact matches score 1 and
5748
+ the farthest rows score 0; if all distances are zero, every score is 1.
5749
+
5750
+ ##### Returns
5751
+
5752
+ The table, so methods can be chained.
5753
+
5754
+ ##### Examples
5755
+
5756
+ ```ts
5757
+ // Measure distance from a reference height and weight.
5758
+ await table
5759
+ .mahalanobis(["height", "weight"], [175, 70], "distance")
5760
+ .log();
5761
+ ```
5762
+
5763
+ ```ts
5764
+ // Compare feature vectors and add a dataset-relative similarity score.
5765
+ await table
5766
+ .mahalanobis("features", [175, 70], "distance", {
5767
+ similarityScoreColumn: "similarity",
5768
+ })
5769
+ .log();
5770
+ ```
5771
+
3799
5772
  #### `unnest`
3800
5773
 
3801
5774
  Unnests (expands) rows by splitting a column's string values into multiple rows