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

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