rubydb 0.1.4 → 0.1.6

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 (469) hide show
  1. checksums.yaml +4 -4
  2. data/.github/PULL_REQUEST_TEMPLATE.md +15 -15
  3. data/.github/workflows/benchmark.yml +26 -26
  4. data/.github/workflows/compatibility.yml +63 -63
  5. data/.github/workflows/fuzz.yml +33 -33
  6. data/.github/workflows/lint.yml +21 -21
  7. data/.github/workflows/operations.yml +24 -24
  8. data/.github/workflows/production-validation.yml +111 -111
  9. data/.github/workflows/release.yml +77 -77
  10. data/.github/workflows/security.yml +39 -37
  11. data/.github/workflows/test.yml +26 -26
  12. data/.github/workflows/workload.yml +58 -58
  13. data/.gitignore +16 -5
  14. data/.rubocop.yml +50 -44
  15. data/.standard.yml +9 -14
  16. data/ARCHITECTURE.md +21 -21
  17. data/CHANGELOG.md +57 -27
  18. data/CODE_OF_CONDUCT.md +13 -13
  19. data/CONTRIBUTING.md +29 -29
  20. data/GOVERNANCE.md +16 -16
  21. data/Gemfile +18 -17
  22. data/Gemfile.lock +125 -71
  23. data/README.md +168 -12
  24. data/ROADMAP.md +27 -27
  25. data/Rakefile +76 -71
  26. data/SECURITY.md +54 -54
  27. data/SUPPORT.md +14 -14
  28. data/accelerator/bin/SHA256SUMS +6 -0
  29. data/accelerator/bin/rubydb-accelerator-darwin-amd64 +0 -0
  30. data/accelerator/bin/rubydb-accelerator-darwin-arm64 +0 -0
  31. data/accelerator/bin/rubydb-accelerator-linux-amd64 +0 -0
  32. data/accelerator/bin/rubydb-accelerator-linux-arm64 +0 -0
  33. data/accelerator/bin/rubydb-accelerator-windows-amd64.exe +0 -0
  34. data/accelerator/bin/rubydb-accelerator-windows-arm64.exe +0 -0
  35. data/accelerator/cmd/rubydb-accelerator/main.go +11 -0
  36. data/accelerator/go.mod +3 -0
  37. data/accelerator/internal/execution/aggregate.go +94 -0
  38. data/accelerator/internal/execution/distinct.go +22 -0
  39. data/accelerator/internal/execution/filter.go +73 -0
  40. data/accelerator/internal/execution/join.go +79 -0
  41. data/accelerator/internal/execution/operators.go +167 -0
  42. data/accelerator/internal/execution/scan.go +20 -0
  43. data/accelerator/internal/execution/sort.go +62 -0
  44. data/accelerator/internal/execution/types.go +136 -0
  45. data/accelerator/internal/execution/value.go +67 -0
  46. data/accelerator/internal/memory/arena.go +47 -0
  47. data/accelerator/internal/memory/reuse.go +22 -0
  48. data/accelerator/internal/metrics/registry.go +67 -0
  49. data/accelerator/internal/parallel/bounded_queue.go +56 -0
  50. data/accelerator/internal/parallel/scheduler.go +47 -0
  51. data/accelerator/internal/parallel/worker_pool.go +53 -0
  52. data/accelerator/internal/protocol/cancellation.go +48 -0
  53. data/accelerator/internal/protocol/columnar.go +263 -0
  54. data/accelerator/internal/protocol/frame.go +187 -0
  55. data/accelerator/internal/runtime/worker.go +521 -0
  56. data/accelerator/internal/storage/page_reader.go +81 -0
  57. data/accelerator/internal/storage/snapshot_scan.go +539 -0
  58. data/accelerator/internal/wal/checksum.go +13 -0
  59. data/accelerator/internal/wal/compression.go +41 -0
  60. data/accelerator/internal/wal/group_commit.go +24 -0
  61. data/accelerator/internal/wal/record_encoder.go +40 -0
  62. data/adapters/activerecord/Gemfile +11 -11
  63. data/adapters/activerecord/README.md +8 -3
  64. data/adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb +881 -879
  65. data/adapters/activerecord/rubydb-activerecord.gemspec +21 -21
  66. data/adapters/activerecord/spec/rubydb_adapter_integration_spec.rb +143 -143
  67. data/adapters/ruby/README.md +18 -18
  68. data/adapters/sequel/README.md +11 -11
  69. data/config/monitoring/prometheus-alerts.yml +39 -39
  70. data/config/production.yml +36 -36
  71. data/docs/README.md +77 -71
  72. data/docs/architecture/concurrency.md +14 -14
  73. data/docs/architecture/current-state.md +125 -125
  74. data/docs/architecture/execution-engine.md +25 -25
  75. data/docs/architecture/go-accelerator.md +179 -0
  76. data/docs/architecture/indexes.md +19 -19
  77. data/docs/architecture/mvcc.md +19 -19
  78. data/docs/architecture/overview.md +13 -13
  79. data/docs/architecture/pages.md +11 -11
  80. data/docs/architecture/production-roadmap.md +82 -82
  81. data/docs/architecture/query-planner.md +20 -20
  82. data/docs/architecture/recovery.md +18 -18
  83. data/docs/architecture/sql-engine.md +12 -12
  84. data/docs/architecture/storage-engine.md +14 -14
  85. data/docs/architecture/transactions.md +10 -10
  86. data/docs/architecture/wal.md +28 -28
  87. data/docs/cli-cheatsheet.md +98 -98
  88. data/docs/cli.md +299 -275
  89. data/docs/contributing/architecture.md +9 -9
  90. data/docs/contributing/benchmarking.md +30 -14
  91. data/docs/contributing/development.md +16 -16
  92. data/docs/contributing/release-process.md +49 -49
  93. data/docs/contributing/testing.md +16 -16
  94. data/docs/debugging.md +229 -229
  95. data/docs/developer/branching.md +10 -10
  96. data/docs/developer/database-diff.md +10 -10
  97. data/docs/developer/local-development.md +49 -17
  98. data/docs/developer/snapshots.md +9 -9
  99. data/docs/developer/temporal-data.md +10 -10
  100. data/docs/developer-guide.md +297 -297
  101. data/docs/getting-started/first-database.md +16 -16
  102. data/docs/getting-started/first-query.md +13 -13
  103. data/docs/getting-started/installation.md +19 -19
  104. data/docs/getting-started/local-to-production.md +300 -300
  105. data/docs/getting-started/quickstart.md +17 -17
  106. data/docs/getting-started/rails.md +16 -16
  107. data/docs/hardening_backlog.md +93 -93
  108. data/docs/lessons-learned.md +112 -112
  109. data/docs/operations/backups.md +33 -33
  110. data/docs/operations/disaster-recovery.md +31 -31
  111. data/docs/operations/failover.md +30 -30
  112. data/docs/operations/monitoring.md +25 -25
  113. data/docs/operations/production-guide.md +295 -295
  114. data/docs/operations/production-runbook.md +45 -45
  115. data/docs/operations/replication.md +33 -33
  116. data/docs/operations/restore.md +6 -6
  117. data/docs/operations/runbook.md +34 -34
  118. data/docs/operations/upgrades.md +14 -14
  119. data/docs/operations/workload-testing.md +17 -17
  120. data/docs/production-readiness.md +118 -118
  121. data/docs/production_validation.md +150 -150
  122. data/docs/rails/active-record.md +11 -11
  123. data/docs/rails/compatibility-guide.md +90 -90
  124. data/docs/rails/database-yml.md +92 -92
  125. data/docs/rails/installation.md +17 -17
  126. data/docs/rails/migrations.md +17 -17
  127. data/docs/rails/production.md +82 -82
  128. data/docs/rails/troubleshooting.md +18 -18
  129. data/docs/release.md +25 -25
  130. data/docs/server/architecture.md +10 -10
  131. data/docs/server/authentication.md +10 -10
  132. data/docs/server/configuration.md +16 -16
  133. data/docs/server/connection-pooling.md +10 -10
  134. data/docs/server/deployment.md +10 -10
  135. data/docs/server/protocol.md +12 -12
  136. data/docs/sql/compatibility-guide.md +82 -82
  137. data/docs/sql/compatibility.md +39 -39
  138. data/docs/sql/data-types.md +10 -10
  139. data/docs/sql/functions.md +9 -9
  140. data/docs/sql/joins.md +9 -9
  141. data/docs/sql/operators.md +9 -9
  142. data/docs/sql/sqlite-compatibility.md +21 -21
  143. data/docs/sql/syntax.md +10 -10
  144. data/docs/sql/transactions.md +10 -10
  145. data/docs/troubleshooting.md +244 -244
  146. data/lessons/01-foundations.md +73 -0
  147. data/lessons/02-local-development.md +121 -0
  148. data/lessons/03-embedded-rubydb.md +99 -0
  149. data/lessons/04-rails-complex-apps.md +138 -0
  150. data/lessons/05-rubydb-production-server.md +237 -0
  151. data/lessons/06-postgresql-massive-apps.md +96 -0
  152. data/lessons/07-hybrid-microservices.md +179 -0
  153. data/lessons/08-migrations-backups-recovery.md +86 -0
  154. data/lessons/09-observability-security-scale.md +87 -0
  155. data/lessons/10-release-readiness.md +192 -0
  156. data/lessons/11-community-adapter.md +323 -0
  157. data/lessons/12-rails-ecommerce-pressure.md +263 -0
  158. data/lib/rubydb/accelerator/client.rb +451 -0
  159. data/lib/rubydb/accelerator/error.rb +22 -0
  160. data/lib/rubydb/accelerator/manager.rb +606 -0
  161. data/lib/rubydb/accelerator.rb +13 -0
  162. data/lib/rubydb/backup/archive.rb +332 -334
  163. data/lib/rubydb/backup/backup.rb +400 -401
  164. data/lib/rubydb/backup/incremental.rb +349 -353
  165. data/lib/rubydb/backup/restore.rb +289 -290
  166. data/lib/rubydb/backup/snapshot.rb +265 -267
  167. data/lib/rubydb/backup/verification.rb +276 -279
  168. data/lib/rubydb/branching/branch.rb +181 -181
  169. data/lib/rubydb/branching/branch_manager.rb +307 -311
  170. data/lib/rubydb/branching/branch_metadata.rb +140 -140
  171. data/lib/rubydb/branching/checkout.rb +165 -166
  172. data/lib/rubydb/branching/copy_on_write.rb +272 -272
  173. data/lib/rubydb/branching/diff.rb +137 -138
  174. data/lib/rubydb/branching/merge.rb +282 -285
  175. data/lib/rubydb/build_info.rb +15 -15
  176. data/lib/rubydb/catalog/catalog.rb +391 -391
  177. data/lib/rubydb/catalog/column.rb +112 -112
  178. data/lib/rubydb/catalog/constraint.rb +180 -180
  179. data/lib/rubydb/catalog/database.rb +184 -184
  180. data/lib/rubydb/catalog/index.rb +97 -97
  181. data/lib/rubydb/catalog/schema.rb +103 -103
  182. data/lib/rubydb/catalog/sequence.rb +90 -90
  183. data/lib/rubydb/catalog/system_catalog.rb +698 -698
  184. data/lib/rubydb/catalog/table.rb +178 -178
  185. data/lib/rubydb/catalog/trigger.rb +102 -102
  186. data/lib/rubydb/catalog/view.rb +66 -66
  187. data/lib/rubydb/cli/application.rb +168 -163
  188. data/lib/rubydb/cli/commands/accelerator.rb +72 -0
  189. data/lib/rubydb/cli/commands/backup.rb +80 -81
  190. data/lib/rubydb/cli/commands/branch.rb +72 -72
  191. data/lib/rubydb/cli/commands/checkout.rb +54 -54
  192. data/lib/rubydb/cli/commands/create.rb +58 -58
  193. data/lib/rubydb/cli/commands/diff.rb +76 -77
  194. data/lib/rubydb/cli/commands/doctor.rb +77 -74
  195. data/lib/rubydb/cli/commands/drop.rb +57 -57
  196. data/lib/rubydb/cli/commands/init.rb +101 -102
  197. data/lib/rubydb/cli/commands/inspect.rb +95 -95
  198. data/lib/rubydb/cli/commands/merge.rb +63 -63
  199. data/lib/rubydb/cli/commands/migrate.rb +62 -62
  200. data/lib/rubydb/cli/commands/restart.rb +42 -39
  201. data/lib/rubydb/cli/commands/restore.rb +121 -121
  202. data/lib/rubydb/cli/commands/shell.rb +365 -365
  203. data/lib/rubydb/cli/commands/snapshot.rb +79 -79
  204. data/lib/rubydb/cli/commands/start.rb +88 -82
  205. data/lib/rubydb/cli/commands/status.rb +96 -92
  206. data/lib/rubydb/cli/commands/stop.rb +47 -47
  207. data/lib/rubydb/cli/commands/vacuum.rb +58 -58
  208. data/lib/rubydb/cli/formatter.rb +221 -221
  209. data/lib/rubydb/cli/output.rb +168 -168
  210. data/lib/rubydb/client/client.rb +309 -304
  211. data/lib/rubydb/client/connection.rb +429 -415
  212. data/lib/rubydb/client/connection_pool.rb +168 -168
  213. data/lib/rubydb/client/connection_url.rb +96 -96
  214. data/lib/rubydb/client/prepared_statement.rb +60 -60
  215. data/lib/rubydb/client/result.rb +127 -123
  216. data/lib/rubydb/client/statement.rb +52 -52
  217. data/lib/rubydb/client/transaction.rb +130 -130
  218. data/lib/rubydb/concurrency/concurrency.rb +19 -19
  219. data/lib/rubydb/concurrency/deadlock_detector.rb +148 -150
  220. data/lib/rubydb/concurrency/latch.rb +101 -101
  221. data/lib/rubydb/concurrency/lock_graph.rb +163 -165
  222. data/lib/rubydb/concurrency/mutex.rb +181 -183
  223. data/lib/rubydb/concurrency/rw_lock.rb +180 -180
  224. data/lib/rubydb/concurrency/scheduler.rb +248 -250
  225. data/lib/rubydb/concurrency/worker_pool.rb +145 -143
  226. data/lib/rubydb/configuration/config.rb +170 -170
  227. data/lib/rubydb/configuration/defaults.rb +191 -179
  228. data/lib/rubydb/configuration/environment.rb +152 -152
  229. data/lib/rubydb/configuration/parser.rb +185 -185
  230. data/lib/rubydb/configuration/validation.rb +228 -221
  231. data/lib/rubydb/constants.rb +74 -74
  232. data/lib/rubydb/constraints/check.rb +181 -181
  233. data/lib/rubydb/constraints/constraint.rb +101 -101
  234. data/lib/rubydb/constraints/foreign_key.rb +130 -130
  235. data/lib/rubydb/constraints/not_null.rb +64 -64
  236. data/lib/rubydb/constraints/primary_key.rb +99 -99
  237. data/lib/rubydb/constraints/unique.rb +106 -108
  238. data/lib/rubydb/constraints/validator.rb +349 -350
  239. data/lib/rubydb/errors/authentication_error.rb +10 -10
  240. data/lib/rubydb/errors/authorization_error.rb +23 -23
  241. data/lib/rubydb/errors/client_error.rb +10 -10
  242. data/lib/rubydb/errors/configuration_error.rb +10 -10
  243. data/lib/rubydb/errors/connection_error.rb +10 -10
  244. data/lib/rubydb/errors/constraint_error.rb +23 -23
  245. data/lib/rubydb/errors/corruption_error.rb +10 -10
  246. data/lib/rubydb/errors/database_error.rb +10 -10
  247. data/lib/rubydb/errors/error.rb +20 -20
  248. data/lib/rubydb/errors/execution_error.rb +10 -10
  249. data/lib/rubydb/errors/parser_error.rb +10 -10
  250. data/lib/rubydb/errors/recovery_error.rb +10 -10
  251. data/lib/rubydb/errors/replication_error.rb +10 -10
  252. data/lib/rubydb/errors/server_error.rb +6 -6
  253. data/lib/rubydb/errors/storage_error.rb +10 -10
  254. data/lib/rubydb/errors/transaction_error.rb +10 -10
  255. data/lib/rubydb/execution/accelerator_dispatch.rb +30 -0
  256. data/lib/rubydb/execution/aggregate_executor.rb +134 -138
  257. data/lib/rubydb/execution/cost_model.rb +72 -0
  258. data/lib/rubydb/execution/delete_executor.rb +110 -112
  259. data/lib/rubydb/execution/distinct_executor.rb +131 -135
  260. data/lib/rubydb/execution/executor.rb +1544 -1188
  261. data/lib/rubydb/execution/expression.rb +191 -193
  262. data/lib/rubydb/execution/index_scan.rb +142 -142
  263. data/lib/rubydb/execution/insert_executor.rb +215 -217
  264. data/lib/rubydb/execution/join_executor.rb +243 -249
  265. data/lib/rubydb/execution/limit_executor.rb +83 -85
  266. data/lib/rubydb/execution/operator_selection.rb +57 -0
  267. data/lib/rubydb/execution/optimizer.rb +227 -215
  268. data/lib/rubydb/execution/physical_plan.rb +47 -0
  269. data/lib/rubydb/execution/plan.rb +355 -353
  270. data/lib/rubydb/execution/planner.rb +508 -536
  271. data/lib/rubydb/execution/predicate.rb +235 -235
  272. data/lib/rubydb/execution/scan.rb +49 -49
  273. data/lib/rubydb/execution/sequential_scan.rb +63 -63
  274. data/lib/rubydb/execution/sort_executor.rb +194 -185
  275. data/lib/rubydb/execution/update_executor.rb +160 -162
  276. data/lib/rubydb/functions/aggregate.rb +70 -70
  277. data/lib/rubydb/functions/date_functions.rb +274 -278
  278. data/lib/rubydb/functions/function.rb +85 -85
  279. data/lib/rubydb/functions/json_functions.rb +231 -215
  280. data/lib/rubydb/functions/numeric_functions.rb +346 -346
  281. data/lib/rubydb/functions/scalar.rb +52 -52
  282. data/lib/rubydb/functions/string_functions.rb +383 -383
  283. data/lib/rubydb/functions/system_functions.rb +258 -246
  284. data/lib/rubydb/history/as_of.rb +238 -238
  285. data/lib/rubydb/history/change.rb +105 -105
  286. data/lib/rubydb/history/history.rb +131 -131
  287. data/lib/rubydb/history/history_manager.rb +228 -229
  288. data/lib/rubydb/history/temporal_query.rb +202 -202
  289. data/lib/rubydb/history/timeline.rb +144 -144
  290. data/lib/rubydb/indexes/btree.rb +215 -186
  291. data/lib/rubydb/indexes/btree_cursor.rb +258 -258
  292. data/lib/rubydb/indexes/btree_node.rb +384 -385
  293. data/lib/rubydb/indexes/hash_index.rb +150 -150
  294. data/lib/rubydb/indexes/index.rb +71 -71
  295. data/lib/rubydb/indexes/index_manager.rb +408 -406
  296. data/lib/rubydb/indexes/index_scan.rb +466 -470
  297. data/lib/rubydb/migrations/migration.rb +253 -254
  298. data/lib/rubydb/migrations/migration_lock.rb +146 -146
  299. data/lib/rubydb/migrations/migration_manager.rb +187 -176
  300. data/lib/rubydb/migrations/migration_version.rb +71 -71
  301. data/lib/rubydb/migrations/schema_diff.rb +211 -211
  302. data/lib/rubydb/migrations/schema_version.rb +64 -64
  303. data/lib/rubydb/monitoring/events.rb +155 -160
  304. data/lib/rubydb/monitoring/health.rb +216 -222
  305. data/lib/rubydb/monitoring/logger.rb +188 -193
  306. data/lib/rubydb/monitoring/metrics.rb +363 -359
  307. data/lib/rubydb/monitoring/performance.rb +176 -176
  308. data/lib/rubydb/monitoring/statistics.rb +168 -170
  309. data/lib/rubydb/mvcc/garbage_collector.rb +199 -199
  310. data/lib/rubydb/mvcc/mvcc.rb +16 -16
  311. data/lib/rubydb/mvcc/snapshot.rb +146 -147
  312. data/lib/rubydb/mvcc/vacuum.rb +180 -180
  313. data/lib/rubydb/mvcc/version.rb +106 -106
  314. data/lib/rubydb/mvcc/version_store.rb +396 -398
  315. data/lib/rubydb/mvcc/visibility.rb +107 -109
  316. data/lib/rubydb/protocol/capabilities.rb +125 -125
  317. data/lib/rubydb/protocol/decoder.rb +142 -145
  318. data/lib/rubydb/protocol/encoder.rb +131 -136
  319. data/lib/rubydb/protocol/handshake.rb +306 -305
  320. data/lib/rubydb/protocol/message.rb +121 -121
  321. data/lib/rubydb/protocol/parameter_binder.rb +101 -0
  322. data/lib/rubydb/protocol/protocol.rb +276 -277
  323. data/lib/rubydb/protocol/version.rb +54 -54
  324. data/lib/rubydb/rails/adapter.rb +245 -239
  325. data/lib/rubydb/rails/connection.rb +312 -314
  326. data/lib/rubydb/rails/database_statements.rb +122 -122
  327. data/lib/rubydb/rails/migration.rb +131 -131
  328. data/lib/rubydb/rails/quoting.rb +109 -109
  329. data/lib/rubydb/rails/result.rb +117 -117
  330. data/lib/rubydb/rails/schema_statements.rb +339 -339
  331. data/lib/rubydb/rails/transaction.rb +105 -105
  332. data/lib/rubydb/rails/type.rb +126 -126
  333. data/lib/rubydb/recovery/checkpoint.rb +261 -257
  334. data/lib/rubydb/recovery/consistency.rb +457 -467
  335. data/lib/rubydb/recovery/corruption_detector.rb +5 -5
  336. data/lib/rubydb/recovery/crash_recovery.rb +381 -387
  337. data/lib/rubydb/recovery/recovery_manager.rb +204 -206
  338. data/lib/rubydb/recovery/redo.rb +235 -237
  339. data/lib/rubydb/recovery/undo.rb +204 -206
  340. data/lib/rubydb/replication/failover.rb +5 -5
  341. data/lib/rubydb/replication/fencing.rb +63 -63
  342. data/lib/rubydb/replication/primary.rb +461 -450
  343. data/lib/rubydb/replication/replica.rb +382 -384
  344. data/lib/rubydb/replication/replication_log.rb +194 -200
  345. data/lib/rubydb/replication/replication_manager.rb +307 -308
  346. data/lib/rubydb/replication/replication_slot.rb +293 -295
  347. data/lib/rubydb/replication/replication_stream.rb +198 -201
  348. data/lib/rubydb/rubydb.rb +570 -560
  349. data/lib/rubydb/security/access_control.rb +252 -254
  350. data/lib/rubydb/security/audit_log.rb +209 -213
  351. data/lib/rubydb/security/authentication.rb +302 -302
  352. data/lib/rubydb/security/authorization.rb +282 -282
  353. data/lib/rubydb/security/credentials.rb +192 -196
  354. data/lib/rubydb/security/password.rb +205 -215
  355. data/lib/rubydb/security/permissions.rb +74 -74
  356. data/lib/rubydb/security/role.rb +99 -101
  357. data/lib/rubydb/security/user.rb +86 -86
  358. data/lib/rubydb/server/connection.rb +383 -366
  359. data/lib/rubydb/server/connection_pool.rb +193 -193
  360. data/lib/rubydb/server/lifecycle.rb +227 -228
  361. data/lib/rubydb/server/listener.rb +139 -136
  362. data/lib/rubydb/server/request_handler.rb +277 -276
  363. data/lib/rubydb/server/server.rb +363 -364
  364. data/lib/rubydb/server/session.rb +416 -369
  365. data/lib/rubydb/server/worker.rb +206 -210
  366. data/lib/rubydb/server/worker_pool.rb +168 -168
  367. data/lib/rubydb/sql/ast/alter_table.rb +169 -169
  368. data/lib/rubydb/sql/ast/begin_transaction.rb +47 -47
  369. data/lib/rubydb/sql/ast/commit.rb +37 -37
  370. data/lib/rubydb/sql/ast/constraint.rb +92 -83
  371. data/lib/rubydb/sql/ast/create_database.rb +41 -41
  372. data/lib/rubydb/sql/ast/create_index.rb +61 -61
  373. data/lib/rubydb/sql/ast/create_schema.rb +52 -52
  374. data/lib/rubydb/sql/ast/create_table.rb +187 -187
  375. data/lib/rubydb/sql/ast/delete.rb +54 -54
  376. data/lib/rubydb/sql/ast/drop_database.rb +41 -41
  377. data/lib/rubydb/sql/ast/drop_index.rb +41 -41
  378. data/lib/rubydb/sql/ast/drop_schema.rb +49 -49
  379. data/lib/rubydb/sql/ast/drop_table.rb +49 -49
  380. data/lib/rubydb/sql/ast/explain.rb +64 -64
  381. data/lib/rubydb/sql/ast/expression.rb +617 -604
  382. data/lib/rubydb/sql/ast/insert.rb +66 -66
  383. data/lib/rubydb/sql/ast/node.rb +42 -42
  384. data/lib/rubydb/sql/ast/rollback.rb +63 -63
  385. data/lib/rubydb/sql/ast/savepoint.rb +59 -59
  386. data/lib/rubydb/sql/ast/select.rb +88 -88
  387. data/lib/rubydb/sql/ast/set_operation.rb +22 -20
  388. data/lib/rubydb/sql/ast/trigger.rb +35 -29
  389. data/lib/rubydb/sql/ast/update.rb +88 -88
  390. data/lib/rubydb/sql/ast/vacuum.rb +19 -19
  391. data/lib/rubydb/sql/ast/view.rb +38 -32
  392. data/lib/rubydb/sql/ast/with.rb +32 -32
  393. data/lib/rubydb/sql/grammar.rb +86 -86
  394. data/lib/rubydb/sql/keywords.rb +156 -156
  395. data/lib/rubydb/sql/lexer.rb +209 -214
  396. data/lib/rubydb/sql/operators.rb +100 -100
  397. data/lib/rubydb/sql/parser.rb +1167 -1170
  398. data/lib/rubydb/sql/planner/analyzer.rb +283 -302
  399. data/lib/rubydb/sql/planner/binder.rb +537 -550
  400. data/lib/rubydb/sql/planner/type_checker.rb +427 -431
  401. data/lib/rubydb/sql/token.rb +210 -210
  402. data/lib/rubydb/storage/buffer_frame.rb +44 -44
  403. data/lib/rubydb/storage/buffer_pool.rb +155 -155
  404. data/lib/rubydb/storage/database_lock.rb +74 -74
  405. data/lib/rubydb/storage/deserializer.rb +332 -342
  406. data/lib/rubydb/storage/engine.rb +2409 -2330
  407. data/lib/rubydb/storage/file_manager.rb +191 -187
  408. data/lib/rubydb/storage/free_space_map.rb +79 -81
  409. data/lib/rubydb/storage/page.rb +92 -94
  410. data/lib/rubydb/storage/page_allocator.rb +852 -855
  411. data/lib/rubydb/storage/page_header.rb +63 -67
  412. data/lib/rubydb/storage/page_manager.rb +127 -131
  413. data/lib/rubydb/storage/record.rb +58 -58
  414. data/lib/rubydb/storage/row.rb +78 -78
  415. data/lib/rubydb/storage/serializer.rb +51 -51
  416. data/lib/rubydb/storage/snapshot_reader.rb +167 -0
  417. data/lib/rubydb/storage/storage_layout.rb +151 -151
  418. data/lib/rubydb/storage/storage_manager.rb +114 -114
  419. data/lib/rubydb/storage/tuple.rb +458 -461
  420. data/lib/rubydb/storage/visibility_map.rb +964 -973
  421. data/lib/rubydb/transactions/commit_manager.rb +219 -220
  422. data/lib/rubydb/transactions/isolation.rb +98 -98
  423. data/lib/rubydb/transactions/lock.rb +76 -76
  424. data/lib/rubydb/transactions/lock_manager.rb +359 -362
  425. data/lib/rubydb/transactions/savepoint.rb +142 -143
  426. data/lib/rubydb/transactions/transaction.rb +214 -215
  427. data/lib/rubydb/transactions/transaction_id.rb +84 -84
  428. data/lib/rubydb/transactions/transaction_log.rb +256 -257
  429. data/lib/rubydb/transactions/transaction_manager.rb +434 -435
  430. data/lib/rubydb/types/bigint.rb +36 -36
  431. data/lib/rubydb/types/blob.rb +37 -37
  432. data/lib/rubydb/types/boolean.rb +34 -34
  433. data/lib/rubydb/types/date.rb +39 -39
  434. data/lib/rubydb/types/decimal.rb +48 -48
  435. data/lib/rubydb/types/float.rb +34 -34
  436. data/lib/rubydb/types/integer.rb +36 -36
  437. data/lib/rubydb/types/json.rb +41 -41
  438. data/lib/rubydb/types/null.rb +34 -34
  439. data/lib/rubydb/types/smallint.rb +36 -36
  440. data/lib/rubydb/types/text.rb +37 -37
  441. data/lib/rubydb/types/time.rb +46 -46
  442. data/lib/rubydb/types/timestamp.rb +39 -39
  443. data/lib/rubydb/types/type.rb +119 -119
  444. data/lib/rubydb/types/uuid.rb +47 -47
  445. data/lib/rubydb/types/varchar.rb +37 -37
  446. data/lib/rubydb/version.rb +32 -32
  447. data/lib/rubydb/wal/archive.rb +207 -193
  448. data/lib/rubydb/wal/checkpoint.rb +181 -183
  449. data/lib/rubydb/wal/lsn.rb +94 -94
  450. data/lib/rubydb/wal/reader.rb +259 -260
  451. data/lib/rubydb/wal/record.rb +105 -105
  452. data/lib/rubydb/wal/segment.rb +193 -193
  453. data/lib/rubydb/wal/wal.rb +481 -452
  454. data/lib/rubydb/wal/writer.rb +236 -236
  455. data/lib/rubydb.rb +7 -7
  456. data/packaging/docker/docker-compose.failover.yml +43 -43
  457. data/packaging/homebrew/rubydb.rb +19 -19
  458. data/rubydb.gemspec +70 -57
  459. data/scripts/benchmark +7 -7
  460. data/scripts/build_accelerator +49 -0
  461. data/scripts/durability_drill +37 -37
  462. data/scripts/fuzz +63 -63
  463. data/scripts/release +77 -42
  464. data/scripts/release_check +43 -43
  465. data/scripts/replication_failover_drill +268 -250
  466. data/scripts/replication_network_failover_drill +287 -255
  467. data/scripts/restore_drill +45 -45
  468. data/scripts/security +45 -0
  469. metadata +102 -1
@@ -0,0 +1,179 @@
1
+ # Lesson 7: a hybrid microservice architecture
2
+
3
+ A practical RubyDB architecture is to keep the large shared business system
4
+ on PostgreSQL and use RubyDB for a small service with a narrow responsibility.
5
+ Examples include a local catalog, a bounded document/index service, an
6
+ internal workflow, or a tenant-isolated tool whose SQL and recovery needs have
7
+ been validated.
8
+
9
+ ## Give each service ownership
10
+
11
+ ```text
12
+ Rails monolith / public API
13
+ |
14
+ +--> PostgreSQL: users, billing, orders, reporting
15
+ |
16
+ +--> RubyDB service API: bounded internal records
17
+ |
18
+ +--> one RubyDB server and persistent data directory
19
+ ```
20
+
21
+ The services communicate through an API or an event contract. They do not
22
+ share an embedded file and they do not write directly into each other’s tables.
23
+ Each service owns its migrations, credentials, backups, alerts, and recovery
24
+ runbook.
25
+
26
+ ## Ruby client for a service
27
+
28
+ ```ruby
29
+ # app/services/catalog_store.rb
30
+ require "rubydb"
31
+
32
+ class CatalogStore
33
+ def initialize(url: ENV.fetch("RUBYDB_URL"))
34
+ @client = RubyDB::Client::Client.new(url: url)
35
+ end
36
+
37
+ def find(code)
38
+ result = @client.query(
39
+ "SELECT code, title FROM catalog_items WHERE code = ?",
40
+ [code]
41
+ )
42
+ result.to_a.first
43
+ end
44
+
45
+ def close
46
+ @client.disconnect
47
+ end
48
+ end
49
+ ```
50
+
51
+ Use the actual client API in the version pinned by the service and add tests
52
+ for connection failures, timeouts, duplicate requests, and empty results. In a
53
+ long-running app, put client lifecycle management in the application’s
54
+ dependency/container layer and close it during shutdown.
55
+
56
+ ## Python services with the RubyDB adapter
57
+
58
+ Python applications connect to RubyDB server mode through the published
59
+ `rubydb-python` DB-API 2.0 adapter. The Python process must not open an
60
+ embedded `.rdb` file. Put the server URL in a secret-managed environment
61
+ variable:
62
+
63
+ ```powershell
64
+ $env:RUBYDB_URL = "rubydbs://service_user:URL_ENCODED_PASSWORD@rubydb.internal:7432/orders?verify_peer=true&ca_file=%2Fetc%2Frubydb%2Ftls%2Fca.crt"
65
+ python -m pip install rubydb-python
66
+ ```
67
+
68
+ Use parameterized queries and a bounded pool in workers:
69
+
70
+ ```python
71
+ import os
72
+ from rubydb import ConnectionPool
73
+
74
+ pool = ConnectionPool(os.environ["RUBYDB_URL"], min_size=1, max_size=8)
75
+ try:
76
+ with pool.connection() as connection:
77
+ with connection.cursor() as cursor:
78
+ cursor.execute(
79
+ "SELECT id, status FROM jobs WHERE account_id = ?",
80
+ [account_id],
81
+ )
82
+ rows = cursor.fetchall()
83
+ finally:
84
+ pool.close()
85
+ ```
86
+
87
+ The adapter is synchronous DB-API code. In an async framework such as Flaxon,
88
+ run database calls in a worker thread so a slow query does not block the event
89
+ loop:
90
+
91
+ ```python
92
+ import asyncio
93
+ from rubydb import connect
94
+
95
+ async def load_jobs(url):
96
+ def query():
97
+ with connect(url, timeout=5) as db:
98
+ with db.cursor() as cursor:
99
+ cursor.execute("SELECT id, status FROM jobs ORDER BY id")
100
+ return cursor.fetchall()
101
+
102
+ return await asyncio.to_thread(query)
103
+ ```
104
+
105
+ Run the complete examples in `examples/python_flask` and
106
+ `examples/python_flaxon`. Both examples use real RubyDB TCP traffic and have
107
+ live integration tests; they are intentionally small starting points, not a
108
+ replacement for application-specific authorization, migrations, backups,
109
+ timeouts, monitoring, and load testing.
110
+
111
+ ## Node.js and TypeScript services
112
+
113
+ Node services use the `rubydb-node` package over the same RubyDB server
114
+ protocol:
115
+
116
+ ```sh
117
+ npm install rubydb-node
118
+ ```
119
+
120
+ ```ts
121
+ import { connect } from "rubydb-node";
122
+
123
+ const db = await connect(process.env.RUBYDB_URL!);
124
+ try {
125
+ const result = await db.query(
126
+ "SELECT id, state FROM jobs WHERE account_id = ?",
127
+ [accountId],
128
+ );
129
+ console.log(result.rows);
130
+ } finally {
131
+ await db.close();
132
+ }
133
+ ```
134
+
135
+ Use `ConnectionPool` for concurrent workers, keep the pool bounded per process,
136
+ and use `rubydbs://` with peer verification in production. The package is
137
+ TypeScript-first, supports prepared statements, transactions, timeouts with
138
+ wire cancellation, and does not access embedded database files. See
139
+ `adapters/rubydb/README.md` for the full Node release and operations boundary.
140
+
141
+ ## A small Rails service
142
+
143
+ ```yaml
144
+ # service/config/database.yml
145
+ production:
146
+ adapter: rubydb
147
+ embedded: false
148
+ url: <%= ENV.fetch("RUBYDB_URL") %>
149
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>
150
+ ```
151
+
152
+ Keep the API idempotent. A client timeout can happen after the server commits
153
+ a write, so a retry must use an idempotency key or first check the operation’s
154
+ result. For cross-service workflows, record an outbox/event in the owning
155
+ system and design consumers to tolerate duplicate delivery.
156
+
157
+ ## What belongs where
158
+
159
+ Keep users, payments, orders, and cross-tenant reporting in PostgreSQL when
160
+ they need shared relational consistency and broad analytical tooling. Keep
161
+ RubyDB data that can be independently backed up, restored, migrated, and
162
+ reconciled. Do not split a single atomic business transaction across the two
163
+ databases unless you have designed and tested a distributed workflow.
164
+
165
+ ## Failure and deployment rules
166
+
167
+ * Deploy the RubyDB service with a persistent volume and one server owner.
168
+ * Make the service private; clients use TLS and least-privilege credentials.
169
+ * Set bounded connection and request timeouts and expose a useful health probe.
170
+ * Retry only idempotent operations, with backoff and a maximum attempt count.
171
+ * Maintain a PostgreSQL and RubyDB restore drill independently.
172
+ * Version the API/event contract before changing either database schema.
173
+
174
+ ## Checkpoint
175
+
176
+ The checkpoint passes when each data set has one owner, the API can tolerate a
177
+ restarted database service, duplicate requests do not create duplicate business
178
+ records, and the two systems can be restored independently. Continue to [lesson 8](08-migrations-backups-recovery.md)
179
+ for migration and recovery drills.
@@ -0,0 +1,86 @@
1
+ # Lesson 8: migrations, backups, and recovery
2
+
3
+ Production data work is a controlled change to a recoverable system. A green
4
+ migration on an empty database is not enough. Test populated tables, rollback
5
+ boundaries, disk growth, indexes, locks, and application compatibility.
6
+
7
+ ## RubyDB migration workflow
8
+
9
+ Preview and apply a migration against a disposable or staging copy:
10
+
11
+ ```sh
12
+ rubydb doctor --quick --json
13
+ rubydb backup --database data/app.rdb --dir backups --type full --compress
14
+ rubydb migrate --database data/app.rdb --path db/migrate --dry-run
15
+ rubydb migrate --database data/app.rdb --path db/migrate
16
+ ```
17
+
18
+ Run the migration once from a release job, not once per web process. Keep the
19
+ pre-migration backup and record the database version, application revision,
20
+ backup checksum, operator, and start/end times.
21
+
22
+ ## Verified RubyDB backup and restore
23
+
24
+ Create a full backup with verification enabled, then dry-run the restore:
25
+
26
+ ```sh
27
+ rubydb backup --database data/app.rdb --dir backups --type full --compress
28
+ rubydb restore --dir backups --latest --dry-run
29
+ rubydb restore --database restored/app.rdb --dir backups --latest
30
+ ```
31
+
32
+ If a release depends on incremental or differential backups, retain the entire
33
+ required chain and its manifest. Keep backups away from the database disk and
34
+ test that a new host can read them. Restore into a new inactive path; do not
35
+ overwrite the only source with `--force`.
36
+
37
+ After restoring, verify both structure and meaning:
38
+
39
+ ```sh
40
+ rubydb inspect --database restored/app.rdb --stats --wal
41
+ rubydb shell --database restored/app.rdb --json
42
+ ```
43
+
44
+ Run schema checks, row counts, foreign-key checks, representative application
45
+ queries, and business totals. Record the achieved RPO and RTO rather than
46
+ assuming the command’s success proves recoverability.
47
+
48
+ ## PostgreSQL backup and restore
49
+
50
+ For PostgreSQL, use the provider’s managed backup/PITR feature where possible
51
+ and rehearse an independent logical backup:
52
+
53
+ ```sh
54
+ pg_dump --format=custom --file=tmp/app-staging.dump "$DATABASE_URL"
55
+ createdb app_restore
56
+ pg_restore --clean --if-exists --dbname=app_restore tmp/app-staging.dump
57
+ ```
58
+
59
+ The restore target must be isolated from production. Validate extensions,
60
+ roles, ownership, sequences, indexes, and application behavior after restore.
61
+ For a managed service, follow its documented restore and point-in-time
62
+ procedure instead of assuming local `createdb` access exists.
63
+
64
+ ## Corruption and interrupted writes
65
+
66
+ When storage or recovery is suspect:
67
+
68
+ 1. stop application writes and preserve the database, WAL, metadata, config,
69
+ and logs together;
70
+ 2. copy the evidence to a separate incident location;
71
+ 3. run `doctor --quick` and `inspect --stats --wal` on the copy;
72
+ 4. restore the latest verified backup into a new path;
73
+ 5. compare schema, row counts, checksums, and business totals; and
74
+ 6. document what data was lost, replayed, or manually reconciled.
75
+
76
+ Do not “repair” corruption by deleting files, dropping tables, or running full
77
+ vacuum on the only copy. Use the repository’s durability and recovery drills
78
+ to rehearse interrupted checkpoints, full disks, corrupted files, compaction,
79
+ and restore at scale before an incident.
80
+
81
+ ## Checkpoint
82
+
83
+ The checkpoint passes when an operator who did not create the backup can restore
84
+ it on another path, prove the data is usable, and state measured RPO/RTO. Keep
85
+ the report with the release evidence. Continue to [lesson 9](09-observability-security-scale.md)
86
+ for operations and security.
@@ -0,0 +1,87 @@
1
+ # Lesson 9: observability, security, and scale
2
+
3
+ Production readiness is an operating discipline. A database is ready only when
4
+ the team can see failures, limit damage, rotate credentials, and make a safe
5
+ recovery decision under pressure.
6
+
7
+ ## Protect the connection
8
+
9
+ For RubyDB server mode, use a private network, password authentication, and
10
+ TLS with peer verification:
11
+
12
+ ```text
13
+ rubydbs://app_user:URL_ENCODED_PASSWORD@db.internal.example:7432/app?verify_peer=true&ca_file=%2Fetc%2Frubydb%2Fca.crt
14
+ ```
15
+
16
+ Store `RUBYDB_URL`, `RUBYDB_PASSWORD`, certificates, and private keys in the
17
+ deployment secret manager. Do not commit them, put them in a Docker image, or
18
+ print them in health checks. Give the application only the database privileges
19
+ it needs and use a separate migration/admin identity.
20
+
21
+ For PostgreSQL, use `DATABASE_URL` from the provider’s secret store, TLS
22
+ settings required by that provider, least-privilege roles, and rotated
23
+ credentials. Review role grants after every schema or service change.
24
+
25
+ ## Set limits before load
26
+
27
+ Bound every layer that can wait:
28
+
29
+ ```yaml
30
+ # config/database.yml
31
+ production:
32
+ adapter: rubydb
33
+ embedded: false
34
+ url: <%= ENV.fetch("RUBYDB_URL") %>
35
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>
36
+ checkout_timeout: <%= ENV.fetch("DB_CHECKOUT_TIMEOUT", "5") %>
37
+ ```
38
+
39
+ Also set application request/job timeouts, connection idle limits, server
40
+ connection limits, maximum request body sizes, and process memory/CPU limits.
41
+ Choose values from measurements. A timeout should fail a request cleanly and
42
+ produce a useful event; it should not cause an unsafe blind retry.
43
+
44
+ ## Monitor signals that lead to incidents
45
+
46
+ Collect metrics and structured logs for:
47
+
48
+ * request and query latency by operation, including p95 and p99;
49
+ * error, timeout, cancellation, retry, and deadlock counts;
50
+ * active connections, pool wait time, and transaction age;
51
+ * WAL/checkpoint growth, database size, free disk, and compaction/vacuum time;
52
+ * backup age, backup verification result, restore drill age, and RPO/RTO; and
53
+ * process restarts, readiness failures, replication lag, and failover events.
54
+
55
+ The RubyDB CLI is useful evidence in an operator check:
56
+
57
+ ```sh
58
+ rubydb --env production status --json
59
+ rubydb --env production doctor --quick --json
60
+ rubydb inspect --database data/app.rdb --stats --wal
61
+ ```
62
+
63
+ Turn those outputs into alerts with thresholds and an owner. A green process
64
+ status is not the same as a healthy application: include a real application
65
+ query and a write/read smoke test in staging and deployment verification.
66
+
67
+ ## Load and concurrency validation
68
+
69
+ Start with a reproducible workload, then increase concurrency gradually:
70
+
71
+ ```sh
72
+ RUBYDB_WORKLOAD_THREADS=16 RUBYDB_WORKLOAD_OPERATIONS=10000 \
73
+ ruby benchmarks/concurrent_workload.rb
74
+ ```
75
+
76
+ Use the repository’s documented workload script and record its output. Measure
77
+ throughput, latency, failures, cancellations, timeouts, deadlocks, memory, WAL,
78
+ and disk use. Run long enough to expose leaks and queue growth. Test separate
79
+ processes and separate hosts for server mode; an in-process benchmark does not
80
+ prove network behavior.
81
+
82
+ ## Checkpoint
83
+
84
+ The checkpoint passes when alerts have thresholds and owners, secrets can be
85
+ rotated without source changes, resource limits are documented, and a sustained
86
+ test produces a baseline with no unexplained errors or unbounded growth.
87
+ Continue to [lesson 10](10-release-readiness.md) for the release gate.
@@ -0,0 +1,192 @@
1
+ # Lesson 10: release readiness
2
+
3
+ The final checkpoint is evidence, not optimism. A production release should
4
+ identify the exact RubyDB and adapter versions, supported Ruby/Rails/OS matrix,
5
+ tested SQL surface, backup artifact, restore result, load baseline, security
6
+ review, and rollback owner.
7
+
8
+ ## Run repository checks
9
+
10
+ From the RubyDB repository:
11
+
12
+ ```sh
13
+ bundle install
14
+ bundle exec rspec
15
+ bundle exec rake
16
+ git diff --check
17
+ ```
18
+
19
+ Run the Rails adapter suite from its directory and repeat it for every Rails
20
+ and Ruby version you claim to support:
21
+
22
+ ```sh
23
+ cd adapters/activerecord
24
+ bundle install
25
+ bundle exec rspec
26
+ ```
27
+
28
+ Add your application’s complex query, migration, schema dump/load, concurrency,
29
+ and failure tests to CI. A passing library suite does not certify an arbitrary
30
+ application.
31
+
32
+ ## Release a gem safely
33
+
34
+ Review the project’s release instructions and run the preflight with a version
35
+ that has not already been published:
36
+
37
+ ```sh
38
+ RUBYDB_RELEASE_VERSION=0.1.6 ruby scripts/release
39
+ ```
40
+
41
+ On PowerShell, use:
42
+
43
+ ```powershell
44
+ $env:RUBYDB_RELEASE_VERSION = "0.1.6"
45
+ ruby scripts/release
46
+ ```
47
+
48
+ The release script builds the gem and writes a checksum. Check the artifact
49
+ locally before publishing:
50
+
51
+ ```sh
52
+ gem specification pkg/rubydb-0.1.6.gem
53
+ gem install pkg/rubydb-0.1.6.gem --local
54
+ ruby -rrubydb -e 'puts RubyDB::VERSION'
55
+ ```
56
+
57
+ Publishing requires a RubyGems API key or trusted publishing setup configured
58
+ on the release machine. The local script publishes only when both the explicit
59
+ publish flag and secret are present; never commit the secret:
60
+
61
+ ```sh
62
+ RUBYDB_RELEASE_VERSION=0.1.6 \
63
+ RUBYDB_PUBLISH=1 \
64
+ GEM_HOST_API_KEY="YOUR_RUBYGEMS_API_KEY" \
65
+ ruby scripts/release
66
+ ```
67
+
68
+ On Windows PowerShell:
69
+
70
+ ```powershell
71
+ $env:RUBYDB_RELEASE_VERSION = "0.1.6"
72
+ $env:RUBYDB_PUBLISH = "1"
73
+ $env:GEM_HOST_API_KEY = "YOUR_RUBYGEMS_API_KEY"
74
+ ruby scripts/release
75
+ ```
76
+
77
+ Prefer the repository’s signed GitHub Actions release workflow for a public
78
+ release. Store signing keys and RubyGems secrets only in protected secret
79
+ storage; do not put them in the repository or a checked-in `.env` file.
80
+
81
+ Release the adapter separately when its version changes, update the changelog,
82
+ tag the source commit, and publish the checksums and supported-version notes.
83
+
84
+ ## Publish the Python adapter to PyPI
85
+
86
+ The Python adapter is a separate distribution named `rubydb-python`; publishing
87
+ the Ruby gem does not publish this package. Build it from the adapter directory
88
+ and validate both distribution formats before upload:
89
+
90
+ ```powershell
91
+ cd adapters/python
92
+ python -m pip install --upgrade build twine
93
+ python -m build
94
+ python -m twine check dist/*
95
+ ```
96
+
97
+ Prefer PyPI Trusted Publishing from CI. For a local upload, use a short-lived,
98
+ scope-limited PyPI token through the environment or Twine's prompt. Never
99
+ commit a token:
100
+
101
+ ```powershell
102
+ $env:TWINE_USERNAME = "__token__"
103
+ $env:TWINE_PASSWORD = (Get-Clipboard).Trim()
104
+ python -m twine upload dist/*
105
+ Remove-Item Env:TWINE_PASSWORD
106
+ ```
107
+
108
+ After upload, verify the package from a clean environment and run the live
109
+ adapter tests against a RubyDB server:
110
+
111
+ ```powershell
112
+ python -m venv .venv-clean
113
+ .venv-clean\Scripts\Activate.ps1
114
+ python -m pip install rubydb-python
115
+ $env:RUBYDB_URL = "rubydbs://service_user:password@127.0.0.1:7432/rubydb"
116
+ python -m unittest discover -s adapters/python/tests -v
117
+ ```
118
+
119
+ The package provides DB-API 2.0 access to RubyDB server mode. It is not a
120
+ PostgreSQL driver and does not make PostgreSQL SQL portable to RubyDB. Pin the
121
+ adapter and server versions together, use TLS in production, and keep the
122
+ application's migration and rollback procedure under version control.
123
+
124
+ ## Build and publish the Node adapter
125
+
126
+ The Node adapter is a separate public npm package named `rubydb-node`. The
127
+ literal `node/rubydb` is not a valid npm name because npm reserves `/` for
128
+ scoped packages such as `@scope/package`.
129
+
130
+ ```powershell
131
+ cd adapters/rubydb
132
+ npm ci
133
+ npm test
134
+ npm run publish:check
135
+ npm publish --access public
136
+ ```
137
+
138
+ Use npm Trusted Publishing from CI or a protected npm token. Never commit an
139
+ `.npmrc` containing credentials. The package's live test runs against a real
140
+ RubyDB server when `RUBYDB_URL` is set:
141
+
142
+ ```powershell
143
+ $env:RUBYDB_URL = "rubydb://rubydb@127.0.0.1:7432/rubydb"
144
+ npm test
145
+ ```
146
+
147
+ The package is a Node.js/TypeScript RubyDB client, not a PostgreSQL driver. Pin
148
+ the npm client and RubyDB server versions together and validate the target
149
+ application's SQL, retry, TLS, migration, backup, and failover behavior.
150
+
151
+ ## Deployment gate
152
+
153
+ For a direct RubyDB production deployment, follow [lesson 5](05-rubydb-production-server.md)
154
+ from top to bottom before this gate. For a massive Rails application, follow
155
+ [lesson 6](06-postgresql-massive-apps.md) and keep RubyDB at a separate service
156
+ boundary.
157
+
158
+ Do not promote until all of these have an owner and a recorded result:
159
+
160
+ * application tests pass against the production database topology;
161
+ * migrations pass on empty and populated staging data;
162
+ * a verified backup restores on another path or host;
163
+ * load tests cover concurrency, timeouts, cancellation, and resource limits;
164
+ * multi-process client/server tests cover restart and network failure;
165
+ * failover and fencing behavior is validated if high availability is claimed;
166
+ * TLS, secrets, least privilege, certificate rotation, and audit logging are
167
+ reviewed;
168
+ * dashboards and alerts page an on-call person;
169
+ * rollback, upgrade, and data-reconciliation procedures are rehearsed; and
170
+ * the README and compatibility guide state what is supported and what is not.
171
+
172
+ ## A sensible first production architecture
173
+
174
+ For a large Rails product, use managed PostgreSQL for the main application and
175
+ deploy RubyDB only for an independently owned microservice whose workload has
176
+ passed the lessons above. For a small internal or single-owner service, RubyDB
177
+ server mode can be reasonable when its SQL, concurrency, recovery, and
178
+ operational limits are accepted. Do not call either architecture universally
179
+ compatible without workload evidence.
180
+
181
+ ## Final checkpoint
182
+
183
+ The journey is complete when a new operator can deploy the exact release,
184
+ verify a real query, observe health and capacity, restore data, and explain the
185
+ rollback path without relying on the author’s laptop. Keep the evidence with
186
+ the release and repeat the drills after major RubyDB, Rails, schema, or hosting
187
+ changes.
188
+
189
+ Continue using the repository’s [CLI guide](../docs/cli.md), [production
190
+ operations guide](../docs/operations/production-guide.md), [Rails compatibility
191
+ guide](../docs/rails/compatibility-guide.md), and [SQL compatibility
192
+ guide](../docs/sql/compatibility-guide.md) as the detailed references.