sequel-duckdb 0.2.1 → 0.3.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/lib/sequel/duckdb/version.rb +1 -1
  4. metadata +3 -57
  5. data/.beads/.beads-credential-key +0 -1
  6. data/.beads/.gitignore +0 -66
  7. data/.beads/README.md +0 -85
  8. data/.beads/config.yaml +0 -56
  9. data/.beads/hooks/post-checkout +0 -24
  10. data/.beads/hooks/post-merge +0 -24
  11. data/.beads/hooks/pre-commit +0 -24
  12. data/.beads/hooks/pre-push +0 -24
  13. data/.beads/hooks/prepare-commit-msg +0 -24
  14. data/.beads/metadata.json +0 -7
  15. data/.kiro/specs/advanced-sql-features-implementation/design.md +0 -26
  16. data/.kiro/specs/advanced-sql-features-implementation/requirements.md +0 -43
  17. data/.kiro/specs/advanced-sql-features-implementation/tasks.md +0 -28
  18. data/.kiro/specs/duckdb-sql-syntax-compatibility/design.md +0 -272
  19. data/.kiro/specs/duckdb-sql-syntax-compatibility/requirements.md +0 -84
  20. data/.kiro/specs/duckdb-sql-syntax-compatibility/tasks.md +0 -107
  21. data/.kiro/specs/edge-cases-and-validation-fixes/requirements.md +0 -32
  22. data/.kiro/specs/integration-test-database-setup/design.md +0 -0
  23. data/.kiro/specs/integration-test-database-setup/requirements.md +0 -117
  24. data/.kiro/specs/sequel-duckdb-adapter/design.md +0 -549
  25. data/.kiro/specs/sequel-duckdb-adapter/requirements.md +0 -202
  26. data/.kiro/specs/sequel-duckdb-adapter/tasks.md +0 -292
  27. data/.kiro/specs/sql-expression-handling-fix/design.md +0 -331
  28. data/.kiro/specs/sql-expression-handling-fix/requirements.md +0 -86
  29. data/.kiro/specs/sql-expression-handling-fix/tasks.md +0 -25
  30. data/.kiro/specs/test-infrastructure-improvements/requirements.md +0 -106
  31. data/.kiro/steering/product.md +0 -26
  32. data/.kiro/steering/structure.md +0 -88
  33. data/.kiro/steering/tech.md +0 -137
  34. data/.kiro/steering/testing.md +0 -213
  35. data/.mdformat.toml +0 -2
  36. data/.rubocop.yml +0 -161
  37. data/.rubocop_todo.yml +0 -323
  38. data/.yardopts +0 -8
  39. data/AGENTS.md +0 -180
  40. data/API_DOCUMENTATION.md +0 -943
  41. data/FINAL_STATUS.md +0 -99
  42. data/MIGRATION_EXAMPLES.md +0 -740
  43. data/PERFORMANCE_OPTIMIZATIONS.md +0 -726
  44. data/REFACTORING_SUMMARY.md +0 -264
  45. data/Rakefile +0 -43
  46. data/TASK_10.2_IMPLEMENTATION_SUMMARY.md +0 -182
  47. data/docs/DUCKDB_SQL_PATTERNS.md +0 -448
  48. data/docs/TASK_12_VERIFICATION_SUMMARY.md +0 -135
  49. data/justfile +0 -50
  50. data/plans/date_arithmetic.md +0 -420
  51. data/plans/engineering/Sequel.md +0 -471
  52. data/plans/engineering/duckdb.md +0 -712
  53. data/plans/engineering/sqlite.md +0 -453
  54. data/plans/mock_connection_bug.md +0 -333
  55. data/plans/mock_without_driver_gem.md +0 -371
  56. data/plans/over_engineering_analysis.md +0 -122
  57. data/plans/schema_management.md +0 -383
  58. data/sig/sequel/duckdb.rbs +0 -6
@@ -1,549 +0,0 @@
1
- # Design Document
2
-
3
- ## Overview
4
-
5
- The Sequel DuckDB adapter will be implemented as a Ruby gem that extends Sequel's database abstraction layer to support DuckDB databases. The design follows Sequel's established adapter architecture patterns, with jeremyevans/sequel as the primary reference, sequel-hexspace as secondary reference for adapter structure, and sequel_impala as tertiary reference for implementation patterns, while leveraging the official ruby-duckdb gem for low-level database connectivity.
6
-
7
- The adapter will be structured following the established Sequel extension pattern with the Sequel::DuckDB namespace, ensuring proper integration with Sequel's testing framework and development workflow.
8
-
9
- ## Architecture
10
-
11
- ### High-Level Architecture
12
-
13
- ```mermaid
14
- graph TB
15
- A[Sequel Application] --> B[Sequel Core]
16
- B --> C[DuckDB Adapter]
17
- C --> D[Ruby-DuckDB Gem]
18
- D --> E[DuckDB Engine]
19
-
20
- subgraph "Single Adapter File"
21
- F[Database Class]
22
- G[Dataset Class]
23
- H[Helper Methods]
24
- end
25
-
26
- C --> F
27
- C --> G
28
- C --> H
29
- ```
30
-
31
- ### File Structure
32
-
33
- Following the sequel-hexspace structure pattern:
34
-
35
- ```text
36
- lib/
37
- └── sequel/
38
- ├── duckdb.rb # Main module entry point
39
- ├── duckdb/
40
- │ └── version.rb # Version constant
41
- └── adapters/
42
- ├── duckdb.rb # Main adapter file (Database & Dataset classes)
43
- └── shared/
44
- └── duckdb.rb # Shared DuckDB-specific functionality
45
- ```
46
-
47
- This structure ensures:
48
-
49
- - **sequel-hexspace Compatibility**: Follows the exact same structure as sequel-hexspace
50
- - **Proper Adapter Registration**: Uses Sequel's standard adapter loading mechanism
51
- - **Shared Functionality**: Common methods separated into shared/duckdb.rb
52
- - **Mock Database Support**: SQL generation works with Sequel's mock database objects
53
- - **Maintenance Organization**: Clear separation between main adapter and shared utilities
54
-
55
- ## Components and Interfaces
56
-
57
- ### Main Adapter Structure
58
-
59
- Following sequel-hexspace pattern:
60
-
61
- ```ruby
62
- # lib/sequel/adapters/duckdb.rb
63
- require 'sequel/adapters/shared/duckdb'
64
-
65
- module Sequel
66
- module DuckDB
67
- class Database < Sequel::Database
68
- include Sequel::DuckDB::DatabaseMethods
69
- set_adapter_scheme :duckdb
70
-
71
- # Core database methods
72
- end
73
-
74
- class Dataset < Sequel::Dataset
75
- include Sequel::DuckDB::DatasetMethods
76
-
77
- # SQL generation and query execution
78
- end
79
- end
80
-
81
- # Register the adapter
82
- Database.adapter_scheme :duckdb, DuckDB::Database
83
- end
84
- ```
85
-
86
- ```ruby
87
- # lib/sequel/adapters/shared/duckdb.rb
88
- require 'duckdb'
89
-
90
- module Sequel
91
- module DuckDB
92
- module DatabaseMethods
93
- # Shared database functionality
94
- end
95
-
96
- module DatasetMethods
97
- # Shared dataset functionality
98
- end
99
- end
100
- end
101
- ```
102
-
103
- ### 1. Database Class
104
-
105
- **Purpose:** Main database class that handles connections, transactions, and schema operations, following sequel-hexspace structure.
106
-
107
- **Key Methods for Mock Database Compatibility:**
108
-
109
- ```ruby
110
- # lib/sequel/adapters/duckdb.rb
111
- class Sequel::DuckDB::Database < Sequel::Database
112
- include Sequel::DuckDB::DatabaseMethods
113
- set_adapter_scheme :duckdb
114
-
115
- # Dataset factory
116
- def dataset_class_default
117
- Dataset
118
- end
119
- end
120
-
121
- # lib/sequel/adapters/shared/duckdb.rb
122
- module Sequel::DuckDB::DatabaseMethods
123
- # Connection management
124
- def connect(server)
125
- opts = server_opts(server)
126
- if opts[:database] == ':memory:'
127
- ::DuckDB::Database.new
128
- else
129
- ::DuckDB::Database.new(opts[:database])
130
- end
131
- end
132
-
133
- def disconnect_connection(conn)
134
- conn.close if conn && !conn.closed?
135
- end
136
-
137
- def valid_connection?(conn)
138
- conn && !conn.closed?
139
- end
140
-
141
- # Schema introspection (works with mock databases)
142
- def tables(opts = OPTS)
143
- schema_parse_tables(opts)
144
- end
145
-
146
- def schema(table, opts = OPTS)
147
- schema_parse_table(table, opts)
148
- end
149
-
150
- def indexes(table, opts = OPTS)
151
- schema_parse_indexes(table, opts)
152
- end
153
-
154
- # SQL execution
155
- def execute(sql, opts = OPTS, &block)
156
- synchronize(opts[:server]) do |conn|
157
- return execute_statement(conn, sql, opts, &block)
158
- end
159
- end
160
-
161
- def execute_insert(sql, opts = OPTS)
162
- execute(sql, opts)
163
- end
164
-
165
- def execute_update(sql, opts = OPTS)
166
- execute(sql, opts)
167
- end
168
-
169
- private
170
-
171
- # Schema parsing methods (mockable)
172
- def schema_parse_tables(opts)
173
- # Query DuckDB system tables or return mock data
174
- end
175
-
176
- def schema_parse_table(table_name, opts)
177
- # Parse individual table schema
178
- end
179
-
180
- def schema_parse_indexes(table_name, opts)
181
- # Parse table indexes
182
- end
183
-
184
- def execute_statement(conn, sql, opts, &block)
185
- # Execute SQL against DuckDB connection
186
- end
187
- end
188
- ```
189
-
190
- ### 2. Dataset Class
191
-
192
- **Purpose:** SQL generation and query execution, fully compatible with Sequel's mock database testing, following sequel-hexspace structure.
193
-
194
- **Key Methods for SQL Generation Testing:**
195
-
196
- ```ruby
197
- # lib/sequel/adapters/duckdb.rb
198
- class Sequel::DuckDB::Dataset < Sequel::Dataset
199
- include Sequel::DuckDB::DatasetMethods
200
- end
201
-
202
- # lib/sequel/adapters/shared/duckdb.rb
203
- module Sequel::DuckDB::DatasetMethods
204
- # SQL generation (works with mock databases)
205
- def select_sql
206
- sql = @opts[:sql]
207
- return sql if sql
208
-
209
- columns_sql = select_columns_sql
210
- sql = "SELECT #{columns_sql}"
211
-
212
- if supports_select_all_and_offset? && @opts[:offset]
213
- sql = select_all_sql(sql)
214
- end
215
-
216
- select_from_sql(sql)
217
- select_join_sql(sql)
218
- select_where_sql(sql)
219
- select_group_sql(sql)
220
- select_having_sql(sql)
221
- select_order_sql(sql)
222
- select_limit_sql(sql)
223
-
224
- sql
225
- end
226
-
227
- def insert_sql(*values)
228
- return static_sql if @opts[:sql]
229
-
230
- columns = insert_columns
231
- values = insert_values(values)
232
-
233
- "INSERT INTO #{source_list(@opts[:from])} #{literal(columns)} VALUES #{values.map{|v| literal(v)}.join(', ')}"
234
- end
235
-
236
- def update_sql(values = OPTS)
237
- return static_sql if @opts[:sql]
238
-
239
- sql = "UPDATE #{source_list(@opts[:from])} SET "
240
- sql << update_columns_sql(values)
241
- select_where_sql(sql)
242
- sql
243
- end
244
-
245
- def delete_sql
246
- return static_sql if @opts[:sql]
247
-
248
- sql = "DELETE FROM #{source_list(@opts[:from])}"
249
- select_where_sql(sql)
250
- sql
251
- end
252
-
253
- # Query execution
254
- def fetch_rows(sql, &block)
255
- execute(sql) do |result|
256
- result.each(&block)
257
- end
258
- end
259
-
260
- # DuckDB capabilities
261
- def supports_window_functions?
262
- true
263
- end
264
-
265
- def supports_cte?
266
- true
267
- end
268
-
269
- def supports_returning?
270
- false
271
- end
272
-
273
- def supports_select_all_and_offset?
274
- true
275
- end
276
-
277
- def quote_identifiers_default
278
- true
279
- end
280
-
281
- private
282
-
283
- # DuckDB-specific SQL generation
284
- def select_limit_sql(sql)
285
- if limit = @opts[:limit]
286
- sql << " LIMIT #{literal(limit)}"
287
- if offset = @opts[:offset]
288
- sql << " OFFSET #{literal(offset)}"
289
- end
290
- end
291
- end
292
-
293
- def literal_string_append(sql, s)
294
- sql << "'" << s.gsub("'", "''") << "'"
295
- end
296
-
297
- def literal_date(date)
298
- "'#{date}'"
299
- end
300
-
301
- def literal_datetime(datetime)
302
- "'#{datetime.strftime('%Y-%m-%d %H:%M:%S')}'"
303
- end
304
-
305
- def literal_time(time)
306
- "'#{time.strftime('%H:%M:%S')}'"
307
- end
308
-
309
- def literal_boolean(value)
310
- value ? 'TRUE' : 'FALSE'
311
- end
312
- end
313
- ```
314
-
315
- ## Data Models
316
-
317
- ### Connection Configuration
318
-
319
- ```ruby
320
- # Standard Sequel connection options
321
- {
322
- adapter: 'duckdb',
323
- database: '/path/to/database.db', # or ':memory:' for in-memory
324
- # DuckDB-specific options can be passed through
325
- readonly: false,
326
- config: {
327
- threads: 4,
328
- memory_limit: '1GB'
329
- }
330
- }
331
- ```
332
-
333
- ### Schema Information Format
334
-
335
- Following Sequel's standard schema format:
336
-
337
- ```ruby
338
- # Schema returned by Database#schema
339
- [
340
- [:id, {
341
- type: :integer,
342
- db_type: 'INTEGER',
343
- allow_null: false,
344
- default: nil,
345
- primary_key: true,
346
- auto_increment: true
347
- }],
348
- [:name, {
349
- type: :string,
350
- db_type: 'VARCHAR',
351
- allow_null: true,
352
- default: nil,
353
- primary_key: false,
354
- auto_increment: false
355
- }]
356
- ]
357
- ```
358
-
359
- ## Error Handling
360
-
361
- ### Error Mapping Strategy
362
-
363
- Map DuckDB errors to appropriate Sequel exceptions:
364
-
365
- ```ruby
366
- # Within Database class
367
- private
368
-
369
- def database_error_classes
370
- [::DuckDB::Error]
371
- end
372
-
373
- def database_exception_sqlstate(exception, opts)
374
- # Extract SQL state from DuckDB error if available
375
- end
376
-
377
- def database_exception_use_sqlstates?
378
- true
379
- end
380
- ```
381
-
382
- ## Testing Strategy
383
-
384
- ### Mock Database Support
385
-
386
- The single-file structure ensures full compatibility with Sequel's mock database testing:
387
-
388
- ```ruby
389
- # Test example
390
- DB = Sequel.mock(host: 'duckdb')
391
- DB.extend_datasets(Sequel::DuckDB::Dataset)
392
-
393
- # SQL generation tests work without real database
394
- dataset = DB[:users].where(name: 'John')
395
- dataset.sql.should == "SELECT * FROM users WHERE (name = 'John')"
396
- ```
397
-
398
- ## Testing Strategy (CRITICAL COMPONENT)
399
-
400
- ### Test-Driven Development Approach
401
-
402
- **MANDATORY**: All code implementation must follow strict Test-Driven Development (TDD):
403
-
404
- 1. **Write Tests First**: Before implementing any functionality, comprehensive tests must be written
405
- 2. **Red-Green-Refactor**: Follow the TDD cycle of failing tests, minimal implementation, then refactoring
406
- 3. **100% Coverage**: All implemented functionality must have corresponding test coverage
407
- 4. **Mock and Integration**: Use both mock database tests and real DuckDB integration tests
408
-
409
- ### Test Structure
410
-
411
- Following sequel-hexspace test organization exactly:
412
-
413
- ```
414
- test/
415
- ├── all.rb # Test runner - loads all test files
416
- ├── spec_helper.rb # Test configuration, setup, and shared utilities
417
- ├── database_test.rb # Database connection, transactions, and basic functionality
418
- ├── dataset_test.rb # Comprehensive SQL generation and query execution tests
419
- ├── schema_test.rb # Schema operations, introspection, and DDL tests
420
- ├── prepared_statement_test.rb # Prepared statement functionality and parameter binding
421
- ├── sql_test.rb # SQL generation syntax and correctness tests
422
- └── type_test.rb # Data type handling, conversion, and mapping tests
423
- ```
424
-
425
- ### Test Categories and Requirements
426
-
427
- 1. **SQL Generation Tests (Unit Tests)**:
428
-
429
- - Use Sequel's mock database functionality
430
- - Test every SQL generation method
431
- - Verify correct SQL syntax and structure
432
- - Test edge cases and parameter handling
433
- - Must be fast and not require database connections
434
-
435
- 2. **Integration Tests**:
436
-
437
- - Use real DuckDB in-memory databases
438
- - Test actual database operations
439
- - Verify data persistence and retrieval
440
- - Test connection management and error handling
441
- - Test transaction behavior
442
-
443
- 3. **Schema Tests**:
444
-
445
- - Test table creation, modification, and deletion
446
- - Test index operations
447
- - Test schema introspection accuracy
448
- - Test constraint handling
449
- - Test various DuckDB-specific schema features
450
-
451
- 4. **Type Conversion Tests**:
452
-
453
- - Test Ruby ↔ DuckDB type mapping for all supported types
454
- - Test edge cases and null handling
455
- - Test precision and scale for numeric types
456
- - Test date/time handling and timezone considerations
457
- - Test binary data and text encoding
458
-
459
- 5. **Error Handling Tests**:
460
-
461
- - Test proper Sequel exception mapping
462
- - Test connection failure scenarios
463
- - Test SQL syntax error handling
464
- - Test constraint violation handling
465
- - Test timeout and resource limit scenarios
466
-
467
- ### Test Implementation Requirements
468
-
469
- - **Before Any Code**: Tests must be written before implementing functionality
470
- - **Comprehensive Coverage**: Every public method must have test coverage
471
- - **Edge Cases**: Tests must cover error conditions and edge cases
472
- - **Performance**: Tests should include basic performance validation
473
- - **Documentation**: Tests serve as executable documentation of expected behavior
474
-
475
- ## Performance Considerations
476
-
477
- ### Connection Management
478
-
479
- - Use DuckDB's connection pooling capabilities
480
- - Handle connection lifecycle properly
481
- - Support both file and in-memory databases efficiently
482
-
483
- ### Query Optimization
484
-
485
- - Leverage DuckDB's columnar storage advantages
486
- - Support DuckDB's parallel query execution
487
- - Use appropriate data types for optimal performance
488
-
489
- ### Memory Management
490
-
491
- - Handle large result sets efficiently
492
- - Support streaming results where possible
493
- - Use DuckDB's memory-mapped file capabilities
494
-
495
- ## Security Considerations
496
-
497
- ### SQL Injection Prevention
498
-
499
- - Use parameterized queries through Sequel's literal system
500
- - Proper identifier quoting
501
- - Input validation and sanitization
502
-
503
- ### Connection Security
504
-
505
- - Support read-only database connections
506
- - Proper handling of database file permissions
507
- - Secure connection string parsing
508
-
509
- ## Deployment and Distribution
510
-
511
- ### Gem Structure
512
-
513
- Following sequel-hexspace structure:
514
-
515
- ```text
516
- sequel-duckdb/
517
- ├── lib/
518
- │ └── sequel/
519
- │ ├── duckdb.rb # Main module entry point
520
- │ ├── duckdb/
521
- │ │ └── version.rb # Version constant
522
- │ └── adapters/
523
- │ ├── duckdb.rb # Main adapter file (Database & Dataset classes)
524
- │ └── shared/
525
- │ └── duckdb.rb # Shared DuckDB-specific functionality
526
- ├── test/ # Test suite following sequel-hexspace pattern
527
- ├── README.md
528
- ├── CHANGELOG.md
529
- ├── LICENSE
530
- ├── sequel-duckdb.gemspec
531
- └── Gemfile
532
- ```
533
-
534
- ### Dependencies
535
-
536
- - **sequel**: Core Sequel gem (>= 5.0)
537
- - **ruby-duckdb**: Official Ruby DuckDB client library
538
- - **ruby**: Minimum Ruby version 3.1.0
539
-
540
- ### Compatibility Matrix
541
-
542
- | Component | Version Requirements |
543
- | ----------- | -------------------- |
544
- | Ruby | >= 3.1.0 |
545
- | Sequel | >= 5.0 |
546
- | DuckDB | >= 0.8.0 |
547
- | Ruby-DuckDB | >= 0.8.0 |
548
-
549
- This design ensures the adapter follows Sequel's established patterns while providing full DuckDB functionality and maintaining compatibility with Sequel's testing framework and mock database support.