@nshiab/simple-data-analysis-core 2.0.8 → 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 (513) 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 +2805 -1077
  9. package/esm/class/SimpleTable.d.ts.map +1 -1
  10. package/esm/class/SimpleTable.js +2777 -1077
  11. package/esm/helpers/appendColumnBatches.d.ts +3 -0
  12. package/esm/helpers/appendColumnBatches.d.ts.map +1 -0
  13. package/esm/helpers/appendColumnBatches.js +21 -0
  14. package/esm/helpers/buildApproximateMutualReachabilityMst.d.ts +45 -0
  15. package/esm/helpers/buildApproximateMutualReachabilityMst.d.ts.map +1 -0
  16. package/esm/helpers/buildApproximateMutualReachabilityMst.js +212 -0
  17. package/esm/helpers/buildChronologicalGraphComponentsSql.d.ts +14 -0
  18. package/esm/helpers/buildChronologicalGraphComponentsSql.d.ts.map +1 -0
  19. package/esm/helpers/buildChronologicalGraphComponentsSql.js +167 -0
  20. package/esm/helpers/buildExactMutualReachabilityMst.d.ts +28 -0
  21. package/esm/helpers/buildExactMutualReachabilityMst.d.ts.map +1 -0
  22. package/esm/helpers/buildExactMutualReachabilityMst.js +97 -0
  23. package/esm/helpers/buildGraphTemporalCostStateSql.d.ts +12 -0
  24. package/esm/helpers/buildGraphTemporalCostStateSql.d.ts.map +1 -0
  25. package/esm/helpers/buildGraphTemporalCostStateSql.js +86 -0
  26. package/esm/helpers/buildGraphTemporalReachabilitySql.d.ts +13 -0
  27. package/esm/helpers/buildGraphTemporalReachabilitySql.d.ts.map +1 -0
  28. package/esm/helpers/buildGraphTemporalReachabilitySql.js +70 -0
  29. package/esm/helpers/buildSparseMutualReachabilityMst.d.ts +10 -0
  30. package/esm/helpers/buildSparseMutualReachabilityMst.d.ts.map +1 -0
  31. package/esm/helpers/buildSparseMutualReachabilityMst.js +47 -0
  32. package/esm/helpers/buildUmapGraph.d.ts +21 -0
  33. package/esm/helpers/buildUmapGraph.d.ts.map +1 -0
  34. package/esm/helpers/buildUmapGraph.js +61 -0
  35. package/esm/helpers/buildVectorNeighbors.d.ts +45 -0
  36. package/esm/helpers/buildVectorNeighbors.d.ts.map +1 -0
  37. package/esm/helpers/buildVectorNeighbors.js +170 -0
  38. package/esm/helpers/buildWeakGraphComponentsSql.d.ts +3 -0
  39. package/esm/helpers/buildWeakGraphComponentsSql.d.ts.map +1 -0
  40. package/esm/helpers/buildWeakGraphComponentsSql.js +32 -0
  41. package/esm/helpers/cacheDatabase.d.ts.map +1 -1
  42. package/esm/helpers/cacheDatabase.js +2 -1
  43. package/esm/helpers/camelCase.d.ts +7 -5
  44. package/esm/helpers/camelCase.d.ts.map +1 -1
  45. package/esm/helpers/camelCase.js +7 -5
  46. package/esm/helpers/capitalize.d.ts +6 -4
  47. package/esm/helpers/capitalize.d.ts.map +1 -1
  48. package/esm/helpers/capitalize.js +6 -4
  49. package/esm/helpers/clusterHdbscan.d.ts +18 -0
  50. package/esm/helpers/clusterHdbscan.d.ts.map +1 -0
  51. package/esm/helpers/clusterHdbscan.js +342 -0
  52. package/esm/helpers/computeCovariance.d.ts +16 -0
  53. package/esm/helpers/computeCovariance.d.ts.map +1 -0
  54. package/esm/helpers/computeCovariance.js +99 -0
  55. package/esm/helpers/computeMahalanobisDistances.d.ts +14 -0
  56. package/esm/helpers/computeMahalanobisDistances.d.ts.map +1 -0
  57. package/esm/helpers/computeMahalanobisDistances.js +87 -0
  58. package/esm/helpers/createDirectory.d.ts +4 -3
  59. package/esm/helpers/createDirectory.d.ts.map +1 -1
  60. package/esm/helpers/createDirectory.js +4 -3
  61. package/esm/helpers/dataToArrays.d.ts +6 -4
  62. package/esm/helpers/dataToArrays.d.ts.map +1 -1
  63. package/esm/helpers/dataToArrays.js +6 -4
  64. package/esm/helpers/extractTypes.d.ts +1 -1
  65. package/esm/helpers/extractTypes.js +4 -9
  66. package/esm/helpers/factorCovariance.d.ts +17 -0
  67. package/esm/helpers/factorCovariance.d.ts.map +1 -0
  68. package/esm/helpers/factorCovariance.js +189 -0
  69. package/esm/helpers/findGeoColumn.d.ts +6 -4
  70. package/esm/helpers/findGeoColumn.d.ts.map +1 -1
  71. package/esm/helpers/findGeoColumn.js +6 -4
  72. package/esm/helpers/findGeoColumnFromSchema.d.ts +8 -5
  73. package/esm/helpers/findGeoColumnFromSchema.d.ts.map +1 -1
  74. package/esm/helpers/findGeoColumnFromSchema.js +8 -5
  75. package/esm/helpers/fitUmapCurve.d.ts +2 -0
  76. package/esm/helpers/fitUmapCurve.d.ts.map +1 -0
  77. package/esm/helpers/fitUmapCurve.js +66 -0
  78. package/esm/helpers/formatDate.d.ts +12 -6
  79. package/esm/helpers/formatDate.d.ts.map +1 -1
  80. package/esm/helpers/formatDate.js +12 -6
  81. package/esm/helpers/formatMissingTables.d.ts +8 -5
  82. package/esm/helpers/formatMissingTables.d.ts.map +1 -1
  83. package/esm/helpers/formatMissingTables.js +8 -5
  84. package/esm/helpers/formatNumber.d.ts +19 -10
  85. package/esm/helpers/formatNumber.d.ts.map +1 -1
  86. package/esm/helpers/formatNumber.js +32 -17
  87. package/esm/helpers/getGraphEdgeIdColumn.d.ts +9 -0
  88. package/esm/helpers/getGraphEdgeIdColumn.d.ts.map +1 -0
  89. package/esm/helpers/getGraphEdgeIdColumn.js +25 -0
  90. package/esm/helpers/getGraphEndpointColumns.d.ts +11 -0
  91. package/esm/helpers/getGraphEndpointColumns.d.ts.map +1 -0
  92. package/esm/helpers/getGraphEndpointColumns.js +160 -0
  93. package/esm/helpers/getGraphWeightColumn.d.ts +10 -0
  94. package/esm/helpers/getGraphWeightColumn.d.ts.map +1 -0
  95. package/esm/helpers/getGraphWeightColumn.js +40 -0
  96. package/esm/helpers/graphRouteResultSchema.d.ts +4 -0
  97. package/esm/helpers/graphRouteResultSchema.d.ts.map +1 -0
  98. package/esm/helpers/graphRouteResultSchema.js +12 -0
  99. package/esm/helpers/graphRouteResultSelect.d.ts +4 -0
  100. package/esm/helpers/graphRouteResultSelect.d.ts.map +1 -0
  101. package/esm/helpers/graphRouteResultSelect.js +22 -0
  102. package/esm/helpers/hasGeometryColumn.d.ts +4 -3
  103. package/esm/helpers/hasGeometryColumn.d.ts.map +1 -1
  104. package/esm/helpers/hasGeometryColumn.js +4 -3
  105. package/esm/helpers/initialUmapCoordinates.d.ts +2 -0
  106. package/esm/helpers/initialUmapCoordinates.d.ts.map +1 -0
  107. package/esm/helpers/initialUmapCoordinates.js +5 -0
  108. package/esm/helpers/inspectGraphConnectivity.d.ts +10 -0
  109. package/esm/helpers/inspectGraphConnectivity.d.ts.map +1 -0
  110. package/esm/helpers/inspectGraphConnectivity.js +55 -0
  111. package/esm/helpers/mergeOptions.d.ts +24 -13
  112. package/esm/helpers/mergeOptions.d.ts.map +1 -1
  113. package/esm/helpers/mergeOptions.js +24 -13
  114. package/esm/helpers/optimizeUmapLayout.d.ts +7 -0
  115. package/esm/helpers/optimizeUmapLayout.d.ts.map +1 -0
  116. package/esm/helpers/optimizeUmapLayout.js +93 -0
  117. package/esm/helpers/parseValue.d.ts +6 -4
  118. package/esm/helpers/parseValue.d.ts.map +1 -1
  119. package/esm/helpers/parseValue.js +6 -4
  120. package/esm/helpers/prepareGraphRouteSql.d.ts +31 -0
  121. package/esm/helpers/prepareGraphRouteSql.d.ts.map +1 -0
  122. package/esm/helpers/prepareGraphRouteSql.js +86 -0
  123. package/esm/helpers/prepareGraphStarts.d.ts +9 -0
  124. package/esm/helpers/prepareGraphStarts.d.ts.map +1 -0
  125. package/esm/helpers/prepareGraphStarts.js +68 -0
  126. package/esm/helpers/prepareGraphTemporalSql.d.ts +28 -0
  127. package/esm/helpers/prepareGraphTemporalSql.d.ts.map +1 -0
  128. package/esm/helpers/prepareGraphTemporalSql.js +154 -0
  129. package/esm/helpers/prepareGraphTraversal.d.ts +19 -0
  130. package/esm/helpers/prepareGraphTraversal.d.ts.map +1 -0
  131. package/esm/helpers/prepareGraphTraversal.js +79 -0
  132. package/esm/helpers/prepareNumericFeatures.d.ts +41 -0
  133. package/esm/helpers/prepareNumericFeatures.d.ts.map +1 -0
  134. package/esm/helpers/prepareNumericFeatures.js +210 -0
  135. package/esm/helpers/prepareUmapLayoutOptions.d.ts +14 -0
  136. package/esm/helpers/prepareUmapLayoutOptions.d.ts.map +1 -0
  137. package/esm/helpers/prepareUmapLayoutOptions.js +23 -0
  138. package/esm/helpers/prettyDuration.d.ts +14 -8
  139. package/esm/helpers/prettyDuration.d.ts.map +1 -1
  140. package/esm/helpers/prettyDuration.js +14 -8
  141. package/esm/helpers/printTable.d.ts +18 -13
  142. package/esm/helpers/printTable.d.ts.map +1 -1
  143. package/esm/helpers/printTable.js +18 -13
  144. package/esm/helpers/publishPreparedColumns.d.ts +37 -0
  145. package/esm/helpers/publishPreparedColumns.d.ts.map +1 -0
  146. package/esm/helpers/publishPreparedColumns.js +113 -0
  147. package/esm/helpers/queryDB.d.ts +24 -13
  148. package/esm/helpers/queryDB.d.ts.map +1 -1
  149. package/esm/helpers/queryDB.js +24 -13
  150. package/esm/helpers/queueAsyncBarrier.d.ts +12 -7
  151. package/esm/helpers/queueAsyncBarrier.d.ts.map +1 -1
  152. package/esm/helpers/queueAsyncBarrier.js +12 -7
  153. package/esm/helpers/queueGraphResult.d.ts +18 -0
  154. package/esm/helpers/queueGraphResult.d.ts.map +1 -0
  155. package/esm/helpers/queueGraphResult.js +39 -0
  156. package/esm/helpers/quoteIdentifier.d.ts +4 -3
  157. package/esm/helpers/quoteIdentifier.d.ts.map +1 -1
  158. package/esm/helpers/quoteIdentifier.js +4 -3
  159. package/esm/helpers/quoteQualifiedIdentifier.d.ts +6 -4
  160. package/esm/helpers/quoteQualifiedIdentifier.d.ts.map +1 -1
  161. package/esm/helpers/quoteQualifiedIdentifier.js +6 -4
  162. package/esm/helpers/readScalarNumber.d.ts +3 -0
  163. package/esm/helpers/readScalarNumber.d.ts.map +1 -0
  164. package/esm/helpers/readScalarNumber.js +4 -0
  165. package/esm/helpers/runQuery.d.ts.map +1 -1
  166. package/esm/helpers/runQuery.js +17 -3
  167. package/esm/helpers/selectFuzzyReplacements.d.ts +11 -0
  168. package/esm/helpers/selectFuzzyReplacements.d.ts.map +1 -0
  169. package/esm/helpers/selectFuzzyReplacements.js +124 -0
  170. package/esm/helpers/stabilizeCosineVectors.d.ts +14 -0
  171. package/esm/helpers/stabilizeCosineVectors.d.ts.map +1 -0
  172. package/esm/helpers/stabilizeCosineVectors.js +34 -0
  173. package/esm/helpers/stringToArray.d.ts +4 -3
  174. package/esm/helpers/stringToArray.d.ts.map +1 -1
  175. package/esm/helpers/stringToArray.js +4 -3
  176. package/esm/helpers/umapRandom.d.ts +2 -0
  177. package/esm/helpers/umapRandom.d.ts.map +1 -0
  178. package/esm/helpers/umapRandom.js +10 -0
  179. package/esm/helpers/updateColumnsWithJS.d.ts +12 -6
  180. package/esm/helpers/updateColumnsWithJS.d.ts.map +1 -1
  181. package/esm/helpers/updateColumnsWithJS.js +12 -6
  182. package/esm/helpers/validateGraphRouteResultSchema.d.ts +4 -0
  183. package/esm/helpers/validateGraphRouteResultSchema.d.ts.map +1 -0
  184. package/esm/helpers/validateGraphRouteResultSchema.js +13 -0
  185. package/esm/helpers/validateGraphTemporalEvents.d.ts +7 -0
  186. package/esm/helpers/validateGraphTemporalEvents.d.ts.map +1 -0
  187. package/esm/helpers/validateGraphTemporalEvents.js +47 -0
  188. package/esm/helpers/validateNumericalAnalysis.d.ts +10 -6
  189. package/esm/helpers/validateNumericalAnalysis.d.ts.map +1 -1
  190. package/esm/helpers/validateNumericalAnalysis.js +10 -6
  191. package/esm/helpers/validateVectorRowIds.d.ts +4 -0
  192. package/esm/helpers/validateVectorRowIds.d.ts.map +1 -0
  193. package/esm/helpers/validateVectorRowIds.js +16 -0
  194. package/esm/helpers/vectorDistanceExpression.d.ts +6 -0
  195. package/esm/helpers/vectorDistanceExpression.d.ts.map +1 -0
  196. package/esm/helpers/vectorDistanceExpression.js +11 -0
  197. package/esm/helpers/wrapString.d.ts +10 -7
  198. package/esm/helpers/wrapString.d.ts.map +1 -1
  199. package/esm/helpers/wrapString.js +10 -7
  200. package/esm/methods/addId.d.ts +5 -0
  201. package/esm/methods/addId.d.ts.map +1 -0
  202. package/esm/methods/addId.js +38 -0
  203. package/esm/methods/cache.js +1 -1
  204. package/esm/methods/commonNeighbors.d.ts +10 -0
  205. package/esm/methods/commonNeighbors.d.ts.map +1 -0
  206. package/esm/methods/commonNeighbors.js +101 -0
  207. package/esm/methods/connectedComponents.d.ts +9 -0
  208. package/esm/methods/connectedComponents.d.ts.map +1 -0
  209. package/esm/methods/connectedComponents.js +147 -0
  210. package/esm/methods/degree.d.ts +9 -0
  211. package/esm/methods/degree.d.ts.map +1 -0
  212. package/esm/methods/degree.js +135 -0
  213. package/esm/methods/distances.d.ts +12 -0
  214. package/esm/methods/distances.d.ts.map +1 -0
  215. package/esm/methods/distances.js +164 -0
  216. package/esm/methods/findCycles.d.ts +12 -0
  217. package/esm/methods/findCycles.d.ts.map +1 -0
  218. package/esm/methods/findCycles.js +330 -0
  219. package/esm/methods/fuzzyClean.d.ts.map +1 -1
  220. package/esm/methods/fuzzyClean.js +17 -136
  221. package/esm/methods/fuzzyJoin.js +70 -16
  222. package/esm/methods/getTypes.d.ts +1 -1
  223. package/esm/methods/hdbscan.d.ts +5 -0
  224. package/esm/methods/hdbscan.d.ts.map +1 -0
  225. package/esm/methods/hdbscan.js +208 -0
  226. package/esm/methods/loadArray.d.ts.map +1 -1
  227. package/esm/methods/loadArray.js +3 -20
  228. package/esm/methods/mahalanobis.d.ts +5 -0
  229. package/esm/methods/mahalanobis.d.ts.map +1 -0
  230. package/esm/methods/mahalanobis.js +92 -0
  231. package/esm/methods/neighbors.d.ts +9 -0
  232. package/esm/methods/neighbors.d.ts.map +1 -0
  233. package/esm/methods/neighbors.js +81 -0
  234. package/esm/methods/normalizeVector.d.ts +5 -0
  235. package/esm/methods/normalizeVector.d.ts.map +1 -0
  236. package/esm/methods/normalizeVector.js +132 -0
  237. package/esm/methods/paths.d.ts +12 -0
  238. package/esm/methods/paths.d.ts.map +1 -0
  239. package/esm/methods/paths.js +287 -0
  240. package/esm/methods/reachable.d.ts +11 -0
  241. package/esm/methods/reachable.d.ts.map +1 -0
  242. package/esm/methods/reachable.js +131 -0
  243. package/esm/methods/rowToVector.d.ts +5 -0
  244. package/esm/methods/rowToVector.d.ts.map +1 -0
  245. package/esm/methods/rowToVector.js +77 -0
  246. package/esm/methods/shortestPath.d.ts +12 -0
  247. package/esm/methods/shortestPath.d.ts.map +1 -0
  248. package/esm/methods/shortestPath.js +337 -0
  249. package/esm/methods/topologicalSort.d.ts +7 -0
  250. package/esm/methods/topologicalSort.d.ts.map +1 -0
  251. package/esm/methods/topologicalSort.js +164 -0
  252. package/esm/methods/umap.d.ts +5 -0
  253. package/esm/methods/umap.d.ts.map +1 -0
  254. package/esm/methods/umap.js +156 -0
  255. package/esm/methods/updateWithJS.js +9 -21
  256. package/llm.md +2170 -128
  257. package/llms.txt +1 -1
  258. package/package.json +1 -1
  259. package/script/class/SDAError.d.ts +6 -6
  260. package/script/class/SDAError.js +6 -6
  261. package/script/class/Simple.d.ts +9 -9
  262. package/script/class/Simple.js +9 -9
  263. package/script/class/SimpleDB.d.ts +80 -76
  264. package/script/class/SimpleDB.d.ts.map +1 -1
  265. package/script/class/SimpleDB.js +80 -76
  266. package/script/class/SimpleTable.d.ts +2805 -1077
  267. package/script/class/SimpleTable.d.ts.map +1 -1
  268. package/script/class/SimpleTable.js +2777 -1077
  269. package/script/helpers/appendColumnBatches.d.ts +3 -0
  270. package/script/helpers/appendColumnBatches.d.ts.map +1 -0
  271. package/script/helpers/appendColumnBatches.js +24 -0
  272. package/script/helpers/buildApproximateMutualReachabilityMst.d.ts +45 -0
  273. package/script/helpers/buildApproximateMutualReachabilityMst.d.ts.map +1 -0
  274. package/script/helpers/buildApproximateMutualReachabilityMst.js +219 -0
  275. package/script/helpers/buildChronologicalGraphComponentsSql.d.ts +14 -0
  276. package/script/helpers/buildChronologicalGraphComponentsSql.d.ts.map +1 -0
  277. package/script/helpers/buildChronologicalGraphComponentsSql.js +174 -0
  278. package/script/helpers/buildExactMutualReachabilityMst.d.ts +28 -0
  279. package/script/helpers/buildExactMutualReachabilityMst.d.ts.map +1 -0
  280. package/script/helpers/buildExactMutualReachabilityMst.js +103 -0
  281. package/script/helpers/buildGraphTemporalCostStateSql.d.ts +12 -0
  282. package/script/helpers/buildGraphTemporalCostStateSql.d.ts.map +1 -0
  283. package/script/helpers/buildGraphTemporalCostStateSql.js +92 -0
  284. package/script/helpers/buildGraphTemporalReachabilitySql.d.ts +13 -0
  285. package/script/helpers/buildGraphTemporalReachabilitySql.d.ts.map +1 -0
  286. package/script/helpers/buildGraphTemporalReachabilitySql.js +76 -0
  287. package/script/helpers/buildSparseMutualReachabilityMst.d.ts +10 -0
  288. package/script/helpers/buildSparseMutualReachabilityMst.d.ts.map +1 -0
  289. package/script/helpers/buildSparseMutualReachabilityMst.js +50 -0
  290. package/script/helpers/buildUmapGraph.d.ts +21 -0
  291. package/script/helpers/buildUmapGraph.d.ts.map +1 -0
  292. package/script/helpers/buildUmapGraph.js +67 -0
  293. package/script/helpers/buildVectorNeighbors.d.ts +45 -0
  294. package/script/helpers/buildVectorNeighbors.d.ts.map +1 -0
  295. package/script/helpers/buildVectorNeighbors.js +176 -0
  296. package/script/helpers/buildWeakGraphComponentsSql.d.ts +3 -0
  297. package/script/helpers/buildWeakGraphComponentsSql.d.ts.map +1 -0
  298. package/script/helpers/buildWeakGraphComponentsSql.js +38 -0
  299. package/script/helpers/cacheDatabase.d.ts.map +1 -1
  300. package/script/helpers/cacheDatabase.js +2 -1
  301. package/script/helpers/camelCase.d.ts +7 -5
  302. package/script/helpers/camelCase.d.ts.map +1 -1
  303. package/script/helpers/camelCase.js +7 -5
  304. package/script/helpers/capitalize.d.ts +6 -4
  305. package/script/helpers/capitalize.d.ts.map +1 -1
  306. package/script/helpers/capitalize.js +6 -4
  307. package/script/helpers/clusterHdbscan.d.ts +18 -0
  308. package/script/helpers/clusterHdbscan.d.ts.map +1 -0
  309. package/script/helpers/clusterHdbscan.js +346 -0
  310. package/script/helpers/computeCovariance.d.ts +16 -0
  311. package/script/helpers/computeCovariance.d.ts.map +1 -0
  312. package/script/helpers/computeCovariance.js +105 -0
  313. package/script/helpers/computeMahalanobisDistances.d.ts +14 -0
  314. package/script/helpers/computeMahalanobisDistances.d.ts.map +1 -0
  315. package/script/helpers/computeMahalanobisDistances.js +93 -0
  316. package/script/helpers/createDirectory.d.ts +4 -3
  317. package/script/helpers/createDirectory.d.ts.map +1 -1
  318. package/script/helpers/createDirectory.js +4 -3
  319. package/script/helpers/dataToArrays.d.ts +6 -4
  320. package/script/helpers/dataToArrays.d.ts.map +1 -1
  321. package/script/helpers/dataToArrays.js +6 -4
  322. package/script/helpers/extractTypes.d.ts +1 -1
  323. package/script/helpers/extractTypes.js +4 -9
  324. package/script/helpers/factorCovariance.d.ts +17 -0
  325. package/script/helpers/factorCovariance.d.ts.map +1 -0
  326. package/script/helpers/factorCovariance.js +194 -0
  327. package/script/helpers/findGeoColumn.d.ts +6 -4
  328. package/script/helpers/findGeoColumn.d.ts.map +1 -1
  329. package/script/helpers/findGeoColumn.js +6 -4
  330. package/script/helpers/findGeoColumnFromSchema.d.ts +8 -5
  331. package/script/helpers/findGeoColumnFromSchema.d.ts.map +1 -1
  332. package/script/helpers/findGeoColumnFromSchema.js +8 -5
  333. package/script/helpers/fitUmapCurve.d.ts +2 -0
  334. package/script/helpers/fitUmapCurve.d.ts.map +1 -0
  335. package/script/helpers/fitUmapCurve.js +69 -0
  336. package/script/helpers/formatDate.d.ts +12 -6
  337. package/script/helpers/formatDate.d.ts.map +1 -1
  338. package/script/helpers/formatDate.js +12 -6
  339. package/script/helpers/formatMissingTables.d.ts +8 -5
  340. package/script/helpers/formatMissingTables.d.ts.map +1 -1
  341. package/script/helpers/formatMissingTables.js +8 -5
  342. package/script/helpers/formatNumber.d.ts +19 -10
  343. package/script/helpers/formatNumber.d.ts.map +1 -1
  344. package/script/helpers/formatNumber.js +32 -17
  345. package/script/helpers/getGraphEdgeIdColumn.d.ts +9 -0
  346. package/script/helpers/getGraphEdgeIdColumn.d.ts.map +1 -0
  347. package/script/helpers/getGraphEdgeIdColumn.js +31 -0
  348. package/script/helpers/getGraphEndpointColumns.d.ts +11 -0
  349. package/script/helpers/getGraphEndpointColumns.d.ts.map +1 -0
  350. package/script/helpers/getGraphEndpointColumns.js +166 -0
  351. package/script/helpers/getGraphWeightColumn.d.ts +10 -0
  352. package/script/helpers/getGraphWeightColumn.d.ts.map +1 -0
  353. package/script/helpers/getGraphWeightColumn.js +46 -0
  354. package/script/helpers/graphRouteResultSchema.d.ts +4 -0
  355. package/script/helpers/graphRouteResultSchema.d.ts.map +1 -0
  356. package/script/helpers/graphRouteResultSchema.js +18 -0
  357. package/script/helpers/graphRouteResultSelect.d.ts +4 -0
  358. package/script/helpers/graphRouteResultSelect.d.ts.map +1 -0
  359. package/script/helpers/graphRouteResultSelect.js +28 -0
  360. package/script/helpers/hasGeometryColumn.d.ts +4 -3
  361. package/script/helpers/hasGeometryColumn.d.ts.map +1 -1
  362. package/script/helpers/hasGeometryColumn.js +4 -3
  363. package/script/helpers/initialUmapCoordinates.d.ts +2 -0
  364. package/script/helpers/initialUmapCoordinates.d.ts.map +1 -0
  365. package/script/helpers/initialUmapCoordinates.js +11 -0
  366. package/script/helpers/inspectGraphConnectivity.d.ts +10 -0
  367. package/script/helpers/inspectGraphConnectivity.d.ts.map +1 -0
  368. package/script/helpers/inspectGraphConnectivity.js +58 -0
  369. package/script/helpers/mergeOptions.d.ts +24 -13
  370. package/script/helpers/mergeOptions.d.ts.map +1 -1
  371. package/script/helpers/mergeOptions.js +24 -13
  372. package/script/helpers/optimizeUmapLayout.d.ts +7 -0
  373. package/script/helpers/optimizeUmapLayout.d.ts.map +1 -0
  374. package/script/helpers/optimizeUmapLayout.js +99 -0
  375. package/script/helpers/parseValue.d.ts +6 -4
  376. package/script/helpers/parseValue.d.ts.map +1 -1
  377. package/script/helpers/parseValue.js +6 -4
  378. package/script/helpers/prepareGraphRouteSql.d.ts +31 -0
  379. package/script/helpers/prepareGraphRouteSql.d.ts.map +1 -0
  380. package/script/helpers/prepareGraphRouteSql.js +127 -0
  381. package/script/helpers/prepareGraphStarts.d.ts +9 -0
  382. package/script/helpers/prepareGraphStarts.d.ts.map +1 -0
  383. package/script/helpers/prepareGraphStarts.js +71 -0
  384. package/script/helpers/prepareGraphTemporalSql.d.ts +28 -0
  385. package/script/helpers/prepareGraphTemporalSql.d.ts.map +1 -0
  386. package/script/helpers/prepareGraphTemporalSql.js +161 -0
  387. package/script/helpers/prepareGraphTraversal.d.ts +19 -0
  388. package/script/helpers/prepareGraphTraversal.d.ts.map +1 -0
  389. package/script/helpers/prepareGraphTraversal.js +87 -0
  390. package/script/helpers/prepareNumericFeatures.d.ts +41 -0
  391. package/script/helpers/prepareNumericFeatures.d.ts.map +1 -0
  392. package/script/helpers/prepareNumericFeatures.js +217 -0
  393. package/script/helpers/prepareUmapLayoutOptions.d.ts +14 -0
  394. package/script/helpers/prepareUmapLayoutOptions.d.ts.map +1 -0
  395. package/script/helpers/prepareUmapLayoutOptions.js +29 -0
  396. package/script/helpers/prettyDuration.d.ts +14 -8
  397. package/script/helpers/prettyDuration.d.ts.map +1 -1
  398. package/script/helpers/prettyDuration.js +14 -8
  399. package/script/helpers/printTable.d.ts +18 -13
  400. package/script/helpers/printTable.d.ts.map +1 -1
  401. package/script/helpers/printTable.js +18 -13
  402. package/script/helpers/publishPreparedColumns.d.ts +37 -0
  403. package/script/helpers/publishPreparedColumns.d.ts.map +1 -0
  404. package/script/helpers/publishPreparedColumns.js +119 -0
  405. package/script/helpers/queryDB.d.ts +24 -13
  406. package/script/helpers/queryDB.d.ts.map +1 -1
  407. package/script/helpers/queryDB.js +24 -13
  408. package/script/helpers/queueAsyncBarrier.d.ts +12 -7
  409. package/script/helpers/queueAsyncBarrier.d.ts.map +1 -1
  410. package/script/helpers/queueAsyncBarrier.js +12 -7
  411. package/script/helpers/queueGraphResult.d.ts +18 -0
  412. package/script/helpers/queueGraphResult.d.ts.map +1 -0
  413. package/script/helpers/queueGraphResult.js +45 -0
  414. package/script/helpers/quoteIdentifier.d.ts +4 -3
  415. package/script/helpers/quoteIdentifier.d.ts.map +1 -1
  416. package/script/helpers/quoteIdentifier.js +4 -3
  417. package/script/helpers/quoteQualifiedIdentifier.d.ts +6 -4
  418. package/script/helpers/quoteQualifiedIdentifier.d.ts.map +1 -1
  419. package/script/helpers/quoteQualifiedIdentifier.js +6 -4
  420. package/script/helpers/readScalarNumber.d.ts +3 -0
  421. package/script/helpers/readScalarNumber.d.ts.map +1 -0
  422. package/script/helpers/readScalarNumber.js +7 -0
  423. package/script/helpers/runQuery.d.ts.map +1 -1
  424. package/script/helpers/runQuery.js +17 -3
  425. package/script/helpers/selectFuzzyReplacements.d.ts +11 -0
  426. package/script/helpers/selectFuzzyReplacements.d.ts.map +1 -0
  427. package/script/helpers/selectFuzzyReplacements.js +127 -0
  428. package/script/helpers/stabilizeCosineVectors.d.ts +14 -0
  429. package/script/helpers/stabilizeCosineVectors.d.ts.map +1 -0
  430. package/script/helpers/stabilizeCosineVectors.js +40 -0
  431. package/script/helpers/stringToArray.d.ts +4 -3
  432. package/script/helpers/stringToArray.d.ts.map +1 -1
  433. package/script/helpers/stringToArray.js +4 -3
  434. package/script/helpers/umapRandom.d.ts +2 -0
  435. package/script/helpers/umapRandom.d.ts.map +1 -0
  436. package/script/helpers/umapRandom.js +13 -0
  437. package/script/helpers/updateColumnsWithJS.d.ts +12 -6
  438. package/script/helpers/updateColumnsWithJS.d.ts.map +1 -1
  439. package/script/helpers/updateColumnsWithJS.js +12 -6
  440. package/script/helpers/validateGraphRouteResultSchema.d.ts +4 -0
  441. package/script/helpers/validateGraphRouteResultSchema.d.ts.map +1 -0
  442. package/script/helpers/validateGraphRouteResultSchema.js +19 -0
  443. package/script/helpers/validateGraphTemporalEvents.d.ts +7 -0
  444. package/script/helpers/validateGraphTemporalEvents.d.ts.map +1 -0
  445. package/script/helpers/validateGraphTemporalEvents.js +53 -0
  446. package/script/helpers/validateNumericalAnalysis.d.ts +10 -6
  447. package/script/helpers/validateNumericalAnalysis.d.ts.map +1 -1
  448. package/script/helpers/validateNumericalAnalysis.js +10 -6
  449. package/script/helpers/validateVectorRowIds.d.ts +4 -0
  450. package/script/helpers/validateVectorRowIds.d.ts.map +1 -0
  451. package/script/helpers/validateVectorRowIds.js +19 -0
  452. package/script/helpers/vectorDistanceExpression.d.ts +6 -0
  453. package/script/helpers/vectorDistanceExpression.d.ts.map +1 -0
  454. package/script/helpers/vectorDistanceExpression.js +14 -0
  455. package/script/helpers/wrapString.d.ts +10 -7
  456. package/script/helpers/wrapString.d.ts.map +1 -1
  457. package/script/helpers/wrapString.js +10 -7
  458. package/script/methods/addId.d.ts +5 -0
  459. package/script/methods/addId.d.ts.map +1 -0
  460. package/script/methods/addId.js +44 -0
  461. package/script/methods/cache.js +1 -1
  462. package/script/methods/commonNeighbors.d.ts +10 -0
  463. package/script/methods/commonNeighbors.d.ts.map +1 -0
  464. package/script/methods/commonNeighbors.js +140 -0
  465. package/script/methods/connectedComponents.d.ts +9 -0
  466. package/script/methods/connectedComponents.d.ts.map +1 -0
  467. package/script/methods/connectedComponents.js +186 -0
  468. package/script/methods/degree.d.ts +9 -0
  469. package/script/methods/degree.d.ts.map +1 -0
  470. package/script/methods/degree.js +141 -0
  471. package/script/methods/distances.d.ts +12 -0
  472. package/script/methods/distances.d.ts.map +1 -0
  473. package/script/methods/distances.js +203 -0
  474. package/script/methods/findCycles.d.ts +12 -0
  475. package/script/methods/findCycles.d.ts.map +1 -0
  476. package/script/methods/findCycles.js +369 -0
  477. package/script/methods/fuzzyClean.d.ts.map +1 -1
  478. package/script/methods/fuzzyClean.js +17 -136
  479. package/script/methods/fuzzyJoin.js +70 -16
  480. package/script/methods/getTypes.d.ts +1 -1
  481. package/script/methods/hdbscan.d.ts +5 -0
  482. package/script/methods/hdbscan.d.ts.map +1 -0
  483. package/script/methods/hdbscan.js +214 -0
  484. package/script/methods/loadArray.d.ts.map +1 -1
  485. package/script/methods/loadArray.js +2 -19
  486. package/script/methods/mahalanobis.d.ts +5 -0
  487. package/script/methods/mahalanobis.d.ts.map +1 -0
  488. package/script/methods/mahalanobis.js +98 -0
  489. package/script/methods/neighbors.d.ts +9 -0
  490. package/script/methods/neighbors.d.ts.map +1 -0
  491. package/script/methods/neighbors.js +120 -0
  492. package/script/methods/normalizeVector.d.ts +5 -0
  493. package/script/methods/normalizeVector.d.ts.map +1 -0
  494. package/script/methods/normalizeVector.js +138 -0
  495. package/script/methods/paths.d.ts +12 -0
  496. package/script/methods/paths.d.ts.map +1 -0
  497. package/script/methods/paths.js +326 -0
  498. package/script/methods/reachable.d.ts +11 -0
  499. package/script/methods/reachable.d.ts.map +1 -0
  500. package/script/methods/reachable.js +170 -0
  501. package/script/methods/rowToVector.d.ts +5 -0
  502. package/script/methods/rowToVector.d.ts.map +1 -0
  503. package/script/methods/rowToVector.js +83 -0
  504. package/script/methods/shortestPath.d.ts +12 -0
  505. package/script/methods/shortestPath.d.ts.map +1 -0
  506. package/script/methods/shortestPath.js +376 -0
  507. package/script/methods/topologicalSort.d.ts +7 -0
  508. package/script/methods/topologicalSort.d.ts.map +1 -0
  509. package/script/methods/topologicalSort.js +170 -0
  510. package/script/methods/umap.d.ts +5 -0
  511. package/script/methods/umap.d.ts.map +1 -0
  512. package/script/methods/umap.js +162 -0
  513. package/script/methods/updateWithJS.js +9 -21
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.8`
4
+ - Version: `2.1.0`
5
5
 
6
6
  To install the library with Deno, use:
7
7
 
@@ -1451,6 +1451,159 @@ await table.createVssIndex("embedding_column", {
1451
1451
  }).log();
1452
1452
  ```
1453
1453
 
1454
+ #### `umap`
1455
+
1456
+ Reduces numeric vectors, such as embeddings, to a two-dimensional UMAP
1457
+ projection. The resulting coordinates are added as `umapX` and `umapY`, while
1458
+ all existing columns (including the source vector column), their values and
1459
+ types, and the input row order are preserved. DuckDB computes neighbors and the
1460
+ fuzzy graph; TypeScript optimizes the coordinates without copying the input
1461
+ vectors into JavaScript. Neighbor search is selected automatically.
1462
+
1463
+ The defaults are a starting point for exploration. To adjust the projection:
1464
+
1465
+ - `neighbors` (default `15`): How many nearby points influence the layout.
1466
+ Smaller values emphasize local detail but can fragment groups. Larger values
1467
+ emphasize broader structure, can hide local detail, and generally require more
1468
+ time and memory.
1469
+ - `metric` (default `"euclidean"`): How similarity is measured. Euclidean
1470
+ compares distance, including differences in vector magnitude. Cosine compares
1471
+ direction, ignoring magnitude. Choose according to what makes vectors similar
1472
+ in your data; neither is universally better.
1473
+ - `epochs` (default `200`): How many passes refine the coordinates. Fewer passes
1474
+ finish sooner but may leave the layout unfinished. More passes allow further
1475
+ refinement and take longer, with diminishing returns.
1476
+ - `minDistance` (default `0.1`): How tightly points can group in the projection.
1477
+ Smaller values allow tighter clumps; larger values spread points out. This
1478
+ changes the layout's appearance, not an accuracy level or the number of
1479
+ optimization passes.
1480
+ - `learningRate` (default `1`): The initial size of coordinate adjustments.
1481
+ Smaller values make gentler adjustments and may need more epochs. Larger
1482
+ values make bigger adjustments but can overshoot useful positions. This does
1483
+ not change the number of passes.
1484
+ - `negativeSamples` (default `5`): How many random points are sampled for
1485
+ repulsion per attractive update. Smaller values reduce work and repulsion;
1486
+ larger values increase both, tending to separate unrelated points more
1487
+ strongly. More samples do not guarantee a better projection.
1488
+
1489
+ ##### Signature
1490
+
1491
+ ```typescript
1492
+ umap(column: string, options?: { neighbors?: number; metric?: "euclidean" | "cosine"; epochs?: number; seed?: number; minDistance?: number; learningRate?: number; negativeSamples?: number }): this;
1493
+ ```
1494
+
1495
+ ##### Parameters
1496
+
1497
+ - **`column`**: The column containing numeric vector embeddings.
1498
+ - **`options`**: Optional projection settings.
1499
+ - **`options.neighbors`**: Neighborhood size, including the point itself.
1500
+ Integer of at least 2, clamped to row count minus one. Defaults to 15.
1501
+ - **`options.metric`**: Input distance metric: "euclidean" or "cosine". Defaults
1502
+ to "euclidean".
1503
+ - **`options.epochs`**: Integer number of refinement passes, at least 1.
1504
+ Defaults to 200.
1505
+ - **`options.seed`**: Integer used to initialize random choices. Defaults to 42.
1506
+ - **`options.minDistance`**: Grouping distance parameter between 0 and 1.
1507
+ Defaults to 0.1.
1508
+ - **`options.learningRate`**: Finite, positive initial learning rate. Defaults
1509
+ to 1.
1510
+ - **`options.negativeSamples`**: Integer number of samples used to separate
1511
+ unrelated points, at least 1. Defaults to 5.
1512
+
1513
+ ##### Returns
1514
+
1515
+ The table, so methods can be chained.
1516
+
1517
+ ##### Examples
1518
+
1519
+ ```ts
1520
+ await table.umap("embedding", {
1521
+ metric: "cosine",
1522
+ seed: 42,
1523
+ }).log();
1524
+ ```
1525
+
1526
+ ```ts
1527
+ await table.umap("embedding", {
1528
+ neighbors: 30,
1529
+ minDistance: 0.25,
1530
+ }).selectColumns(["label", "umapX", "umapY"]).log();
1531
+ ```
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
+
1454
1607
  #### `bm25`
1455
1608
 
1456
1609
  Searches a text column using DuckDB's BM25 ranking function, which scores
@@ -2849,31 +3002,28 @@ await table.loadArray([{ count: 3 }])
2849
3002
  .log();
2850
3003
  ```
2851
3004
 
2852
- #### `extractDatePart`
3005
+ #### `addId`
2853
3006
 
2854
- Extracts one or more components from a temporal column into new columns. Pass a
2855
- single part to create a column with that part's name, or pass an object mapping
2856
- 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.
2857
3012
 
2858
- `dayOfWeek` uses Sunday as `0` through Saturday as `6`. `week` follows ISO week
2859
- numbering, and `dayOfYear` starts at `1`. DuckDB `DATE`, `TIME`, `TIMESTAMP`,
2860
- and `TIMESTAMP WITH TIME ZONE` columns are supported when the requested
2861
- component applies to that type: date parts apply to dates and timestamps, while
2862
- time parts apply to times and timestamps. `NULL` input values produce `NULL`
2863
- extracted values. Parts extracted from `TIMESTAMP WITH TIME ZONE` values use
2864
- UTC.
3013
+ IDs are not globally unique: separate tables can generate the same IDs.
2865
3014
 
2866
3015
  ##### Signature
2867
3016
 
2868
3017
  ```typescript
2869
- 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;
2870
3019
  ```
2871
3020
 
2872
3021
  ##### Parameters
2873
3022
 
2874
- - **`column`**: The temporal column from which to extract components.
2875
- - **`parts`**: A part to extract using its name as the new column, or an object
2876
- 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.
2877
3027
 
2878
3028
  ##### Returns
2879
3029
 
@@ -2882,210 +3032,1956 @@ The table, so methods can be chained.
2882
3032
  ##### Examples
2883
3033
 
2884
3034
  ```ts
2885
- // Add a column named 'year' from the 'publishedAt' timestamp
2886
- await table.extractDatePart("publishedAt", "year").log();
3035
+ // Add numeric IDs: 0, 1, 2, ...
3036
+ await table
3037
+ .addId("edgeId")
3038
+ .log();
2887
3039
  ```
2888
3040
 
2889
3041
  ```ts
2890
- // Extract multiple components with custom column names
2891
- await table.extractDatePart("publishedAt", {
2892
- publicationYear: "year",
2893
- publicationMonth: "month",
2894
- }).log();
3042
+ // Add string IDs: "flight-0", "flight-1", "flight-2", ...
3043
+ await flights
3044
+ .addId("edgeId", { prefix: "flight-" })
3045
+ .log();
2895
3046
  ```
2896
3047
 
2897
- #### `addRowNumber`
3048
+ #### `neighbors`
2898
3049
 
2899
- Adds a new column to the table containing the row number, starting at 0 (like an
2900
- 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:
2901
3068
 
2902
3069
  ##### Signature
2903
3070
 
2904
3071
  ```typescript
2905
- 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;
2906
3073
  ```
2907
3074
 
2908
3075
  ##### Parameters
2909
3076
 
2910
- - **`newColumn`**: The name of the new column that will store the row number.
2911
- - **`options`**: An optional object with configuration options:
2912
- - **`options.by`**: A column name or an array of column names to partition by.
2913
- 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`.
2914
3089
 
2915
3090
  ##### Returns
2916
3091
 
2917
- The table, so methods can be chained.
3092
+ The result table, so methods can be chained.
2918
3093
 
2919
3094
  ##### Examples
2920
3095
 
2921
3096
  ```ts
2922
- // Add a new column named 'rowNumber' with the row number for each row
2923
- await table.addRowNumber("rowNumber").log();
3097
+ await table
3098
+ .neighbors("origin", "destination", "A")
3099
+ .log();
2924
3100
  ```
2925
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
+
2926
3111
  ```ts
2927
- // Add a new column named 'rowNumber' with the row number for each 'category'
2928
- await table.addRowNumber("rowNumber", { by: "category" }).log();
3112
+ await table
3113
+ .neighbors("origin", "destination", "A", { direction: "incoming" })
3114
+ .log();
2929
3115
  ```
2930
3116
 
2931
- #### `crossJoin`
3117
+ | start | node |
3118
+ | ----- | ---- |
3119
+ | A | C |
2932
3120
 
2933
- Performs a cross join operation with another table. A cross join returns the
2934
- Cartesian product of the rows from both tables, meaning all possible pairs of
2935
- rows will be in the resulting table. This means that if the left table has `n`
2936
- 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:
2937
3180
 
2938
3181
  ##### Signature
2939
3182
 
2940
3183
  ```typescript
2941
- crossJoin(rightTable: SimpleTable, options?: { outputTable?: string | boolean }): this;
3184
+ degree(sourceColumn: string, targetColumn: string, options?: { count?: "edges" | "neighbors"; weight?: string; outputTable?: string | boolean }): SimpleTable;
2942
3185
  ```
2943
3186
 
2944
3187
  ##### Parameters
2945
3188
 
2946
- - **`rightTable`**: The SimpleTable instance to cross join with.
2947
- - **`options`**: An optional object with configuration options:
2948
- - **`options.outputTable`**: If `true`, the results will be stored in a new
2949
- table with a generated name. If a string, it will be used as the name for the
2950
- new table. If `false` or omitted, the current table will be overwritten.
2951
- 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`.
2952
3201
 
2953
3202
  ##### Returns
2954
3203
 
2955
- A table instance containing the cross-joined data (either the current table or a
2956
- new table), so methods can be chained.
3204
+ The result table, so methods can be chained.
2957
3205
 
2958
3206
  ##### Examples
2959
3207
 
2960
3208
  ```ts
2961
- // Perform a cross join with 'tableB', overwriting the current table (tableA)
2962
- await tableA.crossJoin(tableB).log();
3209
+ await flights
3210
+ .degree("origin", "destination")
3211
+ .log();
2963
3212
  ```
2964
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
+
2965
3223
  ```ts
2966
- // Perform a cross join with 'tableB' and store the results in a new table with a generated name
2967
- const tableC = await tableA.crossJoin(tableB, { outputTable: true }).log();
3224
+ await flights
3225
+ .degree("origin", "destination", { count: "neighbors" })
3226
+ .log();
2968
3227
  ```
2969
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
+
2970
3238
  ```ts
2971
- // Perform a cross join with 'tableB' and store the results in a new table named 'tableC'
2972
- const tableC = await tableA.crossJoin(tableB, { outputTable: "tableC" }).log();
3239
+ await flights
3240
+ .degree("origin", "destination", { weight: "passengers" })
3241
+ .log();
2973
3242
  ```
2974
3243
 
2975
- #### `join`
3244
+ | node | incoming | outgoing | total |
3245
+ | --------- | -------: | -------: | ----: |
3246
+ | Montreal | 150 | 350 | 500 |
3247
+ | Toronto | 300 | 150 | 450 |
3248
+ | Vancouver | 50 | 0 | 50 |
2976
3249
 
2977
- Merges the data of this table (considered the left table) with another table
2978
- (the right table) based on a common column or multiple columns. Note that the
2979
- order of rows in the returned data is not guaranteed to be the same as in the
2980
- original tables. This operation might create temporary files in a `.tmp` folder;
2981
- 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:
2982
3292
 
2983
3293
  ##### Signature
2984
3294
 
2985
3295
  ```typescript
2986
- 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;
2987
3297
  ```
2988
3298
 
2989
3299
  ##### Parameters
2990
3300
 
2991
- - **`rightTable`**: The SimpleTable instance to be joined with this table.
2992
- - **`options`**: An optional object with configuration options:
2993
- - **`options.on`**: The column(s) to join on. If omitted, the method
2994
- automatically searches for a column name that exists in both tables. Can be a
2995
- single string or an array of strings for multiple join keys.
2996
- - **`options.type`**: The type of join operation to perform. Possible values are
2997
- `"inner"`, `"left"` (default), `"right"`, or `"full"`.
2998
- - **`options.outputTable`**: If `true`, the results will be stored in a new
2999
- table with a generated name. If a string, it will be used as the name for the
3000
- new table. If `false` or omitted, the current table will be overwritten.
3001
- 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`.
3002
3313
 
3003
3314
  ##### Returns
3004
3315
 
3005
- A table instance containing the joined data (either the current table or a new
3006
- table), so methods can be chained.
3316
+ The result table, so methods can be chained.
3007
3317
 
3008
3318
  ##### Examples
3009
3319
 
3010
3320
  ```ts
3011
- // Perform a left join with 'tableB' on a common column (auto-detected), overwriting tableA
3012
- await tableA.join(tableB).log();
3321
+ await connections
3322
+ .commonNeighbors("origin", "destination", "A", "B")
3323
+ .log();
3013
3324
  ```
3014
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
+
3015
3335
  ```ts
3016
- // Perform an inner join with 'tableB' on the 'id' column, storing results in a new table named 'tableC'
3017
- const tableC = await tableA.join(tableB, {
3018
- on: "id",
3019
- type: "inner",
3020
- outputTable: "tableC",
3021
- }).log();
3336
+ await connections
3337
+ .commonNeighbors("origin", "destination", "A", "B", { direction: "incoming" })
3338
+ .log();
3022
3339
  ```
3023
3340
 
3341
+ | node |
3342
+ | ---- |
3343
+ | D |
3344
+
3345
+ With `direction: "both"`, the method finds shared neighbors in either direction:
3346
+
3024
3347
  ```ts
3025
- // Perform a join on multiple columns ('name' and 'category')
3026
- await tableA.join(tableB, { on: ["name", "category"] }).log();
3348
+ await connections
3349
+ .commonNeighbors("origin", "destination", "A", "B", { direction: "both" })
3350
+ .log();
3027
3351
  ```
3028
3352
 
3029
- #### `fuzzyJoin`
3353
+ | node |
3354
+ | ---- |
3355
+ | C |
3356
+ | D |
3030
3357
 
3031
- Performs a fuzzy left join between this table (considered the left table) and
3032
- another table (the right table) based on string similarity between two text
3033
- columns. Uses the [rapidfuzz](https://query.farm/duckdb_extension_rapidfuzz)
3034
- 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:
3035
3360
 
3036
- If a similarity score column is added to the results, the rows will be ordered
3037
- alphabetically by the left column, and then by descending similarity score
3038
- within each group of identical left column values. Otherwise, the rows will be
3039
- order alphabetically by the left column and then by the right column.
3361
+ | source | target |
3362
+ | ------ | ------ |
3363
+ | A | A |
3364
+ | B | A |
3040
3365
 
3041
- This operation might create temporary files in a `.tmp` folder; consider adding
3042
- `.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:
3043
3411
 
3044
3412
  ##### Signature
3045
3413
 
3046
3414
  ```typescript
3047
- 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;
3048
3416
  ```
3049
3417
 
3050
3418
  ##### Parameters
3051
3419
 
3052
- - **`rightTable`**: The SimpleTable instance to be joined with this table.
3053
- - **`leftColumn`**: The name of the column in this (left) table containing the
3054
- text to compare.
3055
- - **`rightColumn`**: The name of the column in the right table containing the
3056
- text to compare.
3057
- - **`threshold`**: The minimum similarity score (0–100) required for two rows to
3058
- be joined. For `method: "ratio"`, a length-based pre-filter is automatically
3059
- applied based on the threshold to improve performance without losing accuracy.
3060
- - **`options`**: An optional object with configuration options:
3061
- - **`options.method`**: The rapidfuzz similarity algorithm to use. Defaults to
3062
- `"ratio"`. - `"ratio"`: Overall similarity (Levenshtein-based). -
3063
- `"partial_ratio"`: Best partial/substring similarity. - `"token_sort_ratio"`:
3064
- Similarity after sorting tokens (words), useful for reordered words. -
3065
- `"token_set_ratio"`: Similarity based on sets of tokens, ignoring duplicates
3066
- and word order.
3067
- - **`options.similarityColumn`**: If provided, a column with this name is added
3068
- to the result containing the similarity score (0–100). If omitted, the score
3069
- is not included in the output.
3070
- - **`options.outputTable`**: If `true`, the results will be stored in a new
3071
- table with a generated name. If a string, it will be used as the name for the
3072
- new table. If `false` or omitted, the current table will be overwritten.
3073
- Defaults to `false`.
3074
- - **`options.prefilterPrefixLength`**: An optional prefix length. Only strings
3075
- sharing the same first N characters are compared. Note that prefix filtering
3076
- 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`.
3077
3445
 
3078
3446
  ##### Returns
3079
3447
 
3080
- A table instance containing the fuzzy-joined data (either the current table or a
3081
- new table), so methods can be chained.
3448
+ The result table, so methods can be chained.
3082
3449
 
3083
3450
  ##### Examples
3084
3451
 
3085
3452
  ```ts
3086
- // Fuzzy left join tableA with tableB on 'name' (left) and 'standardName' (right) with a threshold of 80
3087
- // A length-based pre-filter is automatically applied.
3088
- await tableA.fuzzyJoin(tableB, "name", "standardName", 80).log();
3453
+ await connections
3454
+ .reachable("origin", "destination", "A")
3455
+ .log();
3456
+ ```
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
+
3468
+ ```ts
3469
+ await connections
3470
+ .reachable("origin", "destination", "B", { direction: "incoming" })
3471
+ .log();
3472
+ ```
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
+
3483
+ ```ts
3484
+ await connections
3485
+ .reachable("origin", "destination", "B", { direction: "both" })
3486
+ .log();
3487
+ ```
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
+
3498
+ ```ts
3499
+ await connections
3500
+ .reachable("origin", "destination", ["B", "A"])
3501
+ .log();
3502
+ ```
3503
+
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 |
3514
+
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();
3089
4985
  ```
3090
4986
 
3091
4987
  ```ts
@@ -3717,6 +5613,152 @@ await table
3717
5613
  .rowToText(["name", "age", "salary"], "profile").log();
3718
5614
  ```
3719
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
+
3720
5762
  #### `unnest`
3721
5763
 
3722
5764
  Unnests (expands) rows by splitting a column's string values into multiple rows