sequelizer 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 348bea43e8571c35056619a31d45731f55b48a24cb4b93e94f23ecf7eba3a4af
4
- data.tar.gz: 170ae6de8d06dc7f8030fd97151b1ff7b5666a6d94849a4fe3e056a863938a65
3
+ metadata.gz: 9cda95a3cd5386a1d2e0ce1402793044ba78a07f457a265efe7a45e930095cb0
4
+ data.tar.gz: 5cbfe2a32b9b65f9922d47fa3a9e894e2335874dfed53fd972bc9d9483ee9dd5
5
5
  SHA512:
6
- metadata.gz: 497923374b34e892918aa86dea037c0b25323dc8d829398bb0e97d77386c13e248b68d47f4c7c31650d099fdf85d9cf62203703c2576f31310054f9937df9119
7
- data.tar.gz: f6a8dd133701a962fab9b16a0c0df30a4897d9c08526db07ec7ddef9029eb7140adcfbbab44974be7da2d970f2203308aa419b7112baad046947a50ad4ad93f5
6
+ metadata.gz: 3657c7dfd5f9a040cf0b38caa910c1e5526ff874367fc261eaa2da3c3cebfaba9ffc9ca511e183466b10d019d822cfecd9e4b12e3fcbe07e59fc8075608a98de
7
+ data.tar.gz: 29dd4df1852d028fea492621110a08a65cf186fe672a18645c6f4832aa89c5803c514db68bcd125dc8341e892d24273e0d11eee9f16c0f154cc10c59a967a02a
data/CHANGELOG.md CHANGED
@@ -2,6 +2,35 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.4.0] - 2026-10-25
6
+
7
+ ### Breaking changes
8
+
9
+ - **options:** Passed schema wins, and a caller's after_connect still runs ([8656edc](https://github.com/outcomesinsights/sequelizer/commit/8656edc9bf9d7a5d8f3c8242139c9f779af9b3e0)): when a lower-precedence source (.env, ENV or YAML) sets search_path and the caller passes schema: or schema_search_path:, the passed value is now the search path. Before, the lower-precedence search_path was used. A source that set schema while a lower-precedence source set search_path changes the same way.
10
+ - **funky:** Hash takes a named strategy, and md5 is the default ([5a8ef4e](https://github.com/outcomesinsights/sequelizer/commit/5a8ef4e6df604f40a943f15a30c1618fe08db27a)): funky.hash returns different ids by default. Pass strategy: :legacy to get the ids that earlier versions built.
11
+ - **smart_select_remove:** Raise AllColumnsRemovedError when every column is removed ([d8eeca4](https://github.com/outcomesinsights/sequelizer/commit/d8eeca42bbb5e365290bc4ea911e150ba9799d1f)): code that removed every column with select_remove got SELECT * and now raises AllColumnsRemovedError.
12
+ - **smart_select_remove:** Raise NoColumnsError instead of producing SELECT * ([810a0c7](https://github.com/outcomesinsights/sequelizer/commit/810a0c7fe8406683a185b129797d9818ba4c871e)): code that got SELECT * from select_remove on a database that returns no columns now raises NoColumnsError. conceptql loads this extension and builds SQL on Sequel.mock(host: :postgres) in its tests, so it may see this error when it moves to sequelizer 0.4.
13
+ - Drop hashie and OptionsHash for symbol-keyed hashes ([490c924](https://github.com/outcomesinsights/sequelizer/commit/490c924cba0c87d331607a49ed7dcb5963741e36)): Sequelizer.options and Options#to_hash now return a plain Hash with Symbol keys; look keys up with symbols (h[:adapter]).
14
+ - Remove the update_gemfile command and GemfileModifier ([4837ff4](https://github.com/outcomesinsights/sequelizer/commit/4837ff470477b8e092afaa9de612bf3cf7582580)): the update_gemfile command and Sequelizer::GemfileModifier are removed; use `bundle add <adapter gem>` instead.
15
+
16
+ ### Added
17
+
18
+ - **settable:** Quote Sequel expression values and make set_sql public ([5882d41](https://github.com/outcomesinsights/sequelizer/commit/5882d416429d88a5cc08a391e249e51d76399770))
19
+
20
+ ### Changed
21
+
22
+ - **deps:** Drop the activesupport runtime dependency ([3380d25](https://github.com/outcomesinsights/sequelizer/commit/3380d25805b5608fc87226eaf8a2521262aaa655))
23
+ - **deps:** Drop the pp dependency and require ([8f186b3](https://github.com/outcomesinsights/sequelizer/commit/8f186b34c2011382ed12a67e166dab909e99d93f))
24
+ - Delete empty ConnectionMaker#configure_adapter_specific_options ([33da14e](https://github.com/outcomesinsights/sequelizer/commit/33da14ed0ad8acd41026d4c9e27cba6c62fb1a2b))
25
+ - Apply db_opts without patching ConnectionPool#make_new ([3507790](https://github.com/outcomesinsights/sequelizer/commit/350779069a72e7def64717dbb93eb2266e1cde00))
26
+
27
+ ### Fixed
28
+
29
+ - **sequelizer:** A URL string at new_db and db means { url: string } ([a2e6091](https://github.com/outcomesinsights/sequelizer/commit/a2e6091f735d9f496f521430fb9942898e4bae50))
30
+ - **connection_maker:** Raise MissingAdapterError when nothing is configured ([c531242](https://github.com/outcomesinsights/sequelizer/commit/c531242e84c66390effa145cea5e4412eabaaaf4))
31
+ - **options:** Accept a database URL string as the url option ([73c5f61](https://github.com/outcomesinsights/sequelizer/commit/73c5f61df0c3c2037605d3b53d9c301e087b1c32))
32
+ - **smart_select_remove:** Resolve an explicit select list without querying the database ([f23c851](https://github.com/outcomesinsights/sequelizer/commit/f23c851f1f3ef987bc41869d43e04bb776db44fc))
33
+
5
34
  ## [0.3.0] - 2026-10-01
6
35
 
7
36
  ### Breaking changes
@@ -142,3 +171,5 @@ All notable changes to this project will be documented in this file.
142
171
  ### Added
143
172
 
144
173
  - The project itself
174
+
175
+ [0.4.0]: https://github.com/outcomesinsights/sequelizer/compare/v0.3.0...v0.4.0
data/README.md CHANGED
@@ -4,7 +4,7 @@ I was tired of writing the code to bootstrap a connection to my databases.
4
4
 
5
5
  [Sequel](https://github.com/jeremyevans/sequel/) provides an easy mechanism for connecting to a database, but I didn't want to store my username/password/other sensitive information in the scripts I was writing.
6
6
 
7
- So I wrote this gem that lets me store my database configuration options in either config/database.yml or .env and then lets me call `db` to get a connection to my database.
7
+ So I wrote this gem that lets me store my database configuration options in either config/sequelizer.yml or .env and then lets me call `db` to get a connection to my database.
8
8
 
9
9
  I normally use this gem when I'm writing a quick script or a Thor-based command line utility.
10
10
 
@@ -30,7 +30,7 @@ $ gem install sequelizer
30
30
 
31
31
  ## Usage
32
32
 
33
- To get the most out of Sequelizer, you'll need to create a config/database.yml file or a .env file and specify your database configuration options in that file.
33
+ To get the most out of Sequelizer, you'll need to create a config/sequelizer.yml file or a .env file and specify your database configuration options in that file.
34
34
 
35
35
  Sequelizer comes with a handy command that will print out your connection parameters. Just run:
36
36
 
@@ -38,16 +38,12 @@ Sequelizer comes with a handy command that will print out your connection parame
38
38
  bundle exec sequelizer config
39
39
  ```
40
40
 
41
- You'll also need to make sure the gem for your database is installed. You can do this by adding the gem to your application's Gemfile.
42
-
43
- Sequelizer comes with a handy command that will update your Gemfile for you. Once you've specified your database configuration, run
41
+ You'll also need to make sure the gem for your database is installed. You can do this by adding the gem to your application's Gemfile, e.g. for PostgreSQL:
44
42
 
45
43
  ```
46
- bundle exec sequelizer update_gemfile
44
+ bundle add pg
47
45
  ```
48
46
 
49
- The command will look up the right gem to use with the adapter you've specified, add a line to your Gemfile specifying that gem, and run `bundle install` to install the gem for you.
50
-
51
47
  Once you've specified your options and made sure your database's gem is installed, simply include the Sequelizer module in any class that needs a database connection and you'll get two handy-dandy methods: `db` and `new_db`
52
48
 
53
49
  Observe:
@@ -70,15 +66,17 @@ end
70
66
 
71
67
  `new_db` will create a new connection to the database on each call.
72
68
 
73
- Both take a hash of database options if you don't want to create a config/database.yml or .env file, or simply wish to override those options. Options are merged together from all sources with the following precedence:
69
+ Both take a hash of database options, or a database URL string such as `"postgres://localhost/my_db"`, if you don't want to create a config/sequelizer.yml or .env file, or simply wish to override those options. Options are merged together from all sources with the following precedence:
74
70
 
75
71
  ```
76
- passed_options > .env > manually defined environment variables > config/database.yml > ~/.config/sequelizer/database.yml
72
+ passed_options > .env > manually defined environment variables > config/sequelizer.yml > ~/.config/sequelizer/database.yml
77
73
  ```
78
74
 
79
- So if config/database.yml specifies a connection, you can set an environment variable (either manually, or through .env) to override one of those options. Similarly, if you pass an option to the method directly, that option will override the YAML and ENV-based options. See #3 for further discussion.
75
+ So if config/sequelizer.yml specifies a connection, you can set an environment variable (either manually, or through .env) to override one of those options. Similarly, if you pass an option to the method directly, that option will override the YAML and ENV-based options. See #3 for further discussion.
76
+
77
+ For PostgreSQL, `search_path`, `schema_search_path` and `schema` are three names for one option. The highest-precedence source that sets any of them decides the search path, so a `schema:` you pass overrides a `search_path` from .env or YAML. If one source sets more than one name, `search_path` wins over `schema_search_path`, which wins over `schema`. Sequelizer creates the schemas and sets the search path on each new connection, and then runs any `after_connect` you pass.
80
78
 
81
- Take a look at the examples directory for a few ways you can specify your database configuration options.
79
+ Take a look at the examples directory for a few ways you can specify your database configuration options. Copy a `sequelizer*.yml` example to `config/sequelizer.yml` to use it.
82
80
 
83
81
  ## Frustrations
84
82
 
@@ -38,18 +38,12 @@
38
38
  #
39
39
  # DB.extension :cold_col
40
40
 
41
- require 'active_support/core_ext/object/try'
42
- require 'active_support/core_ext/object/blank'
43
-
44
41
  module Sequel
45
-
46
42
  module ColdColDatabase
47
-
48
43
  # Internal schema registry for managing column information across different sources.
49
44
  # This class centralizes the storage and retrieval of table/view column metadata
50
45
  # from multiple sources including created tables, views, and manually loaded schemas.
51
46
  class SchemaRegistry
52
-
53
47
  # Initialize a new schema registry for the given database.
54
48
  #
55
49
  # @param db [Sequel::Database] the database instance this registry belongs to
@@ -99,7 +93,7 @@ module Sequel
99
93
  literal_name = @db.literal(name)
100
94
  table_name = name_to_string(name)
101
95
 
102
- [@created_views, @created_tables, @schemas].each do |registry|
96
+ [ @created_views, @created_tables, @schemas ].each do |registry|
103
97
  next unless registry
104
98
 
105
99
  if (columns = Sequel.synchronize { registry[literal_name] })
@@ -145,7 +139,6 @@ module Sequel
145
139
  name.to_s
146
140
  end
147
141
  end
148
-
149
142
  end
150
143
 
151
144
  # Sets up the cold column tracking when the extension is loaded
@@ -165,8 +158,8 @@ module Sequel
165
158
  def load_schema(path)
166
159
  schema_data = Psych.load_file(path) || {}
167
160
  schemas = schema_data.to_h do |table, info|
168
- columns = (info[:columns] || {}).map { |column_name, col_info| [column_name.to_sym, col_info] }
169
- [table.to_s, columns]
161
+ columns = (info[:columns] || {}).map { |column_name, col_info| [ column_name.to_sym, col_info ] }
162
+ [ table.to_s, columns ]
170
163
  end
171
164
  cold_col_registry.merge_schemas(schemas)
172
165
  end
@@ -223,13 +216,11 @@ module Sequel
223
216
  end
224
217
 
225
218
  def columns_from_generator(generator)
226
- generator.columns.map { |c| [c[:name], c] }
219
+ generator.columns.map { |c| [ c[:name], c ] }
227
220
  end
228
-
229
221
  end
230
222
 
231
223
  module ColdColDataset
232
-
233
224
  # Return the columns for the dataset without executing a query
234
225
  def columns
235
226
  columns_search
@@ -249,7 +240,7 @@ module Sequel
249
240
 
250
241
  protected
251
242
 
252
- WILDCARD = Sequel.lit('*').freeze
243
+ WILDCARD = Sequel.lit("*").freeze
253
244
 
254
245
  # Determine the probable columns for a dataset based on its query options.
255
246
  # This is the main entry point for column determination logic.
@@ -259,7 +250,7 @@ module Sequel
259
250
  def probable_columns(opts_chain)
260
251
  cols = opts_chain[:select]
261
252
 
262
- return columns_from_sources(opts_chain) if cols.blank?
253
+ return columns_from_sources(opts_chain) if cols.nil? || cols.empty?
263
254
 
264
255
  columns_from_select_list(cols, opts_chain)
265
256
  end
@@ -398,7 +389,7 @@ module Sequel
398
389
  def find_cte_columns(name, opts_chain)
399
390
  current_opts = opts_chain
400
391
 
401
- while current_opts.present?
392
+ while current_opts && !current_opts.empty?
402
393
  with = (current_opts[:with] || []).detect { |wh| literal(wh[:name]) == literal(name) }
403
394
  return with[:dataset].columns_search(opts_chain) if with
404
395
 
@@ -415,7 +406,10 @@ module Sequel
415
406
  # @param opts_chain [Hash] the dataset's query options
416
407
  # @return [Array<Symbol>, nil] column names if found, nil otherwise
417
408
  def find_join_alias(name, opts_chain)
418
- join = (opts_chain[:join] || []).detect { |jc| literal(jc.table_expr.try(:alias)) == literal(name) }
409
+ join = (opts_chain[:join] || []).detect do |jc|
410
+ table_alias = jc.table_expr.alias if jc.table_expr.respond_to?(:alias)
411
+ literal(table_alias) == literal(name)
412
+ end
419
413
  return nil unless join
420
414
 
421
415
  join_expr = join.table_expr.expression
@@ -452,9 +446,7 @@ module Sequel
452
446
  a.is_a?(SQL::Identifier) ? a.value.to_sym : a.to_sym
453
447
  end
454
448
  end
455
-
456
449
  end
457
450
 
458
451
  Database.register_extension(:cold_col, Sequel::ColdColDatabase)
459
-
460
452
  end
@@ -1,5 +1,4 @@
1
1
  module Sequel
2
-
3
2
  # = DbOpts
4
3
  #
5
4
  # Sequel extension that provides database-specific options handling.
@@ -19,10 +18,8 @@ module Sequel
19
18
  # SET work_mem='256MB'
20
19
  # SET shared_preload_libraries='pg_stat_statements'
21
20
  module DbOpts
22
-
23
21
  # Handles extraction and application of database-specific options.
24
22
  class DbOptions
25
-
26
23
  # @!attribute [r] db
27
24
  # @return [Sequel::Database] the database instance
28
25
  attr_reader :db
@@ -53,7 +50,7 @@ module Sequel
53
50
 
54
51
  db.opts.select do |k, _|
55
52
  k.to_s.match(opt_regexp)
56
- end.to_h { |k, v| [k.to_s.gsub(opt_regexp, '').to_sym, prep_value(k, v)] }
53
+ end.to_h { |k, v| [ k.to_s.gsub(opt_regexp, "").to_sym, prep_value(k, v) ] }
57
54
  end
58
55
 
59
56
  # Applies the database options to the given connection.
@@ -83,9 +80,8 @@ module Sequel
83
80
  #
84
81
  # @return [Array<String>] array of SQL SET statements
85
82
  def sql_statements
86
- db.send(:set_sql, to_hash)
83
+ db.set_sql(to_hash)
87
84
  end
88
-
89
85
  end
90
86
 
91
87
  # Returns a DbOptions instance for this database.
@@ -94,9 +90,7 @@ module Sequel
94
90
  def db_opts
95
91
  @db_opts ||= DbOptions.new(self)
96
92
  end
97
-
98
93
  end
99
94
 
100
95
  Database.register_extension(:db_opts, DbOpts)
101
-
102
96
  end
@@ -1,43 +1,81 @@
1
1
  module Sequel
2
-
3
2
  module Funky
3
+ # Raised when funky.hash is given a strategy name it does not know.
4
+ class UnknownHashStrategyError < Sequel::Error
5
+ def initialize(strategy)
6
+ super("unknown funky.hash strategy #{strategy.inspect}; known strategies: #{FunkyBase::HASH_STRATEGIES.map(&:inspect).join(", ")}")
7
+ end
8
+ end
4
9
 
5
10
  class FunkyBase
11
+ # The names funky.hash accepts. A strategy's definition never changes,
12
+ # because a change would change every id built with it; a new
13
+ # definition gets a new name.
14
+ HASH_STRATEGIES = %i[md5 legacy].freeze
15
+
16
+ # ASCII unit separator: joins the parts in the md5 strategy.
17
+ HASH_SEPARATOR = 31
18
+
19
+ # ASCII record separator: stands in for a NULL part in the md5 strategy.
20
+ HASH_NULL_MARKER = 30
6
21
 
7
22
  def initialize(db)
8
23
  @db = db
9
24
  end
10
25
 
26
+ # Returns a signed 64-bit integer expression that hashes +parts+.
27
+ #
28
+ # strategy: :md5 (the default) casts each part to a string, writes a NULL
29
+ # part as chr(30), joins the parts with chr(31), and reads the first 16
30
+ # hex characters of their md5 as a signed integer. It gives the same id
31
+ # on DuckDB and on Spark.
32
+ #
33
+ # strategy: :legacy is each database's form before :md5 existed:
34
+ # hash(concat(...)) on DuckDB and xxhash64(...) on Spark. Use it only to
35
+ # reproduce ids built with it; on DuckDB it gives duplicate ids.
36
+ def hash(*parts, strategy: :md5)
37
+ case strategy
38
+ when :md5 then md5_hash(parts)
39
+ when :legacy then legacy_hash(parts)
40
+ else raise UnknownHashStrategyError, strategy
41
+ end
42
+ end
43
+
11
44
  def to_strptime(format)
12
45
  return format if format =~ /%/
13
46
 
14
- format.gsub('yyyy', '%Y').gsub('MM', '%m').gsub('dd', '%d')
47
+ format.gsub("yyyy", "%Y").gsub("MM", "%m").gsub("dd", "%d")
15
48
  end
16
49
 
17
50
  def from_strptime(format)
18
51
  return format unless format =~ /%/
19
52
 
20
- format.gsub('%Y', 'yyyy').gsub('%m', 'MM').gsub('%d', 'dd')
53
+ format.gsub("%Y", "yyyy").gsub("%m", "MM").gsub("%d", "dd")
21
54
  end
22
55
 
56
+ private
57
+
58
+ # The first 16 hex characters of the md5 of the joined parts.
59
+ def md5_hex16(parts)
60
+ strings = parts.map do |part|
61
+ Sequel.function(:coalesce, Sequel.cast_string(part), Sequel.function(:chr, HASH_NULL_MARKER))
62
+ end
63
+ joined = Sequel.function(:concat_ws, Sequel.function(:chr, HASH_SEPARATOR), *strings)
64
+ Sequel.function(:substr, Sequel.function(:md5, joined), 1, 16)
65
+ end
23
66
  end
24
67
 
25
68
  class FunkySpark < FunkyBase
26
-
27
69
  def str_to_date(value, format, try: false) # rubocop:disable Lint/UnusedMethodArgument
28
70
  Sequel.function(:to_date, Sequel.cast_string(value), format)
29
71
  end
30
72
 
31
- def hash(*)
32
- Sequel.function(:xxhash64, *)
33
- end
34
-
35
73
  def make_json_column(ds, key_column, value_column)
36
74
  json_object_col = Sequel.function(
37
75
  :named_struct,
38
- 'key',
76
+ "key",
39
77
  key_column,
40
- 'value',
78
+ "value",
41
79
  value_column,
42
80
  ).then do |json_object_col|
43
81
  Sequel.function(
@@ -64,24 +102,24 @@ module Sequel
64
102
  Sequel.function(:collect_list, column)
65
103
  end
66
104
 
105
+ private
106
+
107
+ # conv with a negative target base reads the hex as a signed number.
108
+ def md5_hash(parts)
109
+ Sequel.function(:conv, md5_hex16(parts), 16, -10).cast(:bigint)
110
+ end
111
+
112
+ def legacy_hash(parts)
113
+ Sequel.function(:xxhash64, *parts)
114
+ end
67
115
  end
68
116
 
69
117
  class FunkyDuckDB < FunkyBase
70
-
71
118
  def str_to_date(value, format, try: false)
72
119
  strptime_func = try ? :try_strptime : :strptime
73
120
  Sequel.function(strptime_func, Sequel.cast_string(value), to_strptime(format))
74
121
  end
75
122
 
76
- def hash(*)
77
- Sequel.function(:hash, concat(*)).then do |hash_val|
78
- Sequel.case(
79
- { hash_val <= 9_223_372_036_854_775_807 => hash_val },
80
- hash_val - 18_446_744_073_709_551_616,
81
- ).cast(:bigint)
82
- end
83
- end
84
-
85
123
  def concat(*)
86
124
  Sequel.function(:concat, *)
87
125
  end
@@ -106,6 +144,23 @@ module Sequel
106
144
  Sequel.function(:list, column)
107
145
  end
108
146
 
147
+ private
148
+
149
+ def md5_hash(parts)
150
+ signed(Sequel.cast(Sequel.join([ "0x", md5_hex16(parts) ]), :ubigint))
151
+ end
152
+
153
+ def legacy_hash(parts)
154
+ signed(Sequel.function(:hash, concat(*parts)))
155
+ end
156
+
157
+ # Folds a UBIGINT into the BIGINT with the same 64 bits.
158
+ def signed(ubigint)
159
+ Sequel.case(
160
+ { ubigint <= 9_223_372_036_854_775_807 => ubigint },
161
+ ubigint - 18_446_744_073_709_551_616,
162
+ ).cast(:bigint)
163
+ end
109
164
  end
110
165
 
111
166
  def self.extended(db)
@@ -128,9 +183,7 @@ module Sequel
128
183
  raise "No known functions for #{database_type}"
129
184
  end
130
185
  end
131
-
132
186
  end
133
187
 
134
188
  Database.register_extension(:funky, Funky)
135
-
136
189
  end
@@ -1,5 +1,4 @@
1
1
  module Sequel
2
-
3
2
  # = MakeReadyable
4
3
  #
5
4
  # Sequel extension that provides database readiness functionality,
@@ -17,7 +16,6 @@ module Sequel
17
16
  # @example External file sources
18
17
  # db.make_ready(search_path: [Pathname.new('data.parquet')])
19
18
  module MakeReadyable
20
-
21
19
  # Prepares the database by setting up schemas, views, and external data sources.
22
20
  #
23
21
  # This method is primarily geared towards Spark SQL-based databases.
@@ -48,7 +46,6 @@ module Sequel
48
46
  def make_ready(opts = {})
49
47
  ReadyMaker.new(self, opts).run
50
48
  end
51
-
52
49
  end
53
50
 
54
51
  # = ReadyMaker
@@ -57,7 +54,6 @@ module Sequel
57
54
  # This class processes the make_ready options and executes the necessary
58
55
  # SQL statements to set up schemas, views, and external data sources.
59
56
  class ReadyMaker
60
-
61
57
  # @!attribute [r] db
62
58
  # @return [Sequel::Database] the database instance
63
59
  # @!attribute [r] opts
@@ -146,7 +142,6 @@ module Sequel
146
142
  # This class creates temporary views that read from external files
147
143
  # like Parquet, ORC, etc.
148
144
  class FileSourcerer
149
-
150
145
  # @!attribute [r] db
151
146
  # @return [Sequel::Database] the database instance
152
147
  # @!attribute [r] schema
@@ -167,7 +162,7 @@ module Sequel
167
162
  # @param _opts [Hash] unused options parameter
168
163
  # @return [Array<Symbol>] array containing the table name
169
164
  def tables(_opts = {})
170
- [schema.basename(schema.extname).to_s.to_sym]
165
+ [ schema.basename(schema.extname).to_s.to_sym ]
171
166
  end
172
167
 
173
168
  # Creates a temporary view that reads from the external file.
@@ -181,7 +176,7 @@ module Sequel
181
176
  db.create_view(table, {
182
177
  temp: true,
183
178
  using: format,
184
- options: { path: schema.expand_path },
179
+ options: { path: schema.expand_path }
185
180
  }.merge(opts))
186
181
  when :duckdb
187
182
  # DuckDB uses direct file reading with read_* functions
@@ -199,20 +194,20 @@ module Sequel
199
194
  # @param _opts [Hash] additional options to merge (currently unused for DuckDB)
200
195
  def create_duckdb_view(table, _opts)
201
196
  file_path = if schema.directory?
202
- schema.expand_path.join('**').join("*.#{format}").to_s
203
- else
197
+ schema.expand_path.join("**").join("*.#{format}").to_s
198
+ else
204
199
  schema.expand_path.to_s
205
- end
200
+ end
206
201
  read_function = case format
207
- when 'parquet'
202
+ when "parquet"
208
203
  :read_parquet
209
- when 'csv'
204
+ when "csv"
210
205
  :read_csv_auto
211
- when 'json'
206
+ when "json"
212
207
  :read_json_auto
213
- else
208
+ else
214
209
  raise Sequel::Error, "Unsupported file format '#{format}' for DuckDB"
215
- end
210
+ end
216
211
 
217
212
  # DuckDB doesn't support TEMPORARY views, use regular CREATE VIEW
218
213
  db.create_view(table, db.from(Sequel.function(read_function, file_path)))
@@ -224,11 +219,8 @@ module Sequel
224
219
  def format
225
220
  schema.extname[1..]
226
221
  end
227
-
228
222
  end
229
-
230
223
  end
231
224
 
232
225
  Database.register_extension(:make_readyable, MakeReadyable)
233
-
234
226
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sequel
4
-
5
4
  # Provides additional SQL helper methods for database operations.
6
5
  #
7
6
  # The more_sql extension adds convenience methods for SQL operations that
@@ -19,7 +18,6 @@ module Sequel
19
18
  # DB.create_schema(:staging, if_not_exists: true)
20
19
  # # Executes: CREATE SCHEMA IF NOT EXISTS "staging"
21
20
  module MoreSql
22
-
23
21
  # Creates a database schema.
24
22
  #
25
23
  # Generates and executes a CREATE SCHEMA statement with optional
@@ -63,14 +61,12 @@ module Sequel
63
61
  # create_schema_sql(:test, if_not_exists: true)
64
62
  # # => 'CREATE SCHEMA IF NOT EXISTS "test"'
65
63
  def create_schema_sql(schema_name, opts)
66
- sql = 'CREATE SCHEMA '
67
- sql += 'IF NOT EXISTS ' if opts[:if_not_exists]
64
+ sql = "CREATE SCHEMA "
65
+ sql += "IF NOT EXISTS " if opts[:if_not_exists]
68
66
  sql += literal(schema_name)
69
67
  sql
70
68
  end
71
-
72
69
  end
73
70
 
74
71
  Database.register_extension(:more_sql, MoreSql)
75
-
76
72
  end