sequel-duckdb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.kiro/specs/advanced-sql-features-implementation/design.md +24 -0
- data/.kiro/specs/advanced-sql-features-implementation/requirements.md +43 -0
- data/.kiro/specs/advanced-sql-features-implementation/tasks.md +24 -0
- data/.kiro/specs/duckdb-sql-syntax-compatibility/design.md +258 -0
- data/.kiro/specs/duckdb-sql-syntax-compatibility/requirements.md +84 -0
- data/.kiro/specs/duckdb-sql-syntax-compatibility/tasks.md +94 -0
- data/.kiro/specs/edge-cases-and-validation-fixes/requirements.md +32 -0
- data/.kiro/specs/integration-test-database-setup/design.md +0 -0
- data/.kiro/specs/integration-test-database-setup/requirements.md +117 -0
- data/.kiro/specs/sequel-duckdb-adapter/design.md +542 -0
- data/.kiro/specs/sequel-duckdb-adapter/requirements.md +202 -0
- data/.kiro/specs/sequel-duckdb-adapter/tasks.md +247 -0
- data/.kiro/specs/sql-expression-handling-fix/design.md +298 -0
- data/.kiro/specs/sql-expression-handling-fix/requirements.md +86 -0
- data/.kiro/specs/sql-expression-handling-fix/tasks.md +22 -0
- data/.kiro/specs/test-infrastructure-improvements/requirements.md +106 -0
- data/.kiro/steering/product.md +22 -0
- data/.kiro/steering/structure.md +88 -0
- data/.kiro/steering/tech.md +124 -0
- data/.kiro/steering/testing.md +192 -0
- data/.rubocop.yml +103 -0
- data/.yardopts +8 -0
- data/API_DOCUMENTATION.md +919 -0
- data/CHANGELOG.md +131 -0
- data/LICENSE +21 -0
- data/MIGRATION_EXAMPLES.md +740 -0
- data/PERFORMANCE_OPTIMIZATIONS.md +723 -0
- data/README.md +692 -0
- data/Rakefile +27 -0
- data/TASK_10.2_IMPLEMENTATION_SUMMARY.md +164 -0
- data/docs/DUCKDB_SQL_PATTERNS.md +410 -0
- data/docs/TASK_12_VERIFICATION_SUMMARY.md +122 -0
- data/lib/sequel/adapters/duckdb.rb +256 -0
- data/lib/sequel/adapters/shared/duckdb.rb +2349 -0
- data/lib/sequel/duckdb/version.rb +16 -0
- data/lib/sequel/duckdb.rb +43 -0
- data/sig/sequel/duckdb.rbs +6 -0
- metadata +235 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
# Requirements Document
|
2
|
+
|
3
|
+
## Introduction
|
4
|
+
|
5
|
+
This specification addresses database schema and setup issues in integration tests for the sequel-duckdb adapter. Many integration tests are failing because they attempt to perform database operations on tables that don't exist or haven't been properly set up. The test infrastructure needs proper database setup, schema management, and teardown procedures to ensure integration tests run reliably.
|
6
|
+
|
7
|
+
## Requirements
|
8
|
+
|
9
|
+
### Requirement 1: Automatic Test Database Setup
|
10
|
+
|
11
|
+
**User Story:** As a developer running integration tests for the sequel-duckdb adapter, I want test databases to be automatically set up with required schemas, so that tests can focus on functionality rather than database preparation.
|
12
|
+
|
13
|
+
#### Acceptance Criteria
|
14
|
+
|
15
|
+
1. WHEN integration tests start THEN required test tables SHALL be automatically created
|
16
|
+
2. WHEN tests need specific schemas THEN they SHALL be set up before test execution
|
17
|
+
3. WHEN tests require sample data THEN it SHALL be inserted during setup
|
18
|
+
4. WHEN test setup fails THEN clear error messages SHALL indicate the specific failure
|
19
|
+
|
20
|
+
### Requirement 2: Test Table Schema Management
|
21
|
+
|
22
|
+
**User Story:** As a developer writing integration tests for the sequel-duckdb adapter, I want standardized test table schemas that cover all data types and scenarios, so that I can test comprehensive functionality without custom setup.
|
23
|
+
|
24
|
+
#### Acceptance Criteria
|
25
|
+
|
26
|
+
1. WHEN tests need a users table THEN it SHALL include common columns (id, name, email, age, active, created_at)
|
27
|
+
2. WHEN tests need type testing THEN tables SHALL include all supported DuckDB data types
|
28
|
+
3. WHEN tests need relationship testing THEN foreign key relationships SHALL be properly set up
|
29
|
+
4. WHEN tests need constraint testing THEN appropriate constraints SHALL be defined
|
30
|
+
|
31
|
+
### Requirement 3: Test Data Fixtures
|
32
|
+
|
33
|
+
**User Story:** As a developer running integration tests for the sequel-duckdb adapter, I want consistent test data fixtures, so that tests produce predictable results and can be easily debugged.
|
34
|
+
|
35
|
+
#### Acceptance Criteria
|
36
|
+
|
37
|
+
1. WHEN tests need sample users THEN standardized user records SHALL be available
|
38
|
+
2. WHEN tests need relational data THEN properly linked records SHALL be provided
|
39
|
+
3. WHEN tests need edge case data THEN fixtures SHALL include boundary values and special cases
|
40
|
+
4. WHEN tests need large datasets THEN performance test fixtures SHALL be available
|
41
|
+
|
42
|
+
### Requirement 4: Database Cleanup and Isolation
|
43
|
+
|
44
|
+
**User Story:** As a developer running integration tests for the sequel-duckdb adapter, I want each test to run in isolation with a clean database state, so that tests don't interfere with each other and produce consistent results.
|
45
|
+
|
46
|
+
#### Acceptance Criteria
|
47
|
+
|
48
|
+
1. WHEN each test starts THEN it SHALL have a clean database state
|
49
|
+
2. WHEN tests modify data THEN changes SHALL not affect subsequent tests
|
50
|
+
3. WHEN tests create temporary tables THEN they SHALL be cleaned up after the test
|
51
|
+
4. WHEN tests fail THEN database state SHALL be reset for the next test
|
52
|
+
|
53
|
+
### Requirement 5: Schema Introspection Test Support
|
54
|
+
|
55
|
+
**User Story:** As a developer testing schema introspection features of the sequel-duckdb adapter, I want test databases with comprehensive schema elements, so that I can verify all introspection functionality works correctly.
|
56
|
+
|
57
|
+
#### Acceptance Criteria
|
58
|
+
|
59
|
+
1. WHEN testing table listing THEN multiple test tables SHALL exist
|
60
|
+
2. WHEN testing column introspection THEN tables SHALL have diverse column types and properties
|
61
|
+
3. WHEN testing index introspection THEN various index types SHALL be present
|
62
|
+
4. WHEN testing constraint introspection THEN different constraint types SHALL be available
|
63
|
+
|
64
|
+
### Requirement 6: Transaction Testing Support
|
65
|
+
|
66
|
+
**User Story:** As a developer testing transaction functionality of the sequel-duckdb adapter, I want test scenarios that properly exercise transaction behavior, so that I can verify commit, rollback, and isolation work correctly.
|
67
|
+
|
68
|
+
#### Acceptance Criteria
|
69
|
+
|
70
|
+
1. WHEN testing transactions THEN test data SHALL support rollback verification
|
71
|
+
2. WHEN testing nested transactions THEN appropriate test scenarios SHALL be available
|
72
|
+
3. WHEN testing transaction isolation THEN concurrent test scenarios SHALL be supported
|
73
|
+
4. WHEN testing transaction errors THEN error conditions SHALL be reproducible
|
74
|
+
|
75
|
+
### Requirement 7: Performance Testing Database Setup
|
76
|
+
|
77
|
+
**User Story:** As a developer testing performance aspects of the sequel-duckdb adapter, I want test databases with appropriate data volumes, so that I can verify performance optimizations work correctly.
|
78
|
+
|
79
|
+
#### Acceptance Criteria
|
80
|
+
|
81
|
+
1. WHEN testing bulk operations THEN large datasets SHALL be available
|
82
|
+
2. WHEN testing query performance THEN indexed and non-indexed scenarios SHALL be set up
|
83
|
+
3. WHEN testing memory usage THEN datasets of various sizes SHALL be available
|
84
|
+
4. WHEN testing streaming THEN large result sets SHALL be available for testing
|
85
|
+
|
86
|
+
### Requirement 8: Error Condition Testing Setup
|
87
|
+
|
88
|
+
**User Story:** As a developer testing error handling in the sequel-duckdb adapter, I want test scenarios that reliably reproduce error conditions, so that I can verify proper error handling and exception mapping.
|
89
|
+
|
90
|
+
#### Acceptance Criteria
|
91
|
+
|
92
|
+
1. WHEN testing constraint violations THEN tables with constraints SHALL be available
|
93
|
+
2. WHEN testing connection errors THEN invalid database scenarios SHALL be reproducible
|
94
|
+
3. WHEN testing SQL errors THEN scenarios that trigger DuckDB errors SHALL be available
|
95
|
+
4. WHEN testing type errors THEN incompatible data scenarios SHALL be set up
|
96
|
+
|
97
|
+
### Requirement 9: Test Database Configuration
|
98
|
+
|
99
|
+
**User Story:** As a developer running integration tests for the sequel-duckdb adapter, I want flexible test database configuration, so that tests can run in different environments and scenarios.
|
100
|
+
|
101
|
+
#### Acceptance Criteria
|
102
|
+
|
103
|
+
1. WHEN tests run in CI THEN database configuration SHALL be automatically appropriate
|
104
|
+
2. WHEN tests run locally THEN database configuration SHALL support development workflows
|
105
|
+
3. WHEN tests need specific DuckDB settings THEN configuration SHALL be easily adjustable
|
106
|
+
4. WHEN tests need different database sizes THEN memory limits SHALL be configurable
|
107
|
+
|
108
|
+
### Requirement 10: Test Helper Integration
|
109
|
+
|
110
|
+
**User Story:** As a developer writing integration tests for the sequel-duckdb adapter, I want test helpers that work seamlessly with the database setup, so that I can write tests efficiently without boilerplate code.
|
111
|
+
|
112
|
+
#### Acceptance Criteria
|
113
|
+
|
114
|
+
1. WHEN using test helpers THEN they SHALL work with the established database schema
|
115
|
+
2. WHEN creating test data THEN helpers SHALL use the standardized fixtures
|
116
|
+
3. WHEN verifying results THEN helpers SHALL understand the test database structure
|
117
|
+
4. WHEN cleaning up THEN helpers SHALL properly reset database state
|
@@ -0,0 +1,542 @@
|
|
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
|
+
```ruby
|
109
|
+
# lib/sequel/adapters/duckdb.rb
|
110
|
+
class Sequel::DuckDB::Database < Sequel::Database
|
111
|
+
include Sequel::DuckDB::DatabaseMethods
|
112
|
+
set_adapter_scheme :duckdb
|
113
|
+
|
114
|
+
# Dataset factory
|
115
|
+
def dataset_class_default
|
116
|
+
Dataset
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# lib/sequel/adapters/shared/duckdb.rb
|
121
|
+
module Sequel::DuckDB::DatabaseMethods
|
122
|
+
# Connection management
|
123
|
+
def connect(server)
|
124
|
+
opts = server_opts(server)
|
125
|
+
if opts[:database] == ':memory:'
|
126
|
+
::DuckDB::Database.new
|
127
|
+
else
|
128
|
+
::DuckDB::Database.new(opts[:database])
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def disconnect_connection(conn)
|
133
|
+
conn.close if conn && !conn.closed?
|
134
|
+
end
|
135
|
+
|
136
|
+
def valid_connection?(conn)
|
137
|
+
conn && !conn.closed?
|
138
|
+
end
|
139
|
+
|
140
|
+
# Schema introspection (works with mock databases)
|
141
|
+
def tables(opts = OPTS)
|
142
|
+
schema_parse_tables(opts)
|
143
|
+
end
|
144
|
+
|
145
|
+
def schema(table, opts = OPTS)
|
146
|
+
schema_parse_table(table, opts)
|
147
|
+
end
|
148
|
+
|
149
|
+
def indexes(table, opts = OPTS)
|
150
|
+
schema_parse_indexes(table, opts)
|
151
|
+
end
|
152
|
+
|
153
|
+
# SQL execution
|
154
|
+
def execute(sql, opts = OPTS, &block)
|
155
|
+
synchronize(opts[:server]) do |conn|
|
156
|
+
return execute_statement(conn, sql, opts, &block)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def execute_insert(sql, opts = OPTS)
|
161
|
+
execute(sql, opts)
|
162
|
+
end
|
163
|
+
|
164
|
+
def execute_update(sql, opts = OPTS)
|
165
|
+
execute(sql, opts)
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
# Schema parsing methods (mockable)
|
171
|
+
def schema_parse_tables(opts)
|
172
|
+
# Query DuckDB system tables or return mock data
|
173
|
+
end
|
174
|
+
|
175
|
+
def schema_parse_table(table_name, opts)
|
176
|
+
# Parse individual table schema
|
177
|
+
end
|
178
|
+
|
179
|
+
def schema_parse_indexes(table_name, opts)
|
180
|
+
# Parse table indexes
|
181
|
+
end
|
182
|
+
|
183
|
+
def execute_statement(conn, sql, opts, &block)
|
184
|
+
# Execute SQL against DuckDB connection
|
185
|
+
end
|
186
|
+
end
|
187
|
+
```
|
188
|
+
|
189
|
+
### 2. Dataset Class
|
190
|
+
|
191
|
+
**Purpose:** SQL generation and query execution, fully compatible with Sequel's mock database testing, following sequel-hexspace structure.
|
192
|
+
|
193
|
+
**Key Methods for SQL Generation Testing:**
|
194
|
+
```ruby
|
195
|
+
# lib/sequel/adapters/duckdb.rb
|
196
|
+
class Sequel::DuckDB::Dataset < Sequel::Dataset
|
197
|
+
include Sequel::DuckDB::DatasetMethods
|
198
|
+
end
|
199
|
+
|
200
|
+
# lib/sequel/adapters/shared/duckdb.rb
|
201
|
+
module Sequel::DuckDB::DatasetMethods
|
202
|
+
# SQL generation (works with mock databases)
|
203
|
+
def select_sql
|
204
|
+
sql = @opts[:sql]
|
205
|
+
return sql if sql
|
206
|
+
|
207
|
+
columns_sql = select_columns_sql
|
208
|
+
sql = "SELECT #{columns_sql}"
|
209
|
+
|
210
|
+
if supports_select_all_and_offset? && @opts[:offset]
|
211
|
+
sql = select_all_sql(sql)
|
212
|
+
end
|
213
|
+
|
214
|
+
select_from_sql(sql)
|
215
|
+
select_join_sql(sql)
|
216
|
+
select_where_sql(sql)
|
217
|
+
select_group_sql(sql)
|
218
|
+
select_having_sql(sql)
|
219
|
+
select_order_sql(sql)
|
220
|
+
select_limit_sql(sql)
|
221
|
+
|
222
|
+
sql
|
223
|
+
end
|
224
|
+
|
225
|
+
def insert_sql(*values)
|
226
|
+
return static_sql if @opts[:sql]
|
227
|
+
|
228
|
+
columns = insert_columns
|
229
|
+
values = insert_values(values)
|
230
|
+
|
231
|
+
"INSERT INTO #{source_list(@opts[:from])} #{literal(columns)} VALUES #{values.map{|v| literal(v)}.join(', ')}"
|
232
|
+
end
|
233
|
+
|
234
|
+
def update_sql(values = OPTS)
|
235
|
+
return static_sql if @opts[:sql]
|
236
|
+
|
237
|
+
sql = "UPDATE #{source_list(@opts[:from])} SET "
|
238
|
+
sql << update_columns_sql(values)
|
239
|
+
select_where_sql(sql)
|
240
|
+
sql
|
241
|
+
end
|
242
|
+
|
243
|
+
def delete_sql
|
244
|
+
return static_sql if @opts[:sql]
|
245
|
+
|
246
|
+
sql = "DELETE FROM #{source_list(@opts[:from])}"
|
247
|
+
select_where_sql(sql)
|
248
|
+
sql
|
249
|
+
end
|
250
|
+
|
251
|
+
# Query execution
|
252
|
+
def fetch_rows(sql, &block)
|
253
|
+
execute(sql) do |result|
|
254
|
+
result.each(&block)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
# DuckDB capabilities
|
259
|
+
def supports_window_functions?
|
260
|
+
true
|
261
|
+
end
|
262
|
+
|
263
|
+
def supports_cte?
|
264
|
+
true
|
265
|
+
end
|
266
|
+
|
267
|
+
def supports_returning?
|
268
|
+
false
|
269
|
+
end
|
270
|
+
|
271
|
+
def supports_select_all_and_offset?
|
272
|
+
true
|
273
|
+
end
|
274
|
+
|
275
|
+
def quote_identifiers_default
|
276
|
+
true
|
277
|
+
end
|
278
|
+
|
279
|
+
private
|
280
|
+
|
281
|
+
# DuckDB-specific SQL generation
|
282
|
+
def select_limit_sql(sql)
|
283
|
+
if limit = @opts[:limit]
|
284
|
+
sql << " LIMIT #{literal(limit)}"
|
285
|
+
if offset = @opts[:offset]
|
286
|
+
sql << " OFFSET #{literal(offset)}"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def literal_string_append(sql, s)
|
292
|
+
sql << "'" << s.gsub("'", "''") << "'"
|
293
|
+
end
|
294
|
+
|
295
|
+
def literal_date(date)
|
296
|
+
"'#{date}'"
|
297
|
+
end
|
298
|
+
|
299
|
+
def literal_datetime(datetime)
|
300
|
+
"'#{datetime.strftime('%Y-%m-%d %H:%M:%S')}'"
|
301
|
+
end
|
302
|
+
|
303
|
+
def literal_time(time)
|
304
|
+
"'#{time.strftime('%H:%M:%S')}'"
|
305
|
+
end
|
306
|
+
|
307
|
+
def literal_boolean(value)
|
308
|
+
value ? 'TRUE' : 'FALSE'
|
309
|
+
end
|
310
|
+
end
|
311
|
+
```
|
312
|
+
|
313
|
+
## Data Models
|
314
|
+
|
315
|
+
### Connection Configuration
|
316
|
+
|
317
|
+
```ruby
|
318
|
+
# Standard Sequel connection options
|
319
|
+
{
|
320
|
+
adapter: 'duckdb',
|
321
|
+
database: '/path/to/database.db', # or ':memory:' for in-memory
|
322
|
+
# DuckDB-specific options can be passed through
|
323
|
+
readonly: false,
|
324
|
+
config: {
|
325
|
+
threads: 4,
|
326
|
+
memory_limit: '1GB'
|
327
|
+
}
|
328
|
+
}
|
329
|
+
```
|
330
|
+
|
331
|
+
### Schema Information Format
|
332
|
+
|
333
|
+
Following Sequel's standard schema format:
|
334
|
+
|
335
|
+
```ruby
|
336
|
+
# Schema returned by Database#schema
|
337
|
+
[
|
338
|
+
[:id, {
|
339
|
+
type: :integer,
|
340
|
+
db_type: 'INTEGER',
|
341
|
+
allow_null: false,
|
342
|
+
default: nil,
|
343
|
+
primary_key: true,
|
344
|
+
auto_increment: true
|
345
|
+
}],
|
346
|
+
[:name, {
|
347
|
+
type: :string,
|
348
|
+
db_type: 'VARCHAR',
|
349
|
+
allow_null: true,
|
350
|
+
default: nil,
|
351
|
+
primary_key: false,
|
352
|
+
auto_increment: false
|
353
|
+
}]
|
354
|
+
]
|
355
|
+
```
|
356
|
+
|
357
|
+
## Error Handling
|
358
|
+
|
359
|
+
### Error Mapping Strategy
|
360
|
+
|
361
|
+
Map DuckDB errors to appropriate Sequel exceptions:
|
362
|
+
|
363
|
+
```ruby
|
364
|
+
# Within Database class
|
365
|
+
private
|
366
|
+
|
367
|
+
def database_error_classes
|
368
|
+
[::DuckDB::Error]
|
369
|
+
end
|
370
|
+
|
371
|
+
def database_exception_sqlstate(exception, opts)
|
372
|
+
# Extract SQL state from DuckDB error if available
|
373
|
+
end
|
374
|
+
|
375
|
+
def database_exception_use_sqlstates?
|
376
|
+
true
|
377
|
+
end
|
378
|
+
```
|
379
|
+
|
380
|
+
## Testing Strategy
|
381
|
+
|
382
|
+
### Mock Database Support
|
383
|
+
|
384
|
+
The single-file structure ensures full compatibility with Sequel's mock database testing:
|
385
|
+
|
386
|
+
```ruby
|
387
|
+
# Test example
|
388
|
+
DB = Sequel.mock(host: 'duckdb')
|
389
|
+
DB.extend_datasets(Sequel::DuckDB::Dataset)
|
390
|
+
|
391
|
+
# SQL generation tests work without real database
|
392
|
+
dataset = DB[:users].where(name: 'John')
|
393
|
+
dataset.sql.should == "SELECT * FROM users WHERE (name = 'John')"
|
394
|
+
```
|
395
|
+
|
396
|
+
## Testing Strategy (CRITICAL COMPONENT)
|
397
|
+
|
398
|
+
### Test-Driven Development Approach
|
399
|
+
|
400
|
+
**MANDATORY**: All code implementation must follow strict Test-Driven Development (TDD):
|
401
|
+
|
402
|
+
1. **Write Tests First**: Before implementing any functionality, comprehensive tests must be written
|
403
|
+
2. **Red-Green-Refactor**: Follow the TDD cycle of failing tests, minimal implementation, then refactoring
|
404
|
+
3. **100% Coverage**: All implemented functionality must have corresponding test coverage
|
405
|
+
4. **Mock and Integration**: Use both mock database tests and real DuckDB integration tests
|
406
|
+
|
407
|
+
### Test Structure
|
408
|
+
|
409
|
+
Following sequel-hexspace test organization exactly:
|
410
|
+
|
411
|
+
```
|
412
|
+
test/
|
413
|
+
├── all.rb # Test runner - loads all test files
|
414
|
+
├── spec_helper.rb # Test configuration, setup, and shared utilities
|
415
|
+
├── database_test.rb # Database connection, transactions, and basic functionality
|
416
|
+
├── dataset_test.rb # Comprehensive SQL generation and query execution tests
|
417
|
+
├── schema_test.rb # Schema operations, introspection, and DDL tests
|
418
|
+
├── prepared_statement_test.rb # Prepared statement functionality and parameter binding
|
419
|
+
├── sql_test.rb # SQL generation syntax and correctness tests
|
420
|
+
└── type_test.rb # Data type handling, conversion, and mapping tests
|
421
|
+
```
|
422
|
+
|
423
|
+
### Test Categories and Requirements
|
424
|
+
|
425
|
+
1. **SQL Generation Tests (Unit Tests)**:
|
426
|
+
- Use Sequel's mock database functionality
|
427
|
+
- Test every SQL generation method
|
428
|
+
- Verify correct SQL syntax and structure
|
429
|
+
- Test edge cases and parameter handling
|
430
|
+
- Must be fast and not require database connections
|
431
|
+
|
432
|
+
2. **Integration Tests**:
|
433
|
+
- Use real DuckDB in-memory databases
|
434
|
+
- Test actual database operations
|
435
|
+
- Verify data persistence and retrieval
|
436
|
+
- Test connection management and error handling
|
437
|
+
- Test transaction behavior
|
438
|
+
|
439
|
+
3. **Schema Tests**:
|
440
|
+
- Test table creation, modification, and deletion
|
441
|
+
- Test index operations
|
442
|
+
- Test schema introspection accuracy
|
443
|
+
- Test constraint handling
|
444
|
+
- Test various DuckDB-specific schema features
|
445
|
+
|
446
|
+
4. **Type Conversion Tests**:
|
447
|
+
- Test Ruby ↔ DuckDB type mapping for all supported types
|
448
|
+
- Test edge cases and null handling
|
449
|
+
- Test precision and scale for numeric types
|
450
|
+
- Test date/time handling and timezone considerations
|
451
|
+
- Test binary data and text encoding
|
452
|
+
|
453
|
+
5. **Error Handling Tests**:
|
454
|
+
- Test proper Sequel exception mapping
|
455
|
+
- Test connection failure scenarios
|
456
|
+
- Test SQL syntax error handling
|
457
|
+
- Test constraint violation handling
|
458
|
+
- Test timeout and resource limit scenarios
|
459
|
+
|
460
|
+
### Test Implementation Requirements
|
461
|
+
|
462
|
+
- **Before Any Code**: Tests must be written before implementing functionality
|
463
|
+
- **Comprehensive Coverage**: Every public method must have test coverage
|
464
|
+
- **Edge Cases**: Tests must cover error conditions and edge cases
|
465
|
+
- **Performance**: Tests should include basic performance validation
|
466
|
+
- **Documentation**: Tests serve as executable documentation of expected behavior
|
467
|
+
|
468
|
+
## Performance Considerations
|
469
|
+
|
470
|
+
### Connection Management
|
471
|
+
|
472
|
+
- Use DuckDB's connection pooling capabilities
|
473
|
+
- Handle connection lifecycle properly
|
474
|
+
- Support both file and in-memory databases efficiently
|
475
|
+
|
476
|
+
### Query Optimization
|
477
|
+
|
478
|
+
- Leverage DuckDB's columnar storage advantages
|
479
|
+
- Support DuckDB's parallel query execution
|
480
|
+
- Use appropriate data types for optimal performance
|
481
|
+
|
482
|
+
### Memory Management
|
483
|
+
|
484
|
+
- Handle large result sets efficiently
|
485
|
+
- Support streaming results where possible
|
486
|
+
- Use DuckDB's memory-mapped file capabilities
|
487
|
+
|
488
|
+
## Security Considerations
|
489
|
+
|
490
|
+
### SQL Injection Prevention
|
491
|
+
|
492
|
+
- Use parameterized queries through Sequel's literal system
|
493
|
+
- Proper identifier quoting
|
494
|
+
- Input validation and sanitization
|
495
|
+
|
496
|
+
### Connection Security
|
497
|
+
|
498
|
+
- Support read-only database connections
|
499
|
+
- Proper handling of database file permissions
|
500
|
+
- Secure connection string parsing
|
501
|
+
|
502
|
+
## Deployment and Distribution
|
503
|
+
|
504
|
+
### Gem Structure
|
505
|
+
|
506
|
+
Following sequel-hexspace structure:
|
507
|
+
|
508
|
+
```text
|
509
|
+
sequel-duckdb/
|
510
|
+
├── lib/
|
511
|
+
│ └── sequel/
|
512
|
+
│ ├── duckdb.rb # Main module entry point
|
513
|
+
│ ├── duckdb/
|
514
|
+
│ │ └── version.rb # Version constant
|
515
|
+
│ └── adapters/
|
516
|
+
│ ├── duckdb.rb # Main adapter file (Database & Dataset classes)
|
517
|
+
│ └── shared/
|
518
|
+
│ └── duckdb.rb # Shared DuckDB-specific functionality
|
519
|
+
├── test/ # Test suite following sequel-hexspace pattern
|
520
|
+
├── README.md
|
521
|
+
├── CHANGELOG.md
|
522
|
+
├── LICENSE
|
523
|
+
├── sequel-duckdb.gemspec
|
524
|
+
└── Gemfile
|
525
|
+
```
|
526
|
+
|
527
|
+
### Dependencies
|
528
|
+
|
529
|
+
- **sequel**: Core Sequel gem (>= 5.0)
|
530
|
+
- **ruby-duckdb**: Official Ruby DuckDB client library
|
531
|
+
- **ruby**: Minimum Ruby version 3.1.0
|
532
|
+
|
533
|
+
### Compatibility Matrix
|
534
|
+
|
535
|
+
| Component | Version Requirements |
|
536
|
+
| ----------- | -------------------- |
|
537
|
+
| Ruby | >= 3.1.0 |
|
538
|
+
| Sequel | >= 5.0 |
|
539
|
+
| DuckDB | >= 0.8.0 |
|
540
|
+
| Ruby-DuckDB | >= 0.8.0 |
|
541
|
+
|
542
|
+
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.
|