dwh 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.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +36 -0
  3. data/CHANGELOG.md +5 -0
  4. data/LICENSE +21 -0
  5. data/README.md +130 -0
  6. data/Rakefile +42 -0
  7. data/docs/DWH/Adapters/Adapter.html +3053 -0
  8. data/docs/DWH/Adapters/Athena.html +1704 -0
  9. data/docs/DWH/Adapters/Boolean.html +121 -0
  10. data/docs/DWH/Adapters/Druid.html +1626 -0
  11. data/docs/DWH/Adapters/DuckDb.html +2012 -0
  12. data/docs/DWH/Adapters/MySql.html +1704 -0
  13. data/docs/DWH/Adapters/OpenAuthorizable/ClassMethods.html +265 -0
  14. data/docs/DWH/Adapters/OpenAuthorizable.html +1102 -0
  15. data/docs/DWH/Adapters/Postgres.html +2000 -0
  16. data/docs/DWH/Adapters/Snowflake.html +1662 -0
  17. data/docs/DWH/Adapters/SqlServer.html +2084 -0
  18. data/docs/DWH/Adapters/Trino.html +1835 -0
  19. data/docs/DWH/Adapters.html +129 -0
  20. data/docs/DWH/AuthenticationError.html +142 -0
  21. data/docs/DWH/Behaviors.html +767 -0
  22. data/docs/DWH/Capabilities.html +748 -0
  23. data/docs/DWH/Column.html +1115 -0
  24. data/docs/DWH/ConfigError.html +143 -0
  25. data/docs/DWH/ConnectionError.html +143 -0
  26. data/docs/DWH/DWHError.html +138 -0
  27. data/docs/DWH/ExecutionError.html +143 -0
  28. data/docs/DWH/Factory.html +1133 -0
  29. data/docs/DWH/Functions/Arrays.html +505 -0
  30. data/docs/DWH/Functions/Dates.html +1644 -0
  31. data/docs/DWH/Functions/ExtractDatePart.html +804 -0
  32. data/docs/DWH/Functions/Nulls.html +377 -0
  33. data/docs/DWH/Functions.html +846 -0
  34. data/docs/DWH/Logger.html +258 -0
  35. data/docs/DWH/OAuthError.html +138 -0
  36. data/docs/DWH/Settings.html +658 -0
  37. data/docs/DWH/StreamingStats.html +804 -0
  38. data/docs/DWH/Table.html +1260 -0
  39. data/docs/DWH/TableStats.html +583 -0
  40. data/docs/DWH/TokenExpiredError.html +142 -0
  41. data/docs/DWH/UnsupportedCapability.html +135 -0
  42. data/docs/DWH.html +220 -0
  43. data/docs/_index.html +471 -0
  44. data/docs/class_list.html +54 -0
  45. data/docs/css/common.css +1 -0
  46. data/docs/css/full_list.css +58 -0
  47. data/docs/css/style.css +503 -0
  48. data/docs/file.README.html +210 -0
  49. data/docs/file.adapters.html +514 -0
  50. data/docs/file.creating-adapters.html +497 -0
  51. data/docs/file.getting-started.html +288 -0
  52. data/docs/file.usage.html +446 -0
  53. data/docs/file_list.html +79 -0
  54. data/docs/frames.html +22 -0
  55. data/docs/guides/adapters.md +445 -0
  56. data/docs/guides/creating-adapters.md +430 -0
  57. data/docs/guides/getting-started.md +225 -0
  58. data/docs/guides/usage.md +378 -0
  59. data/docs/index.html +210 -0
  60. data/docs/js/app.js +344 -0
  61. data/docs/js/full_list.js +242 -0
  62. data/docs/js/jquery.js +4 -0
  63. data/docs/method_list.html +2038 -0
  64. data/docs/top-level-namespace.html +110 -0
  65. data/lib/dwh/adapters/athena.rb +359 -0
  66. data/lib/dwh/adapters/druid.rb +267 -0
  67. data/lib/dwh/adapters/duck_db.rb +235 -0
  68. data/lib/dwh/adapters/my_sql.rb +235 -0
  69. data/lib/dwh/adapters/open_authorizable.rb +215 -0
  70. data/lib/dwh/adapters/postgres.rb +250 -0
  71. data/lib/dwh/adapters/snowflake.rb +489 -0
  72. data/lib/dwh/adapters/sql_server.rb +257 -0
  73. data/lib/dwh/adapters/trino.rb +213 -0
  74. data/lib/dwh/adapters.rb +363 -0
  75. data/lib/dwh/behaviors.rb +67 -0
  76. data/lib/dwh/capabilities.rb +39 -0
  77. data/lib/dwh/column.rb +79 -0
  78. data/lib/dwh/errors.rb +29 -0
  79. data/lib/dwh/factory.rb +125 -0
  80. data/lib/dwh/functions/arrays.rb +42 -0
  81. data/lib/dwh/functions/dates.rb +162 -0
  82. data/lib/dwh/functions/extract_date_part.rb +70 -0
  83. data/lib/dwh/functions/nulls.rb +31 -0
  84. data/lib/dwh/functions.rb +86 -0
  85. data/lib/dwh/logger.rb +50 -0
  86. data/lib/dwh/settings/athena.yml +77 -0
  87. data/lib/dwh/settings/base.yml +81 -0
  88. data/lib/dwh/settings/databricks.yml +51 -0
  89. data/lib/dwh/settings/druid.yml +59 -0
  90. data/lib/dwh/settings/duckdb.yml +44 -0
  91. data/lib/dwh/settings/mysql.yml +67 -0
  92. data/lib/dwh/settings/postgres.yml +30 -0
  93. data/lib/dwh/settings/redshift.yml +52 -0
  94. data/lib/dwh/settings/snowflake.yml +45 -0
  95. data/lib/dwh/settings/sqlserver.yml +80 -0
  96. data/lib/dwh/settings/trino.yml +77 -0
  97. data/lib/dwh/settings.rb +79 -0
  98. data/lib/dwh/streaming_stats.rb +69 -0
  99. data/lib/dwh/table.rb +105 -0
  100. data/lib/dwh/table_stats.rb +51 -0
  101. data/lib/dwh/version.rb +5 -0
  102. data/lib/dwh.rb +54 -0
  103. data/sig/dwh.rbs +4 -0
  104. metadata +231 -0
@@ -0,0 +1,378 @@
1
+ <!--
2
+ # @title Advanced Usage
3
+ -->
4
+ # Advanced Usage Guide
5
+
6
+ This guide covers advanced features and usage patterns for DWH, including function translation, streaming, connection pooling, and performance optimization.
7
+
8
+ ## SQL Function Translation
9
+
10
+ DWH provides automatic translation of common SQL functions to database-specific syntax. This allows you to write database-agnostic code while leveraging native optimizations.
11
+
12
+ ### Date Functions
13
+
14
+ #### Date Truncation
15
+
16
+ ```ruby
17
+ # Truncate dates to different periods
18
+ adapter.truncate_date('week', 'created_at')
19
+ # PostgreSQL: DATE_TRUNC('week', created_at)
20
+ # SQL Server: DATETRUNC(week, created_at)
21
+ # MySQL: DATE_FORMAT(created_at, '%Y-%m-%d') - complex logic
22
+
23
+ adapter.truncate_date('month', 'order_date')
24
+ adapter.truncate_date('year', 'signup_date')
25
+ ```
26
+
27
+ #### Date Literals
28
+
29
+ ```ruby
30
+ # Create database-specific date literals
31
+ adapter.date_literal('2025-01-01')
32
+ # PostgreSQL: '2025-01-01'::DATE
33
+ # SQL Server: '2025-01-01'
34
+ # MySQL: '2025-01-01'
35
+
36
+ adapter.date_time_literal('2025-01-01 10:30:00')
37
+ # PostgreSQL: '2025-01-01 10:30:00'::TIMESTAMP
38
+ # SQL Server: '2025-01-01 10:30:00'
39
+ ```
40
+
41
+ #### Date Arithmetic
42
+
43
+ ```ruby
44
+ # Add/subtract time periods
45
+ adapter.date_add('created_at', 30, 'day')
46
+ # PostgreSQL: (created_at + '30 day'::interval)
47
+ # SQL Server: DATEADD(day, 30, created_at)
48
+ # MySQL: TIMESTAMPADD(day, 30, created_at)
49
+
50
+ adapter.date_diff('end_date', 'start_date', 'day')
51
+ # Calculate difference between dates in specified units
52
+ ```
53
+
54
+ #### Date Extraction
55
+
56
+ ```ruby
57
+ # Extract date parts
58
+ adapter.extract_year('created_at')
59
+ # PostgreSQL: extract(year from created_at)
60
+ # SQL Server: DATEPART(year, created_at)
61
+
62
+ adapter.extract_month('created_at')
63
+ adapter.extract_day_of_week('created_at')
64
+ adapter.extract_quarter('created_at')
65
+ ```
66
+
67
+ ### String Functions
68
+
69
+ ```ruby
70
+ # String manipulation
71
+ adapter.trim('column_name') # Remove whitespace
72
+ adapter.upper_case('column_name') # Convert to uppercase
73
+ adapter.lower_case('column_name') # Convert to lowercase
74
+
75
+ # Quoting and literals
76
+ adapter.quote('column_name') # Database-specific column quoting
77
+ adapter.string_literal('value') # Database-specific string literals
78
+ ```
79
+
80
+ ### Null Handling
81
+
82
+ ```ruby
83
+ # Null value handling
84
+ adapter.if_null('column1', "'default'")
85
+ # PostgreSQL: COALESCE(column1, 'default')
86
+ # SQL Server: ISNULL(column1, 'default')
87
+
88
+ adapter.null_if('column1', "'empty'")
89
+ # Returns NULL if column1 equals 'empty'
90
+
91
+ adapter.null_if_zero('numeric_column')
92
+ # Returns NULL if numeric_column equals 0
93
+ ```
94
+
95
+ ### Array Functions
96
+
97
+ Available for databases that support array operations (PostgreSQL, Druid):
98
+
99
+ ```ruby
100
+ # Check if array contains any values from a list
101
+ adapter.array_in_list('tags', "'tech', 'science'")
102
+ # PostgreSQL: tags && ARRAY['tech', 'science']
103
+ # Druid: MV_OVERLAP(tags, ARRAY['tech', 'science'])
104
+
105
+ # Check if array excludes all values from a list
106
+ adapter.array_exclude_list('categories', "'spam', 'test'")
107
+
108
+ # Unnest/explode array for joins
109
+ adapter.array_unnest_join('tags', 'tag_alias')
110
+ # PostgreSQL: CROSS JOIN UNNEST(tags) AS tag_alias
111
+ # Druid: CROSS JOIN UNNEST(MV_TO_ARRAY(tags)) tag_alias
112
+ ```
113
+
114
+ ### Type Casting
115
+
116
+ ```ruby
117
+ # Database-specific type casting
118
+ adapter.cast('column_name', 'INTEGER')
119
+ # PostgreSQL: column_name::INTEGER
120
+ # SQL Server: CAST(column_name AS INTEGER)
121
+ # MySQL: CAST(column_name AS SIGNED)
122
+ ```
123
+
124
+ ## Streaming and Large Result Sets
125
+
126
+ ### Basic Streaming
127
+
128
+ ```ruby
129
+ # Stream results directly to a file
130
+ File.open('large_export.csv', 'w') do |file|
131
+ adapter.execute_stream("SELECT * FROM large_table", file)
132
+ end
133
+
134
+ # Stream with custom processing
135
+ adapter.stream("SELECT * FROM large_table") do |chunk|
136
+ # Process each chunk as it arrives
137
+ process_data_chunk(chunk)
138
+ end
139
+ ```
140
+
141
+ ### Streaming with Statistics
142
+
143
+ ```ruby
144
+ # Create streaming stats collector
145
+ stats = DWH::StreamingStats.new(10_000) # Keep 10k rows in memory for preview
146
+
147
+ # Stream with stats tracking
148
+ File.open('export.csv', 'w') do |file|
149
+ exec_thread = adapter.execute_stream("SELECT * FROM large_table", file, stats: stats)
150
+
151
+ # Monitor progress in another thread
152
+ Thread.new do
153
+ loop do
154
+ puts "Processed: #{stats.total_rows} rows"
155
+ puts "Preview size: #{stats.data.size} rows"
156
+ puts "Max row size: #{stats.max_row_size} bytes"
157
+ sleep(5)
158
+ break unless exec_thread.alive?
159
+ end
160
+ end
161
+ end
162
+
163
+ # Access collected statistics
164
+ puts "Final count: #{stats.total_rows}"
165
+ puts "Sample data: #{stats.data.first(5)}"
166
+ ```
167
+
168
+ ### Memory Management
169
+
170
+ ```ruby
171
+ # Configure streaming stats memory usage
172
+ stats = DWH::StreamingStats.new(50_000) # Keep more data for larger previews
173
+
174
+ # Reset stats for reuse
175
+ stats.reset
176
+
177
+ # Manual memory management
178
+ stats.add_row(['col1', 'col2', 'col3'])
179
+ current_data = stats.data # Thread-safe access
180
+ ```
181
+
182
+ ## Connection Pooling
183
+
184
+ ### Creating Connection Pools
185
+
186
+ ```ruby
187
+ # Create a named connection pool
188
+ pool = DWH.pool('analytics_pool', :postgres, {
189
+ host: 'localhost',
190
+ database: 'analytics',
191
+ username: 'analyst',
192
+ password: 'password'
193
+ }, size: 10, timeout: 5)
194
+
195
+ # Multiple pools for different databases
196
+ etl_pool = DWH.pool('etl_pool', :postgres, etl_config, size: 5)
197
+ reporting_pool = DWH.pool('reporting_pool', :mysql, reporting_config, size: 15)
198
+ ```
199
+
200
+ ### Using Connection Pools
201
+
202
+ ```ruby
203
+ # Basic pool usage
204
+ pool.with do |connection|
205
+ results = connection.execute("SELECT COUNT(*) FROM users")
206
+ metadata = connection.metadata('orders')
207
+ end
208
+
209
+ # Nested pool operations
210
+ pool.with do |conn1|
211
+ users = conn1.execute("SELECT id FROM users LIMIT 100")
212
+
213
+ pool.with do |conn2| # Gets different connection from pool
214
+ orders = conn2.execute("SELECT * FROM orders WHERE user_id IN (?)",
215
+ users.map(&:first))
216
+ end
217
+ end
218
+ ```
219
+
220
+ ### Pool Management
221
+
222
+ ```ruby
223
+ # Check pool status
224
+ puts "Pool size: #{pool.size}"
225
+ puts "Available connections: #{pool.available}"
226
+ puts "Active connections: #{pool.in_use}"
227
+
228
+ # Graceful shutdown
229
+ DWH.shutdown('analytics_pool')
230
+
231
+ # Shutdown all pools
232
+ DWH.shutdown_all
233
+ ```
234
+
235
+ ## Database Capabilities Detection
236
+
237
+ ### Checking Capabilities
238
+
239
+ ```ruby
240
+ # Check what features are supported
241
+ if adapter.supports_window_functions?
242
+ query = "SELECT name, ROW_NUMBER() OVER (ORDER BY created_at) FROM users"
243
+ results = adapter.execute(query)
244
+ end
245
+ ```
246
+
247
+ ### Available Capability Checks
248
+
249
+ - `supports_table_join?` - Basic JOIN support
250
+ - `supports_full_join?` - FULL OUTER JOIN support
251
+ - `supports_cross_join?` - CROSS JOIN support
252
+ - `supports_sub_queries?` - Subquery support
253
+ - `supports_common_table_expressions?` - CTE support
254
+ - `supports_temp_tables?` - Temporary table support
255
+ - `supports_window_functions?` - Window function support
256
+ - `supports_array_functions?` - Array operation support
257
+
258
+ ## Performance Optimization
259
+
260
+ ### Query Timeouts
261
+
262
+ ```ruby
263
+ # Set query timeouts per adapter
264
+ postgres = DWH.create(:postgres, {
265
+ host: 'localhost',
266
+ database: 'mydb',
267
+ username: 'user',
268
+ query_timeout: 1800 # 30 minutes
269
+ })
270
+
271
+ # For long-running analytical queries
272
+ druid = DWH.create(:druid, {
273
+ host: 'localhost',
274
+ port: 8080,
275
+ protocol: 'http',
276
+ query_timeout: 3600 # 1 hour
277
+ })
278
+ ```
279
+
280
+ ### Result Format Optimization
281
+
282
+ ```ruby
283
+ # Choose appropriate result format for your use case
284
+ arrays = adapter.execute(sql, format: :array) # Fastest, least memory
285
+ objects = adapter.execute(sql, format: :object) # Hash access, more memory
286
+ csv = adapter.execute(sql, format: :csv) # String format
287
+ native = adapter.execute(sql, format: :native) # Database's native format
288
+ ```
289
+
290
+ ### Streaming for Large Results
291
+
292
+ ```ruby
293
+ # Use streaming for large result sets
294
+ def export_large_table(adapter, table_name, output_file)
295
+ query = "SELECT * FROM #{table_name}"
296
+
297
+ File.open(output_file, 'w') do |file|
298
+ adapter.execute_stream(query, file)
299
+ end
300
+ end
301
+
302
+ # Chunk processing for memory efficiency
303
+ def process_large_dataset(adapter, query)
304
+ adapter.stream(query) do |chunk|
305
+ # Process each chunk immediately
306
+ # Avoids loading entire result set into memory
307
+ chunk.each { |row| process_row(row) }
308
+ end
309
+ end
310
+ ```
311
+
312
+ ## Error Handling and Debugging
313
+
314
+ ### Comprehensive Error Handling
315
+
316
+ ```ruby
317
+ begin
318
+ results = adapter.execute("SELECT * FROM table")
319
+ rescue DWH::ExecutionError => e
320
+ # Query execution failed
321
+ puts "Query failed: #{e.message}"
322
+ puts "SQL: #{e.sql}" if e.respond_to?(:sql)
323
+ rescue DWH::ConnectionError => e
324
+ # Connection issues
325
+ puts "Connection failed: #{e.message}"
326
+ # Implement retry logic
327
+ rescue DWH::ConfigError => e
328
+ # Configuration problems
329
+ puts "Configuration error: #{e.message}"
330
+ rescue DWH::UnsupportedCapability => e
331
+ # Attempted unsupported operation
332
+ puts "Feature not supported: #{e.message}"
333
+ end
334
+ ```
335
+
336
+ ## Custom Settings and Overrides
337
+
338
+ ### Runtime Settings Modification
339
+
340
+ ```ruby
341
+ # Create adapter with custom settings
342
+ adapter = DWH.create(:postgres, {
343
+ host: 'localhost',
344
+ database: 'mydb',
345
+ username: 'user',
346
+ settings: {
347
+ quote: '`@exp`', # Use backticks instead of double quotes
348
+ supports_window_functions: false, # Force disable window functions
349
+ temp_table_type: 'cte' # Prefer CTEs over subqueries
350
+ }
351
+ })
352
+
353
+ # Modify settings at runtime
354
+ adapter.alter_settings({
355
+ supports_full_join: false, # Disable FULL JOINs
356
+ final_pass_measure_join_type: 'inner' # Use INNER JOINs
357
+ })
358
+
359
+ # Reset to original settings
360
+ adapter.reset_settings
361
+ ```
362
+
363
+ ### Custom Function Mappings
364
+
365
+ ```ruby
366
+ # Override specific function translations
367
+ adapter = DWH.create(:postgres, {
368
+ host: 'localhost',
369
+ database: 'mydb',
370
+ username: 'user',
371
+ settings: {
372
+ truncate_date: "DATE_TRUNC('@unit', @exp)", # Custom date truncation
373
+ cast: "@exp::@type", # PostgreSQL-style casting
374
+ null_if: "CASE WHEN @exp = @target THEN NULL ELSE @exp END" # Custom NULLIF
375
+ }
376
+ })
377
+ ```
378
+
data/docs/index.html ADDED
@@ -0,0 +1,210 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ File: README
8
+
9
+ &mdash; Documentation by YARD 0.9.37
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" />
16
+
17
+ <script type="text/javascript">
18
+ pathId = "README";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="class_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index</a> &raquo;
40
+ <span class="title">File: README</span>
41
+
42
+ </div>
43
+
44
+ <div id="search">
45
+
46
+ <a class="full_list_link" id="class_list_link"
47
+ href="class_list.html">
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
54
+ </a>
55
+
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
59
+
60
+ <div id="content"><div id='filecontents'>
61
+ <p><a href="https://github.com/stratasite/dwh/actions"><img src="https://github.com/stratasite/dwh/workflows/Ruby/badge.svg" alt="Ruby" /></a></p>
62
+
63
+ <h1 id="dwh---data-warehouse-adapter-library">DWH - Data Warehouse Adapter Library</h1>
64
+
65
+ <p>A light weight library to connect, introspect, and query popular databases over a unified interface. This gem is intended for analtyical workloads. The library also provides database specific translations for common functions like <code>date_trunc</code>, <code>date_add</code> etc. The function tranlation is not comprehensive. But, it does provides good coverage for date handling, and some array handling as well.</p>
66
+
67
+ <blockquote>
68
+ <p>[!NOTE]
69
+ <strong>This is not an ORM</strong> nor will it cast types to ruby unless the underlying client does it out of the box. The goal here is to create an Architecture where new databases can be onboarded quickly.</p>
70
+ </blockquote>
71
+
72
+ <h2 id="why-do-we-need-another-database-abstraction-layer">Why do we need another database abstraction layer?</h2>
73
+
74
+ <p>Libraries like <a href="https://github.com/jeremyevans/sequel">Sequel</a> are amazing and comprehensive. However, its broad coverage also makes it more laborious to add new databases. Especially, ones with only HTTP endpoints for Ruby. We seem to be having an explosion of databases recently and a light weight interface will allow us to integrate faster.</p>
75
+
76
+ <p>The adapter only has 5 core methods (6 including the connection method). A YAML settings controls how it interacts with a particular db. It is relatively fast to add a new db. See the <a href="http://github.com/stratasite/dwh/blob/main/lib/dwh/adapters/druid.rb">Druid</a> implementation as an example. And <a href="https://github.com/stratasite/dwh/blob/main/lib/dwh/settings/druid.yml">here</a> is its corresponding YAML settings file.</p>
77
+
78
+ <h2 id="features">Features</h2>
79
+
80
+ <ul>
81
+ <li><strong>Unified Interface</strong>: Connect to multiple database types using the same API</li>
82
+ <li><strong>SQL Function Translation</strong>: Automatically translates common SQL functions to database-specific syntax</li>
83
+ <li><strong>Connection Pooling</strong>: Built-in connection pool management for high-performance applications</li>
84
+ <li><strong>Rich Metadata</strong>: Extract table schemas, column information, and statistics</li>
85
+ </ul>
86
+
87
+ <h2 id="supported-databases">Supported Databases</h2>
88
+
89
+ <ul>
90
+ <li><strong>Snowflake</strong> - High performance cloud warehouse</li>
91
+ <li><strong>Trino</strong> (formerly Presto) - Distributed SQL query engine</li>
92
+ <li><strong>AWS Athena</strong> - AWS big data warehouse</li>
93
+ <li><strong>Apache Druid</strong> - Real-time analytics database</li>
94
+ <li><strong>DuckDB</strong> - In-process analytical database</li>
95
+ <li><strong>PostgreSQL</strong> - Full-featured RDBMS with advanced SQL support</li>
96
+ <li><strong>MySQL</strong> - Popular open-source database</li>
97
+ <li><strong>SQL Server</strong> - Microsoft’s enterprise database</li>
98
+ </ul>
99
+
100
+ <h2 id="integrations-coming-soon">Integrations Coming Soon</h2>
101
+
102
+ <ul>
103
+ <li><strong>Redshift</strong> - AWS data warehouse platform</li>
104
+ <li><strong>ClickHouse</strong> - High performance analytical db</li>
105
+ <li><strong>Databricks</strong> - Big data compute engine</li>
106
+ <li><strong>MotherDuck</strong> - Hosted DuckDB service</li>
107
+ </ul>
108
+
109
+ <h2 id="quick-start">Quick Start</h2>
110
+
111
+ <p>Install it yourself as:</p>
112
+
113
+ <p><code>bash
114
+ gem install dwh
115
+ </code></p>
116
+
117
+ <h3 id="connect-and-execute-a-basic-query">Connect and Execute a Basic Query</h3>
118
+
119
+ <p>```ruby
120
+ require ‘dwh’</p>
121
+
122
+ <h1 id="connect-to-druid">Connect to Druid</h1>
123
+ <p>druid = DWH.create(:druid, {
124
+ host: ‘localhost’,
125
+ port: 8080,
126
+ protocol: ‘http’
127
+ })</p>
128
+
129
+ <h1 id="basic-query-execution">basic query execution</h1>
130
+ <p>results = druid.execute(“SELECT * FROM web_sales”, format: :csv)
131
+ ```</p>
132
+
133
+ <h2 id="core-api">Core API</h2>
134
+
135
+ <p>Standardized API across adapters:</p>
136
+
137
+ <dl>
138
+ <dt>connection</dt>
139
+ <dd>Creates a reusuable connection based on config hash passed in</dd>
140
+ <dt>tables(schema: nil, catalog: nil)</dt>
141
+ <dd> returns a list of tables from the default connection or from the specified schema and catalog </dd>
142
+ <dt> metadata(table_name, schema: nil, catalog: nil) </dt>
143
+ <dd> provides metadata about a table </dd>
144
+ <dt>stats(table_name, date_column: nil) </dt>
145
+ <dd> provides table row count and date range </dd>
146
+ <dt> execute(sql, format: :array, retries: 0) </dt>
147
+ <dd> runs a query and returns in given format </dd>
148
+ <dt> execute_stream(sql, io, stats: nil) </dt>
149
+ <dd> runs a query and streams it as csv into the given io </dd>
150
+ </dl>
151
+
152
+ <h2 id="tutorials-and-guides">Tutorials and Guides</h2>
153
+
154
+ <ul>
155
+ <li><a href="/docs/guides/getting-started.md">Getting Started</a></li>
156
+ <li><a href="/docs/guides/adapters.md">Adapter Configuration</a></li>
157
+ <li><a href="/docs/guides/creating-adapters.md">Creating an Adapter</a></li>
158
+ <li><a href="https://rubydoc.info/github/stratasite/dwh.git">API</a></li>
159
+ </ul>
160
+
161
+ <h2 id="testing">Testing</h2>
162
+
163
+ <p>Certain databases have to be tested via docker. Those tests will try to launch docker compose services in <code>test/support/compose*.yml</code></p>
164
+
165
+ <p>Run Unit Tests:</p>
166
+
167
+ <p><code>bash
168
+ bundle exec rake test:unit
169
+ </code></p>
170
+
171
+ <p>Run tests on RDBMS dbs:</p>
172
+
173
+ <p><code>bash
174
+ bundle exec rake test:system:rdbms
175
+ </code></p>
176
+
177
+ <p>Run tests on druid:</p>
178
+
179
+ <p><code>bash
180
+ bundle exec rake test:system:druid
181
+ </code></p>
182
+
183
+ <h2 id="development">Development</h2>
184
+
185
+ <p>After checking out the repo, run <code>bin/setup</code> to install dependencies. Then, run <code>rake test</code> to run the tests. You can also run <code>bin/console</code> for an interactive prompt.</p>
186
+
187
+ <p>To install this gem onto your local machine, run <code>bundle exec rake install</code>.</p>
188
+
189
+ <h2 id="contributing">Contributing</h2>
190
+
191
+ <p>Bug reports and pull requests are welcome on GitHub at <a href="https://github.com/stratasite/dwh">https://github.com/stratasite/dwh</a>.</p>
192
+
193
+ <h2 id="license">License</h2>
194
+
195
+ <p>This project is available as open source under the terms of the MIT License.</p>
196
+
197
+ <h2 id="version">Version</h2>
198
+
199
+ <p>Current version: 0.1.0</p>
200
+ </div></div>
201
+
202
+ <div id="footer">
203
+ Generated on Fri Aug 22 08:31:21 2025 by
204
+ <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
205
+ 0.9.37 (ruby-3.4.4).
206
+ </div>
207
+
208
+ </div>
209
+ </body>
210
+ </html>