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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/sequel/duckdb/version.rb +1 -1
- metadata +3 -57
- data/.beads/.beads-credential-key +0 -1
- data/.beads/.gitignore +0 -66
- data/.beads/README.md +0 -85
- data/.beads/config.yaml +0 -56
- data/.beads/hooks/post-checkout +0 -24
- data/.beads/hooks/post-merge +0 -24
- data/.beads/hooks/pre-commit +0 -24
- data/.beads/hooks/pre-push +0 -24
- data/.beads/hooks/prepare-commit-msg +0 -24
- data/.beads/metadata.json +0 -7
- data/.kiro/specs/advanced-sql-features-implementation/design.md +0 -26
- data/.kiro/specs/advanced-sql-features-implementation/requirements.md +0 -43
- data/.kiro/specs/advanced-sql-features-implementation/tasks.md +0 -28
- data/.kiro/specs/duckdb-sql-syntax-compatibility/design.md +0 -272
- data/.kiro/specs/duckdb-sql-syntax-compatibility/requirements.md +0 -84
- data/.kiro/specs/duckdb-sql-syntax-compatibility/tasks.md +0 -107
- data/.kiro/specs/edge-cases-and-validation-fixes/requirements.md +0 -32
- data/.kiro/specs/integration-test-database-setup/design.md +0 -0
- data/.kiro/specs/integration-test-database-setup/requirements.md +0 -117
- data/.kiro/specs/sequel-duckdb-adapter/design.md +0 -549
- data/.kiro/specs/sequel-duckdb-adapter/requirements.md +0 -202
- data/.kiro/specs/sequel-duckdb-adapter/tasks.md +0 -292
- data/.kiro/specs/sql-expression-handling-fix/design.md +0 -331
- data/.kiro/specs/sql-expression-handling-fix/requirements.md +0 -86
- data/.kiro/specs/sql-expression-handling-fix/tasks.md +0 -25
- data/.kiro/specs/test-infrastructure-improvements/requirements.md +0 -106
- data/.kiro/steering/product.md +0 -26
- data/.kiro/steering/structure.md +0 -88
- data/.kiro/steering/tech.md +0 -137
- data/.kiro/steering/testing.md +0 -213
- data/.mdformat.toml +0 -2
- data/.rubocop.yml +0 -161
- data/.rubocop_todo.yml +0 -323
- data/.yardopts +0 -8
- data/AGENTS.md +0 -180
- data/API_DOCUMENTATION.md +0 -943
- data/FINAL_STATUS.md +0 -99
- data/MIGRATION_EXAMPLES.md +0 -740
- data/PERFORMANCE_OPTIMIZATIONS.md +0 -726
- data/REFACTORING_SUMMARY.md +0 -264
- data/Rakefile +0 -43
- data/TASK_10.2_IMPLEMENTATION_SUMMARY.md +0 -182
- data/docs/DUCKDB_SQL_PATTERNS.md +0 -448
- data/docs/TASK_12_VERIFICATION_SUMMARY.md +0 -135
- data/justfile +0 -50
- data/plans/date_arithmetic.md +0 -420
- data/plans/engineering/Sequel.md +0 -471
- data/plans/engineering/duckdb.md +0 -712
- data/plans/engineering/sqlite.md +0 -453
- data/plans/mock_connection_bug.md +0 -333
- data/plans/mock_without_driver_gem.md +0 -371
- data/plans/over_engineering_analysis.md +0 -122
- data/plans/schema_management.md +0 -383
- 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.
|