rubydb 0.1.4 → 0.1.5

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 (420) 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 +12 -5
  14. data/.rubocop.yml +50 -44
  15. data/.standard.yml +9 -14
  16. data/ARCHITECTURE.md +21 -21
  17. data/CHANGELOG.md +43 -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 +249 -162
  24. data/ROADMAP.md +27 -27
  25. data/Rakefile +71 -71
  26. data/SECURITY.md +54 -54
  27. data/SUPPORT.md +14 -14
  28. data/adapters/activerecord/Gemfile +11 -11
  29. data/adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb +873 -879
  30. data/adapters/activerecord/rubydb-activerecord.gemspec +20 -20
  31. data/adapters/activerecord/spec/rubydb_adapter_integration_spec.rb +143 -143
  32. data/adapters/ruby/README.md +18 -18
  33. data/adapters/sequel/README.md +11 -11
  34. data/config/monitoring/prometheus-alerts.yml +39 -39
  35. data/config/production.yml +36 -36
  36. data/docs/README.md +75 -71
  37. data/docs/architecture/concurrency.md +14 -14
  38. data/docs/architecture/current-state.md +125 -125
  39. data/docs/architecture/execution-engine.md +25 -25
  40. data/docs/architecture/indexes.md +19 -19
  41. data/docs/architecture/mvcc.md +19 -19
  42. data/docs/architecture/overview.md +13 -13
  43. data/docs/architecture/pages.md +11 -11
  44. data/docs/architecture/production-roadmap.md +82 -82
  45. data/docs/architecture/query-planner.md +20 -20
  46. data/docs/architecture/recovery.md +18 -18
  47. data/docs/architecture/sql-engine.md +12 -12
  48. data/docs/architecture/storage-engine.md +14 -14
  49. data/docs/architecture/transactions.md +10 -10
  50. data/docs/architecture/wal.md +28 -28
  51. data/docs/cli-cheatsheet.md +98 -98
  52. data/docs/cli.md +275 -275
  53. data/docs/contributing/architecture.md +9 -9
  54. data/docs/contributing/benchmarking.md +14 -14
  55. data/docs/contributing/development.md +16 -16
  56. data/docs/contributing/release-process.md +49 -49
  57. data/docs/contributing/testing.md +16 -16
  58. data/docs/debugging.md +229 -229
  59. data/docs/developer/branching.md +10 -10
  60. data/docs/developer/database-diff.md +10 -10
  61. data/docs/developer/local-development.md +17 -17
  62. data/docs/developer/snapshots.md +9 -9
  63. data/docs/developer/temporal-data.md +10 -10
  64. data/docs/developer-guide.md +297 -297
  65. data/docs/getting-started/first-database.md +16 -16
  66. data/docs/getting-started/first-query.md +13 -13
  67. data/docs/getting-started/installation.md +19 -19
  68. data/docs/getting-started/local-to-production.md +300 -300
  69. data/docs/getting-started/quickstart.md +17 -17
  70. data/docs/getting-started/rails.md +16 -16
  71. data/docs/hardening_backlog.md +93 -93
  72. data/docs/lessons-learned.md +112 -112
  73. data/docs/operations/backups.md +33 -33
  74. data/docs/operations/disaster-recovery.md +31 -31
  75. data/docs/operations/failover.md +30 -30
  76. data/docs/operations/monitoring.md +25 -25
  77. data/docs/operations/production-guide.md +295 -295
  78. data/docs/operations/production-runbook.md +45 -45
  79. data/docs/operations/replication.md +33 -33
  80. data/docs/operations/restore.md +6 -6
  81. data/docs/operations/runbook.md +34 -34
  82. data/docs/operations/upgrades.md +14 -14
  83. data/docs/operations/workload-testing.md +17 -17
  84. data/docs/production-readiness.md +118 -118
  85. data/docs/production_validation.md +150 -150
  86. data/docs/rails/active-record.md +11 -11
  87. data/docs/rails/compatibility-guide.md +90 -90
  88. data/docs/rails/database-yml.md +92 -92
  89. data/docs/rails/installation.md +17 -17
  90. data/docs/rails/migrations.md +17 -17
  91. data/docs/rails/production.md +82 -82
  92. data/docs/rails/troubleshooting.md +18 -18
  93. data/docs/release.md +25 -25
  94. data/docs/server/architecture.md +10 -10
  95. data/docs/server/authentication.md +10 -10
  96. data/docs/server/configuration.md +16 -16
  97. data/docs/server/connection-pooling.md +10 -10
  98. data/docs/server/deployment.md +10 -10
  99. data/docs/server/protocol.md +12 -12
  100. data/docs/sql/compatibility-guide.md +82 -82
  101. data/docs/sql/compatibility.md +39 -39
  102. data/docs/sql/data-types.md +10 -10
  103. data/docs/sql/functions.md +9 -9
  104. data/docs/sql/joins.md +9 -9
  105. data/docs/sql/operators.md +9 -9
  106. data/docs/sql/sqlite-compatibility.md +21 -21
  107. data/docs/sql/syntax.md +10 -10
  108. data/docs/sql/transactions.md +10 -10
  109. data/docs/troubleshooting.md +244 -244
  110. data/lessons/01-foundations.md +73 -0
  111. data/lessons/02-local-development.md +121 -0
  112. data/lessons/03-embedded-rubydb.md +99 -0
  113. data/lessons/04-rails-complex-apps.md +138 -0
  114. data/lessons/05-rubydb-production-server.md +237 -0
  115. data/lessons/06-postgresql-massive-apps.md +96 -0
  116. data/lessons/07-hybrid-microservices.md +94 -0
  117. data/lessons/08-migrations-backups-recovery.md +86 -0
  118. data/lessons/09-observability-security-scale.md +87 -0
  119. data/lessons/10-release-readiness.md +125 -0
  120. data/lib/rubydb/backup/archive.rb +332 -334
  121. data/lib/rubydb/backup/backup.rb +400 -401
  122. data/lib/rubydb/backup/incremental.rb +349 -353
  123. data/lib/rubydb/backup/restore.rb +289 -290
  124. data/lib/rubydb/backup/snapshot.rb +265 -267
  125. data/lib/rubydb/backup/verification.rb +276 -279
  126. data/lib/rubydb/branching/branch.rb +181 -181
  127. data/lib/rubydb/branching/branch_manager.rb +307 -311
  128. data/lib/rubydb/branching/branch_metadata.rb +140 -140
  129. data/lib/rubydb/branching/checkout.rb +165 -166
  130. data/lib/rubydb/branching/copy_on_write.rb +272 -272
  131. data/lib/rubydb/branching/diff.rb +137 -138
  132. data/lib/rubydb/branching/merge.rb +282 -285
  133. data/lib/rubydb/build_info.rb +15 -15
  134. data/lib/rubydb/catalog/catalog.rb +391 -391
  135. data/lib/rubydb/catalog/column.rb +112 -112
  136. data/lib/rubydb/catalog/constraint.rb +180 -180
  137. data/lib/rubydb/catalog/database.rb +184 -184
  138. data/lib/rubydb/catalog/index.rb +97 -97
  139. data/lib/rubydb/catalog/schema.rb +103 -103
  140. data/lib/rubydb/catalog/sequence.rb +90 -90
  141. data/lib/rubydb/catalog/system_catalog.rb +698 -698
  142. data/lib/rubydb/catalog/table.rb +178 -178
  143. data/lib/rubydb/catalog/trigger.rb +102 -102
  144. data/lib/rubydb/catalog/view.rb +66 -66
  145. data/lib/rubydb/cli/application.rb +163 -163
  146. data/lib/rubydb/cli/commands/backup.rb +80 -81
  147. data/lib/rubydb/cli/commands/branch.rb +72 -72
  148. data/lib/rubydb/cli/commands/checkout.rb +54 -54
  149. data/lib/rubydb/cli/commands/create.rb +58 -58
  150. data/lib/rubydb/cli/commands/diff.rb +76 -77
  151. data/lib/rubydb/cli/commands/doctor.rb +74 -74
  152. data/lib/rubydb/cli/commands/drop.rb +57 -57
  153. data/lib/rubydb/cli/commands/init.rb +101 -102
  154. data/lib/rubydb/cli/commands/inspect.rb +95 -95
  155. data/lib/rubydb/cli/commands/merge.rb +63 -63
  156. data/lib/rubydb/cli/commands/migrate.rb +62 -62
  157. data/lib/rubydb/cli/commands/restart.rb +42 -39
  158. data/lib/rubydb/cli/commands/restore.rb +121 -121
  159. data/lib/rubydb/cli/commands/shell.rb +365 -365
  160. data/lib/rubydb/cli/commands/snapshot.rb +79 -79
  161. data/lib/rubydb/cli/commands/start.rb +88 -82
  162. data/lib/rubydb/cli/commands/status.rb +96 -92
  163. data/lib/rubydb/cli/commands/stop.rb +47 -47
  164. data/lib/rubydb/cli/commands/vacuum.rb +58 -58
  165. data/lib/rubydb/cli/formatter.rb +221 -221
  166. data/lib/rubydb/cli/output.rb +168 -168
  167. data/lib/rubydb/client/client.rb +302 -304
  168. data/lib/rubydb/client/connection.rb +414 -415
  169. data/lib/rubydb/client/connection_pool.rb +168 -168
  170. data/lib/rubydb/client/connection_url.rb +96 -96
  171. data/lib/rubydb/client/prepared_statement.rb +60 -60
  172. data/lib/rubydb/client/result.rb +123 -123
  173. data/lib/rubydb/client/statement.rb +52 -52
  174. data/lib/rubydb/client/transaction.rb +130 -130
  175. data/lib/rubydb/concurrency/concurrency.rb +19 -19
  176. data/lib/rubydb/concurrency/deadlock_detector.rb +148 -150
  177. data/lib/rubydb/concurrency/latch.rb +101 -101
  178. data/lib/rubydb/concurrency/lock_graph.rb +163 -165
  179. data/lib/rubydb/concurrency/mutex.rb +181 -183
  180. data/lib/rubydb/concurrency/rw_lock.rb +180 -180
  181. data/lib/rubydb/concurrency/scheduler.rb +248 -250
  182. data/lib/rubydb/concurrency/worker_pool.rb +145 -143
  183. data/lib/rubydb/configuration/config.rb +170 -170
  184. data/lib/rubydb/configuration/defaults.rb +179 -179
  185. data/lib/rubydb/configuration/environment.rb +152 -152
  186. data/lib/rubydb/configuration/parser.rb +185 -185
  187. data/lib/rubydb/configuration/validation.rb +221 -221
  188. data/lib/rubydb/constants.rb +74 -74
  189. data/lib/rubydb/constraints/check.rb +181 -181
  190. data/lib/rubydb/constraints/constraint.rb +101 -101
  191. data/lib/rubydb/constraints/foreign_key.rb +130 -130
  192. data/lib/rubydb/constraints/not_null.rb +64 -64
  193. data/lib/rubydb/constraints/primary_key.rb +99 -99
  194. data/lib/rubydb/constraints/unique.rb +106 -108
  195. data/lib/rubydb/constraints/validator.rb +349 -350
  196. data/lib/rubydb/errors/authentication_error.rb +10 -10
  197. data/lib/rubydb/errors/authorization_error.rb +23 -23
  198. data/lib/rubydb/errors/client_error.rb +10 -10
  199. data/lib/rubydb/errors/configuration_error.rb +10 -10
  200. data/lib/rubydb/errors/connection_error.rb +10 -10
  201. data/lib/rubydb/errors/constraint_error.rb +23 -23
  202. data/lib/rubydb/errors/corruption_error.rb +10 -10
  203. data/lib/rubydb/errors/database_error.rb +10 -10
  204. data/lib/rubydb/errors/error.rb +20 -20
  205. data/lib/rubydb/errors/execution_error.rb +10 -10
  206. data/lib/rubydb/errors/parser_error.rb +10 -10
  207. data/lib/rubydb/errors/recovery_error.rb +10 -10
  208. data/lib/rubydb/errors/replication_error.rb +10 -10
  209. data/lib/rubydb/errors/server_error.rb +6 -6
  210. data/lib/rubydb/errors/storage_error.rb +10 -10
  211. data/lib/rubydb/errors/transaction_error.rb +10 -10
  212. data/lib/rubydb/execution/aggregate_executor.rb +134 -138
  213. data/lib/rubydb/execution/delete_executor.rb +110 -112
  214. data/lib/rubydb/execution/distinct_executor.rb +131 -135
  215. data/lib/rubydb/execution/executor.rb +1182 -1188
  216. data/lib/rubydb/execution/expression.rb +191 -193
  217. data/lib/rubydb/execution/index_scan.rb +142 -142
  218. data/lib/rubydb/execution/insert_executor.rb +215 -217
  219. data/lib/rubydb/execution/join_executor.rb +243 -249
  220. data/lib/rubydb/execution/limit_executor.rb +83 -85
  221. data/lib/rubydb/execution/optimizer.rb +227 -215
  222. data/lib/rubydb/execution/plan.rb +355 -353
  223. data/lib/rubydb/execution/planner.rb +542 -536
  224. data/lib/rubydb/execution/predicate.rb +235 -235
  225. data/lib/rubydb/execution/scan.rb +49 -49
  226. data/lib/rubydb/execution/sequential_scan.rb +63 -63
  227. data/lib/rubydb/execution/sort_executor.rb +180 -185
  228. data/lib/rubydb/execution/update_executor.rb +160 -162
  229. data/lib/rubydb/functions/aggregate.rb +70 -70
  230. data/lib/rubydb/functions/date_functions.rb +274 -278
  231. data/lib/rubydb/functions/function.rb +85 -85
  232. data/lib/rubydb/functions/json_functions.rb +231 -215
  233. data/lib/rubydb/functions/numeric_functions.rb +346 -346
  234. data/lib/rubydb/functions/scalar.rb +52 -52
  235. data/lib/rubydb/functions/string_functions.rb +383 -383
  236. data/lib/rubydb/functions/system_functions.rb +258 -246
  237. data/lib/rubydb/history/as_of.rb +238 -238
  238. data/lib/rubydb/history/change.rb +105 -105
  239. data/lib/rubydb/history/history.rb +131 -131
  240. data/lib/rubydb/history/history_manager.rb +228 -229
  241. data/lib/rubydb/history/temporal_query.rb +202 -202
  242. data/lib/rubydb/history/timeline.rb +144 -144
  243. data/lib/rubydb/indexes/btree.rb +186 -186
  244. data/lib/rubydb/indexes/btree_cursor.rb +258 -258
  245. data/lib/rubydb/indexes/btree_node.rb +384 -385
  246. data/lib/rubydb/indexes/hash_index.rb +150 -150
  247. data/lib/rubydb/indexes/index.rb +71 -71
  248. data/lib/rubydb/indexes/index_manager.rb +408 -406
  249. data/lib/rubydb/indexes/index_scan.rb +466 -470
  250. data/lib/rubydb/migrations/migration.rb +253 -254
  251. data/lib/rubydb/migrations/migration_lock.rb +146 -146
  252. data/lib/rubydb/migrations/migration_manager.rb +187 -176
  253. data/lib/rubydb/migrations/migration_version.rb +71 -71
  254. data/lib/rubydb/migrations/schema_diff.rb +211 -211
  255. data/lib/rubydb/migrations/schema_version.rb +64 -64
  256. data/lib/rubydb/monitoring/events.rb +155 -160
  257. data/lib/rubydb/monitoring/health.rb +216 -222
  258. data/lib/rubydb/monitoring/logger.rb +188 -193
  259. data/lib/rubydb/monitoring/metrics.rb +363 -359
  260. data/lib/rubydb/monitoring/performance.rb +176 -176
  261. data/lib/rubydb/monitoring/statistics.rb +168 -170
  262. data/lib/rubydb/mvcc/garbage_collector.rb +199 -199
  263. data/lib/rubydb/mvcc/mvcc.rb +16 -16
  264. data/lib/rubydb/mvcc/snapshot.rb +146 -147
  265. data/lib/rubydb/mvcc/vacuum.rb +180 -180
  266. data/lib/rubydb/mvcc/version.rb +106 -106
  267. data/lib/rubydb/mvcc/version_store.rb +396 -398
  268. data/lib/rubydb/mvcc/visibility.rb +107 -109
  269. data/lib/rubydb/protocol/capabilities.rb +125 -125
  270. data/lib/rubydb/protocol/decoder.rb +142 -145
  271. data/lib/rubydb/protocol/encoder.rb +131 -136
  272. data/lib/rubydb/protocol/handshake.rb +306 -305
  273. data/lib/rubydb/protocol/message.rb +121 -121
  274. data/lib/rubydb/protocol/parameter_binder.rb +101 -0
  275. data/lib/rubydb/protocol/protocol.rb +276 -277
  276. data/lib/rubydb/protocol/version.rb +54 -54
  277. data/lib/rubydb/rails/adapter.rb +245 -239
  278. data/lib/rubydb/rails/connection.rb +312 -314
  279. data/lib/rubydb/rails/database_statements.rb +122 -122
  280. data/lib/rubydb/rails/migration.rb +131 -131
  281. data/lib/rubydb/rails/quoting.rb +109 -109
  282. data/lib/rubydb/rails/result.rb +117 -117
  283. data/lib/rubydb/rails/schema_statements.rb +339 -339
  284. data/lib/rubydb/rails/transaction.rb +105 -105
  285. data/lib/rubydb/rails/type.rb +126 -126
  286. data/lib/rubydb/recovery/checkpoint.rb +261 -257
  287. data/lib/rubydb/recovery/consistency.rb +457 -467
  288. data/lib/rubydb/recovery/corruption_detector.rb +5 -5
  289. data/lib/rubydb/recovery/crash_recovery.rb +381 -387
  290. data/lib/rubydb/recovery/recovery_manager.rb +204 -206
  291. data/lib/rubydb/recovery/redo.rb +235 -237
  292. data/lib/rubydb/recovery/undo.rb +204 -206
  293. data/lib/rubydb/replication/failover.rb +5 -5
  294. data/lib/rubydb/replication/fencing.rb +63 -63
  295. data/lib/rubydb/replication/primary.rb +461 -450
  296. data/lib/rubydb/replication/replica.rb +382 -384
  297. data/lib/rubydb/replication/replication_log.rb +194 -200
  298. data/lib/rubydb/replication/replication_manager.rb +307 -308
  299. data/lib/rubydb/replication/replication_slot.rb +293 -295
  300. data/lib/rubydb/replication/replication_stream.rb +198 -201
  301. data/lib/rubydb/rubydb.rb +564 -560
  302. data/lib/rubydb/security/access_control.rb +252 -254
  303. data/lib/rubydb/security/audit_log.rb +209 -213
  304. data/lib/rubydb/security/authentication.rb +302 -302
  305. data/lib/rubydb/security/authorization.rb +282 -282
  306. data/lib/rubydb/security/credentials.rb +192 -196
  307. data/lib/rubydb/security/password.rb +205 -215
  308. data/lib/rubydb/security/permissions.rb +74 -74
  309. data/lib/rubydb/security/role.rb +99 -101
  310. data/lib/rubydb/security/user.rb +86 -86
  311. data/lib/rubydb/server/connection.rb +383 -366
  312. data/lib/rubydb/server/connection_pool.rb +193 -193
  313. data/lib/rubydb/server/lifecycle.rb +227 -228
  314. data/lib/rubydb/server/listener.rb +139 -136
  315. data/lib/rubydb/server/request_handler.rb +277 -276
  316. data/lib/rubydb/server/server.rb +363 -364
  317. data/lib/rubydb/server/session.rb +371 -369
  318. data/lib/rubydb/server/worker.rb +206 -210
  319. data/lib/rubydb/server/worker_pool.rb +168 -168
  320. data/lib/rubydb/sql/ast/alter_table.rb +169 -169
  321. data/lib/rubydb/sql/ast/begin_transaction.rb +47 -47
  322. data/lib/rubydb/sql/ast/commit.rb +37 -37
  323. data/lib/rubydb/sql/ast/constraint.rb +92 -83
  324. data/lib/rubydb/sql/ast/create_database.rb +41 -41
  325. data/lib/rubydb/sql/ast/create_index.rb +61 -61
  326. data/lib/rubydb/sql/ast/create_schema.rb +52 -52
  327. data/lib/rubydb/sql/ast/create_table.rb +187 -187
  328. data/lib/rubydb/sql/ast/delete.rb +54 -54
  329. data/lib/rubydb/sql/ast/drop_database.rb +41 -41
  330. data/lib/rubydb/sql/ast/drop_index.rb +41 -41
  331. data/lib/rubydb/sql/ast/drop_schema.rb +49 -49
  332. data/lib/rubydb/sql/ast/drop_table.rb +49 -49
  333. data/lib/rubydb/sql/ast/explain.rb +64 -64
  334. data/lib/rubydb/sql/ast/expression.rb +617 -604
  335. data/lib/rubydb/sql/ast/insert.rb +66 -66
  336. data/lib/rubydb/sql/ast/node.rb +42 -42
  337. data/lib/rubydb/sql/ast/rollback.rb +63 -63
  338. data/lib/rubydb/sql/ast/savepoint.rb +59 -59
  339. data/lib/rubydb/sql/ast/select.rb +88 -88
  340. data/lib/rubydb/sql/ast/set_operation.rb +22 -20
  341. data/lib/rubydb/sql/ast/trigger.rb +35 -29
  342. data/lib/rubydb/sql/ast/update.rb +88 -88
  343. data/lib/rubydb/sql/ast/vacuum.rb +19 -19
  344. data/lib/rubydb/sql/ast/view.rb +38 -32
  345. data/lib/rubydb/sql/ast/with.rb +32 -32
  346. data/lib/rubydb/sql/grammar.rb +86 -86
  347. data/lib/rubydb/sql/keywords.rb +156 -156
  348. data/lib/rubydb/sql/lexer.rb +209 -214
  349. data/lib/rubydb/sql/operators.rb +100 -100
  350. data/lib/rubydb/sql/parser.rb +1167 -1170
  351. data/lib/rubydb/sql/planner/analyzer.rb +283 -302
  352. data/lib/rubydb/sql/planner/binder.rb +537 -550
  353. data/lib/rubydb/sql/planner/type_checker.rb +427 -431
  354. data/lib/rubydb/sql/token.rb +210 -210
  355. data/lib/rubydb/storage/buffer_frame.rb +44 -44
  356. data/lib/rubydb/storage/buffer_pool.rb +155 -155
  357. data/lib/rubydb/storage/database_lock.rb +74 -74
  358. data/lib/rubydb/storage/deserializer.rb +332 -342
  359. data/lib/rubydb/storage/engine.rb +2347 -2330
  360. data/lib/rubydb/storage/file_manager.rb +191 -187
  361. data/lib/rubydb/storage/free_space_map.rb +79 -81
  362. data/lib/rubydb/storage/page.rb +92 -94
  363. data/lib/rubydb/storage/page_allocator.rb +852 -855
  364. data/lib/rubydb/storage/page_header.rb +63 -67
  365. data/lib/rubydb/storage/page_manager.rb +127 -131
  366. data/lib/rubydb/storage/record.rb +58 -58
  367. data/lib/rubydb/storage/row.rb +78 -78
  368. data/lib/rubydb/storage/serializer.rb +51 -51
  369. data/lib/rubydb/storage/storage_layout.rb +151 -151
  370. data/lib/rubydb/storage/storage_manager.rb +114 -114
  371. data/lib/rubydb/storage/tuple.rb +458 -461
  372. data/lib/rubydb/storage/visibility_map.rb +964 -973
  373. data/lib/rubydb/transactions/commit_manager.rb +219 -220
  374. data/lib/rubydb/transactions/isolation.rb +98 -98
  375. data/lib/rubydb/transactions/lock.rb +76 -76
  376. data/lib/rubydb/transactions/lock_manager.rb +359 -362
  377. data/lib/rubydb/transactions/savepoint.rb +142 -143
  378. data/lib/rubydb/transactions/transaction.rb +214 -215
  379. data/lib/rubydb/transactions/transaction_id.rb +84 -84
  380. data/lib/rubydb/transactions/transaction_log.rb +256 -257
  381. data/lib/rubydb/transactions/transaction_manager.rb +434 -435
  382. data/lib/rubydb/types/bigint.rb +36 -36
  383. data/lib/rubydb/types/blob.rb +37 -37
  384. data/lib/rubydb/types/boolean.rb +34 -34
  385. data/lib/rubydb/types/date.rb +39 -39
  386. data/lib/rubydb/types/decimal.rb +48 -48
  387. data/lib/rubydb/types/float.rb +34 -34
  388. data/lib/rubydb/types/integer.rb +36 -36
  389. data/lib/rubydb/types/json.rb +41 -41
  390. data/lib/rubydb/types/null.rb +34 -34
  391. data/lib/rubydb/types/smallint.rb +36 -36
  392. data/lib/rubydb/types/text.rb +37 -37
  393. data/lib/rubydb/types/time.rb +46 -46
  394. data/lib/rubydb/types/timestamp.rb +39 -39
  395. data/lib/rubydb/types/type.rb +119 -119
  396. data/lib/rubydb/types/uuid.rb +47 -47
  397. data/lib/rubydb/types/varchar.rb +37 -37
  398. data/lib/rubydb/version.rb +32 -32
  399. data/lib/rubydb/wal/archive.rb +190 -193
  400. data/lib/rubydb/wal/checkpoint.rb +181 -183
  401. data/lib/rubydb/wal/lsn.rb +94 -94
  402. data/lib/rubydb/wal/reader.rb +259 -260
  403. data/lib/rubydb/wal/record.rb +105 -105
  404. data/lib/rubydb/wal/segment.rb +193 -193
  405. data/lib/rubydb/wal/wal.rb +480 -452
  406. data/lib/rubydb/wal/writer.rb +236 -236
  407. data/lib/rubydb.rb +7 -7
  408. data/packaging/docker/docker-compose.failover.yml +43 -43
  409. data/packaging/homebrew/rubydb.rb +19 -19
  410. data/rubydb.gemspec +60 -57
  411. data/scripts/benchmark +7 -7
  412. data/scripts/durability_drill +37 -37
  413. data/scripts/fuzz +63 -63
  414. data/scripts/release +45 -40
  415. data/scripts/release_check +43 -43
  416. data/scripts/replication_failover_drill +268 -250
  417. data/scripts/replication_network_failover_drill +287 -255
  418. data/scripts/restore_drill +45 -45
  419. data/scripts/security +45 -0
  420. metadata +54 -1
@@ -1,214 +1,209 @@
1
- # frozen_string_literal: true
2
-
3
- require "strscan"
4
- require_relative "../errors/error"
5
- require_relative "../errors/parser_error"
6
-
7
- module RubyDB
8
- module SQL
9
- # SQL Lexer - converts SQL text into tokens
10
- class Lexer
11
- attr_reader :tokens, :current_position
12
-
13
- def initialize(text)
14
- @text = text
15
- @scanner = StringScanner.new(text)
16
- @tokens = []
17
- @current_position = { line: 1, column: 1 }
18
- @line_start = 0
19
- @current_position[:line] = 1
20
- @current_position[:column] = 1
21
- end
22
-
23
- def tokenize
24
- @tokens = []
25
- until @scanner.eos?
26
- skip_whitespace
27
- break if @scanner.eos?
28
-
29
- token = scan_token
30
- @tokens << token if token
31
- end
32
- @tokens << Token.new(Token::Type::EOF, line: @current_position[:line], column: @current_position[:column])
33
- @tokens
34
- end
35
-
36
- private
37
-
38
- def skip_whitespace
39
- while true
40
- case
41
- when @scanner.scan(/\s+/)
42
- update_position($&)
43
- when @scanner.scan(/--[^\n]*/)
44
- update_position($&)
45
- next
46
- when @scanner.scan(/\/\*.*?\*\//m)
47
- update_position($&)
48
- next
49
- else
50
- break
51
- end
52
- end
53
- end
54
-
55
- def scan_token
56
- pos = { line: @current_position[:line], column: @current_position[:column] }
57
-
58
- token =
59
- case
60
- when @scanner.scan(/[a-zA-Z_][a-zA-Z0-9_]*/)
61
- word = @scanner.matched.upcase
62
- update_position($&)
63
- if Keywords.keyword?(word)
64
- Token.new(Keywords.token_type(word), word, **pos)
65
- else
66
- Token.new(Token::Type::IDENTIFIER, @scanner.matched, **pos)
67
- end
68
-
69
- when @scanner.scan(/'(?:''|[^'])*'/)
70
- update_position($&)
71
- Token.new(Token::Type::STRING, @scanner.matched[1..-2].gsub("''", "'"), **pos)
72
-
73
- when @scanner.scan(/"[^"]*"/)
74
- update_position($&)
75
- Token.new(Token::Type::IDENTIFIER, @scanner.matched[1..-2], **pos)
76
-
77
- when @scanner.scan(/`[^`]*`/)
78
- update_position($&)
79
- Token.new(Token::Type::IDENTIFIER, @scanner.matched[1..-2], **pos)
80
-
81
- when @scanner.scan(/\d+\.\d+/)
82
- update_position($&)
83
- Token.new(Token::Type::NUMBER, @scanner.matched.to_f, **pos)
84
-
85
- when @scanner.scan(/\d+/)
86
- update_position($&)
87
- Token.new(Token::Type::NUMBER, @scanner.matched.to_i, **pos)
88
-
89
- when @scanner.scan(/\?/)
90
- update_position($&)
91
- Token.new(Token::Type::PARAMETER, nil, **pos)
92
-
93
- when @scanner.scan(/\$\d+/)
94
- update_position($&)
95
- Token.new(Token::Type::PARAMETER, @scanner.matched[1..-1].to_i, **pos)
96
-
97
- when @scanner.scan(/<=/)
98
- update_position($&)
99
- Token.new(Token::Type::LTE, "<=", **pos)
100
-
101
- when @scanner.scan(/>=/)
102
- update_position($&)
103
- Token.new(Token::Type::GTE, ">=", **pos)
104
-
105
- when @scanner.scan(/!=|<>/)
106
- update_position($&)
107
- Token.new(Token::Type::NE, @scanner.matched, **pos)
108
-
109
- when @scanner.scan(/=/)
110
- update_position($&)
111
- Token.new(Token::Type::EQ, "=", **pos)
112
-
113
- when @scanner.scan(/</)
114
- update_position($&)
115
- Token.new(Token::Type::LT, "<", **pos)
116
-
117
- when @scanner.scan(/>/)
118
- update_position($&)
119
- Token.new(Token::Type::GT, ">", **pos)
120
-
121
- when @scanner.scan(/\+/)
122
- update_position($&)
123
- Token.new(Token::Type::PLUS, "+", **pos)
124
-
125
- when @scanner.scan(/-/)
126
- update_position($&)
127
- Token.new(Token::Type::MINUS, "-", **pos)
128
-
129
- when @scanner.scan(/\*/)
130
- update_position($&)
131
- Token.new(Token::Type::STAR, "*", **pos)
132
-
133
- when @scanner.scan(/\//)
134
- update_position($&)
135
- Token.new(Token::Type::SLASH, "/", **pos)
136
-
137
- when @scanner.scan(/\%/)
138
- update_position($&)
139
- Token.new(Token::Type::PERCENT, "%", **pos)
140
-
141
- when @scanner.scan(/\(/)
142
- update_position($&)
143
- Token.new(Token::Type::LPAREN, "(", **pos)
144
-
145
- when @scanner.scan(/\)/)
146
- update_position($&)
147
- Token.new(Token::Type::RPAREN, ")", **pos)
148
-
149
- when @scanner.scan(/,/)
150
- update_position($&)
151
- Token.new(Token::Type::COMMA, ",", **pos)
152
-
153
- when @scanner.scan(/;/)
154
- update_position($&)
155
- Token.new(Token::Type::SEMICOLON, ";", **pos)
156
-
157
- when @scanner.scan(/\./)
158
- update_position($&)
159
- Token.new(Token::Type::DOT, ".", **pos)
160
-
161
- when @scanner.scan(/\[/)
162
- update_position($&)
163
- Token.new(Token::Type::LBRACKET, "[", **pos)
164
-
165
- when @scanner.scan(/\]/)
166
- update_position($&)
167
- Token.new(Token::Type::RBRACKET, "]", **pos)
168
-
169
- when @scanner.scan(/\{/)
170
- update_position($&)
171
- Token.new(Token::Type::LBRACE, "{", **pos)
172
-
173
- when @scanner.scan(/\}/)
174
- update_position($&)
175
- Token.new(Token::Type::RBRACE, "}", **pos)
176
-
177
- when @scanner.scan(/&/)
178
- update_position($&)
179
- Token.new(Token::Type::AMPERSAND, "&", **pos)
180
-
181
- when @scanner.scan(/\|/)
182
- update_position($&)
183
- Token.new(Token::Type::PIPE, "|", **pos)
184
-
185
- when @scanner.scan(/\^/)
186
- update_position($&)
187
- Token.new(Token::Type::CARET, "^", **pos)
188
-
189
- when @scanner.scan(/~/)
190
- update_position($&)
191
- Token.new(Token::Type::TILDE, "~", **pos)
192
-
193
- else
194
- char = @scanner.getch
195
- update_position(char)
196
- raise RubyDB::ParserError, "Unexpected character #{char.inspect} at #{@current_position[:line]}:#{@current_position[:column]}"
197
- end
198
-
199
- token
200
- end
201
-
202
- def update_position(text)
203
- text ||= @scanner.matched
204
- lines = text.count("\n")
205
- if lines > 0
206
- @current_position[:line] += lines
207
- @current_position[:column] = text.length - text.rindex("\n")
208
- else
209
- @current_position[:column] += text.length
210
- end
211
- end
212
- end
213
- end
214
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "strscan"
4
+ require_relative "../errors/error"
5
+ require_relative "../errors/parser_error"
6
+
7
+ module RubyDB
8
+ module SQL
9
+ # SQL Lexer - converts SQL text into tokens
10
+ class Lexer
11
+ attr_reader :tokens, :current_position
12
+
13
+ def initialize(text)
14
+ @text = text
15
+ @scanner = StringScanner.new(text)
16
+ @tokens = []
17
+ @current_position = {line: 1, column: 1}
18
+ @line_start = 0
19
+ @current_position[:line] = 1
20
+ @current_position[:column] = 1
21
+ end
22
+
23
+ def tokenize
24
+ @tokens = []
25
+ until @scanner.eos?
26
+ skip_whitespace
27
+ break if @scanner.eos?
28
+
29
+ token = scan_token
30
+ @tokens << token if token
31
+ end
32
+ @tokens << Token.new(Token::Type::EOF, line: @current_position[:line], column: @current_position[:column])
33
+ @tokens
34
+ end
35
+
36
+ private
37
+
38
+ def skip_whitespace
39
+ loop do
40
+ if @scanner.scan(/\s+/)
41
+ update_position($&)
42
+ elsif @scanner.scan(/--[^\n]*/)
43
+ update_position($&)
44
+ next
45
+ elsif @scanner.scan(/\/\*.*?\*\//m)
46
+ update_position($&)
47
+ next
48
+ else
49
+ break
50
+ end
51
+ end
52
+ end
53
+
54
+ def scan_token
55
+ pos = {line: @current_position[:line], column: @current_position[:column]}
56
+
57
+ if @scanner.scan(/[a-zA-Z_][a-zA-Z0-9_]*/)
58
+ word = @scanner.matched.upcase
59
+ update_position($&)
60
+ if Keywords.keyword?(word)
61
+ Token.new(Keywords.token_type(word), word, **pos)
62
+ else
63
+ Token.new(Token::Type::IDENTIFIER, @scanner.matched, **pos)
64
+ end
65
+
66
+ elsif @scanner.scan(/'(?:''|[^'])*'/)
67
+ update_position($&)
68
+ Token.new(Token::Type::STRING, @scanner.matched[1..-2].gsub("''", "'"), **pos)
69
+
70
+ elsif @scanner.scan(/"[^"]*"/)
71
+ update_position($&)
72
+ Token.new(Token::Type::IDENTIFIER, @scanner.matched[1..-2], **pos)
73
+
74
+ elsif @scanner.scan(/`[^`]*`/)
75
+ update_position($&)
76
+ Token.new(Token::Type::IDENTIFIER, @scanner.matched[1..-2], **pos)
77
+
78
+ elsif @scanner.scan(/\d+\.\d+/)
79
+ update_position($&)
80
+ Token.new(Token::Type::NUMBER, @scanner.matched.to_f, **pos)
81
+
82
+ elsif @scanner.scan(/\d+/)
83
+ update_position($&)
84
+ Token.new(Token::Type::NUMBER, @scanner.matched.to_i, **pos)
85
+
86
+ elsif @scanner.scan("?")
87
+ update_position($&)
88
+ Token.new(Token::Type::PARAMETER, nil, **pos)
89
+
90
+ elsif @scanner.scan(/\$\d+/)
91
+ update_position($&)
92
+ Token.new(Token::Type::PARAMETER, @scanner.matched[1..].to_i, **pos)
93
+
94
+ elsif @scanner.scan("<=")
95
+ update_position($&)
96
+ Token.new(Token::Type::LTE, "<=", **pos)
97
+
98
+ elsif @scanner.scan(">=")
99
+ update_position($&)
100
+ Token.new(Token::Type::GTE, ">=", **pos)
101
+
102
+ elsif @scanner.scan(/!=|<>/)
103
+ update_position($&)
104
+ Token.new(Token::Type::NE, @scanner.matched, **pos)
105
+
106
+ elsif @scanner.scan("=")
107
+ update_position($&)
108
+ Token.new(Token::Type::EQ, "=", **pos)
109
+
110
+ elsif @scanner.scan("<")
111
+ update_position($&)
112
+ Token.new(Token::Type::LT, "<", **pos)
113
+
114
+ elsif @scanner.scan(">")
115
+ update_position($&)
116
+ Token.new(Token::Type::GT, ">", **pos)
117
+
118
+ elsif @scanner.scan("+")
119
+ update_position($&)
120
+ Token.new(Token::Type::PLUS, "+", **pos)
121
+
122
+ elsif @scanner.scan("-")
123
+ update_position($&)
124
+ Token.new(Token::Type::MINUS, "-", **pos)
125
+
126
+ elsif @scanner.scan("*")
127
+ update_position($&)
128
+ Token.new(Token::Type::STAR, "*", **pos)
129
+
130
+ elsif @scanner.scan("/")
131
+ update_position($&)
132
+ Token.new(Token::Type::SLASH, "/", **pos)
133
+
134
+ elsif @scanner.scan("%")
135
+ update_position($&)
136
+ Token.new(Token::Type::PERCENT, "%", **pos)
137
+
138
+ elsif @scanner.scan("(")
139
+ update_position($&)
140
+ Token.new(Token::Type::LPAREN, "(", **pos)
141
+
142
+ elsif @scanner.scan(")")
143
+ update_position($&)
144
+ Token.new(Token::Type::RPAREN, ")", **pos)
145
+
146
+ elsif @scanner.scan(",")
147
+ update_position($&)
148
+ Token.new(Token::Type::COMMA, ",", **pos)
149
+
150
+ elsif @scanner.scan(";")
151
+ update_position($&)
152
+ Token.new(Token::Type::SEMICOLON, ";", **pos)
153
+
154
+ elsif @scanner.scan(".")
155
+ update_position($&)
156
+ Token.new(Token::Type::DOT, ".", **pos)
157
+
158
+ elsif @scanner.scan("[")
159
+ update_position($&)
160
+ Token.new(Token::Type::LBRACKET, "[", **pos)
161
+
162
+ elsif @scanner.scan("]")
163
+ update_position($&)
164
+ Token.new(Token::Type::RBRACKET, "]", **pos)
165
+
166
+ elsif @scanner.scan("{")
167
+ update_position($&)
168
+ Token.new(Token::Type::LBRACE, "{", **pos)
169
+
170
+ elsif @scanner.scan("}")
171
+ update_position($&)
172
+ Token.new(Token::Type::RBRACE, "}", **pos)
173
+
174
+ elsif @scanner.scan("&")
175
+ update_position($&)
176
+ Token.new(Token::Type::AMPERSAND, "&", **pos)
177
+
178
+ elsif @scanner.scan("|")
179
+ update_position($&)
180
+ Token.new(Token::Type::PIPE, "|", **pos)
181
+
182
+ elsif @scanner.scan("^")
183
+ update_position($&)
184
+ Token.new(Token::Type::CARET, "^", **pos)
185
+
186
+ elsif @scanner.scan("~")
187
+ update_position($&)
188
+ Token.new(Token::Type::TILDE, "~", **pos)
189
+
190
+ else
191
+ char = @scanner.getch
192
+ update_position(char)
193
+ raise RubyDB::ParserError, "Unexpected character #{char.inspect} at #{@current_position[:line]}:#{@current_position[:column]}"
194
+ end
195
+ end
196
+
197
+ def update_position(text)
198
+ text ||= @scanner.matched
199
+ lines = text.count("\n")
200
+ if lines > 0
201
+ @current_position[:line] += lines
202
+ @current_position[:column] = text.length - text.rindex("\n")
203
+ else
204
+ @current_position[:column] += text.length
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
@@ -1,100 +1,100 @@
1
- # frozen_string_literal: true
2
-
3
- module RubyDB
4
- module SQL
5
- # SQL operator definitions
6
- module Operators
7
- # Operator precedence (higher = binds tighter)
8
- PRECEDENCE = {
9
- Token::Type::DOT => 18,
10
- Token::Type::LBRACKET => 18,
11
- Token::Type::TILDE => 17,
12
- Token::Type::STAR => 16,
13
- Token::Type::SLASH => 16,
14
- Token::Type::PERCENT => 16,
15
- Token::Type::PLUS => 15,
16
- Token::Type::MINUS => 15,
17
- Token::Type::AMPERSAND => 14,
18
- Token::Type::PIPE => 13,
19
- Token::Type::CARET => 12,
20
- Token::Type::LT => 11,
21
- Token::Type::LTE => 11,
22
- Token::Type::GT => 11,
23
- Token::Type::GTE => 11,
24
- Token::Type::EQ => 10,
25
- Token::Type::NE => 10,
26
- Token::Type::LIKE => 9,
27
- Token::Type::ILIKE => 9,
28
- Token::Type::NOT => 8,
29
- Token::Type::AND => 7,
30
- Token::Type::OR => 6,
31
- Token::Type::BETWEEN => 5,
32
- Token::Type::IN => 5,
33
- Token::Type::IS => 5
34
- }.freeze
35
-
36
- # Operator associativity: :left, :right, or :nonassoc
37
- ASSOCIATIVITY = {
38
- Token::Type::DOT => :left,
39
- Token::Type::LBRACKET => :left,
40
- Token::Type::TILDE => :right,
41
- Token::Type::STAR => :left,
42
- Token::Type::SLASH => :left,
43
- Token::Type::PERCENT => :left,
44
- Token::Type::PLUS => :left,
45
- Token::Type::MINUS => :left,
46
- Token::Type::AMPERSAND => :left,
47
- Token::Type::PIPE => :left,
48
- Token::Type::CARET => :left,
49
- Token::Type::LT => :nonassoc,
50
- Token::Type::LTE => :nonassoc,
51
- Token::Type::GT => :nonassoc,
52
- Token::Type::GTE => :nonassoc,
53
- Token::Type::EQ => :nonassoc,
54
- Token::Type::NE => :nonassoc,
55
- Token::Type::LIKE => :nonassoc,
56
- Token::Type::ILIKE => :nonassoc,
57
- Token::Type::NOT => :right,
58
- Token::Type::AND => :left,
59
- Token::Type::OR => :left,
60
- Token::Type::BETWEEN => :nonassoc,
61
- Token::Type::IN => :nonassoc,
62
- Token::Type::IS => :nonassoc
63
- }.freeze
64
-
65
- def self.precedence(token_type)
66
- PRECEDENCE[token_type] || 0
67
- end
68
-
69
- def self.associativity(token_type)
70
- ASSOCIATIVITY[token_type] || :left
71
- end
72
-
73
- def self.comparison?(token_type)
74
- [Token::Type::EQ, Token::Type::NE, Token::Type::LT,
75
- Token::Type::LTE, Token::Type::GT, Token::Type::GTE,
76
- Token::Type::LIKE, Token::Type::ILIKE, Token::Type::BETWEEN,
77
- Token::Type::IN, Token::Type::IS].include?(token_type)
78
- end
79
-
80
- def self.logical?(token_type)
81
- [Token::Type::AND, Token::Type::OR, Token::Type::NOT].include?(token_type)
82
- end
83
-
84
- def self.arithmetic?(token_type)
85
- [Token::Type::PLUS, Token::Type::MINUS, Token::Type::STAR,
86
- Token::Type::SLASH, Token::Type::PERCENT].include?(token_type)
87
- end
88
-
89
- def self.bitwise?(token_type)
90
- [Token::Type::AMPERSAND, Token::Type::PIPE,
91
- Token::Type::CARET, Token::Type::TILDE].include?(token_type)
92
- end
93
-
94
- def self.unary?(token_type)
95
- [Token::Type::PLUS, Token::Type::MINUS, Token::Type::TILDE,
96
- Token::Type::NOT].include?(token_type)
97
- end
98
- end
99
- end
100
- end
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ # SQL operator definitions
6
+ module Operators
7
+ # Operator precedence (higher = binds tighter)
8
+ PRECEDENCE = {
9
+ Token::Type::DOT => 18,
10
+ Token::Type::LBRACKET => 18,
11
+ Token::Type::TILDE => 17,
12
+ Token::Type::STAR => 16,
13
+ Token::Type::SLASH => 16,
14
+ Token::Type::PERCENT => 16,
15
+ Token::Type::PLUS => 15,
16
+ Token::Type::MINUS => 15,
17
+ Token::Type::AMPERSAND => 14,
18
+ Token::Type::PIPE => 13,
19
+ Token::Type::CARET => 12,
20
+ Token::Type::LT => 11,
21
+ Token::Type::LTE => 11,
22
+ Token::Type::GT => 11,
23
+ Token::Type::GTE => 11,
24
+ Token::Type::EQ => 10,
25
+ Token::Type::NE => 10,
26
+ Token::Type::LIKE => 9,
27
+ Token::Type::ILIKE => 9,
28
+ Token::Type::NOT => 8,
29
+ Token::Type::AND => 7,
30
+ Token::Type::OR => 6,
31
+ Token::Type::BETWEEN => 5,
32
+ Token::Type::IN => 5,
33
+ Token::Type::IS => 5
34
+ }.freeze
35
+
36
+ # Operator associativity: :left, :right, or :nonassoc
37
+ ASSOCIATIVITY = {
38
+ Token::Type::DOT => :left,
39
+ Token::Type::LBRACKET => :left,
40
+ Token::Type::TILDE => :right,
41
+ Token::Type::STAR => :left,
42
+ Token::Type::SLASH => :left,
43
+ Token::Type::PERCENT => :left,
44
+ Token::Type::PLUS => :left,
45
+ Token::Type::MINUS => :left,
46
+ Token::Type::AMPERSAND => :left,
47
+ Token::Type::PIPE => :left,
48
+ Token::Type::CARET => :left,
49
+ Token::Type::LT => :nonassoc,
50
+ Token::Type::LTE => :nonassoc,
51
+ Token::Type::GT => :nonassoc,
52
+ Token::Type::GTE => :nonassoc,
53
+ Token::Type::EQ => :nonassoc,
54
+ Token::Type::NE => :nonassoc,
55
+ Token::Type::LIKE => :nonassoc,
56
+ Token::Type::ILIKE => :nonassoc,
57
+ Token::Type::NOT => :right,
58
+ Token::Type::AND => :left,
59
+ Token::Type::OR => :left,
60
+ Token::Type::BETWEEN => :nonassoc,
61
+ Token::Type::IN => :nonassoc,
62
+ Token::Type::IS => :nonassoc
63
+ }.freeze
64
+
65
+ def self.precedence(token_type)
66
+ PRECEDENCE[token_type] || 0
67
+ end
68
+
69
+ def self.associativity(token_type)
70
+ ASSOCIATIVITY[token_type] || :left
71
+ end
72
+
73
+ def self.comparison?(token_type)
74
+ [Token::Type::EQ, Token::Type::NE, Token::Type::LT,
75
+ Token::Type::LTE, Token::Type::GT, Token::Type::GTE,
76
+ Token::Type::LIKE, Token::Type::ILIKE, Token::Type::BETWEEN,
77
+ Token::Type::IN, Token::Type::IS].include?(token_type)
78
+ end
79
+
80
+ def self.logical?(token_type)
81
+ [Token::Type::AND, Token::Type::OR, Token::Type::NOT].include?(token_type)
82
+ end
83
+
84
+ def self.arithmetic?(token_type)
85
+ [Token::Type::PLUS, Token::Type::MINUS, Token::Type::STAR,
86
+ Token::Type::SLASH, Token::Type::PERCENT].include?(token_type)
87
+ end
88
+
89
+ def self.bitwise?(token_type)
90
+ [Token::Type::AMPERSAND, Token::Type::PIPE,
91
+ Token::Type::CARET, Token::Type::TILDE].include?(token_type)
92
+ end
93
+
94
+ def self.unary?(token_type)
95
+ [Token::Type::PLUS, Token::Type::MINUS, Token::Type::TILDE,
96
+ Token::Type::NOT].include?(token_type)
97
+ end
98
+ end
99
+ end
100
+ end