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 +4 -4
- data/CHANGELOG.md +31 -0
- data/README.md +10 -12
- data/lib/sequel/extensions/cold_col.rb +11 -19
- data/lib/sequel/extensions/db_opts.rb +2 -8
- data/lib/sequel/extensions/funky.rb +75 -22
- data/lib/sequel/extensions/make_readyable.rb +10 -18
- data/lib/sequel/extensions/more_sql.rb +2 -6
- data/lib/sequel/extensions/platform.rb +19 -35
- data/lib/sequel/extensions/settable.rb +25 -12
- data/lib/sequel/extensions/smart_select_remove.rb +79 -21
- data/lib/sequel/extensions/sql_recorder.rb +0 -4
- data/lib/sequel/extensions/unionize.rb +2 -10
- data/lib/sequel/extensions/usable.rb +0 -4
- data/lib/sequelizer/cli.rb +15 -36
- data/lib/sequelizer/connection_maker.rb +42 -11
- data/lib/sequelizer/env_config.rb +2 -4
- data/lib/sequelizer/options.rb +75 -67
- data/lib/sequelizer/version.rb +1 -3
- data/lib/sequelizer/yaml_config.rb +10 -13
- data/lib/sequelizer.rb +14 -12
- metadata +36 -51
- data/lib/sequelizer/gemfile_modifier.rb +0 -91
- data/lib/sequelizer/monkey_patches/database_in_after_connect.rb +0 -28
- data/lib/sequelizer/options_hash.rb +0 -9
|
@@ -18,18 +18,15 @@
|
|
|
18
18
|
#
|
|
19
19
|
# Related module: Sequel::Platform
|
|
20
20
|
|
|
21
|
-
require
|
|
21
|
+
require "kvcsv"
|
|
22
22
|
|
|
23
23
|
module Sequel
|
|
24
|
-
|
|
25
24
|
# The Platform module provides database platform abstraction through
|
|
26
25
|
# configuration-driven capabilities and code-driven function translations.
|
|
27
26
|
module Platform
|
|
28
|
-
|
|
29
27
|
# Base platform class with KVCSV config loading and default implementations.
|
|
30
28
|
# Subclasses override function translation methods for platform-specific SQL.
|
|
31
29
|
class Base
|
|
32
|
-
|
|
33
30
|
attr_reader :db, :config
|
|
34
31
|
|
|
35
32
|
# Initialize platform with database connection and config paths.
|
|
@@ -122,27 +119,23 @@ module Sequel
|
|
|
122
119
|
def days_between(from, to)
|
|
123
120
|
date_diff(from, to)
|
|
124
121
|
end
|
|
125
|
-
|
|
126
122
|
end
|
|
127
123
|
|
|
128
124
|
# PostgreSQL platform with Postgres-specific function translations.
|
|
129
125
|
class Postgres < Base
|
|
130
|
-
|
|
131
126
|
def date_diff(from, to)
|
|
132
127
|
# Postgres uses date subtraction
|
|
133
|
-
Sequel.lit(
|
|
128
|
+
Sequel.lit("(? - ?)", to, from)
|
|
134
129
|
end
|
|
135
130
|
|
|
136
131
|
def days_between(from, to)
|
|
137
132
|
# Postgres date subtraction returns integer days
|
|
138
|
-
Sequel.lit(
|
|
133
|
+
Sequel.lit("(? - ?)", to, from)
|
|
139
134
|
end
|
|
140
|
-
|
|
141
135
|
end
|
|
142
136
|
|
|
143
137
|
# Spark platform with Spark SQL-specific function translations.
|
|
144
138
|
class Spark < Base
|
|
145
|
-
|
|
146
139
|
def date_diff(from, to)
|
|
147
140
|
# Spark datediff has reversed argument order (end, start)
|
|
148
141
|
Sequel.function(:datediff, to, from)
|
|
@@ -151,35 +144,30 @@ module Sequel
|
|
|
151
144
|
def str_to_date(value, format)
|
|
152
145
|
Sequel.function(:to_date, Sequel.cast_string(value), format)
|
|
153
146
|
end
|
|
154
|
-
|
|
155
147
|
end
|
|
156
148
|
|
|
157
149
|
# Snowflake platform with Snowflake-specific function translations.
|
|
158
150
|
class Snowflake < Base
|
|
159
|
-
|
|
160
151
|
def date_diff(from, to)
|
|
161
152
|
# Snowflake requires unit parameter
|
|
162
|
-
Sequel.function(:datediff,
|
|
153
|
+
Sequel.function(:datediff, "day", from, to)
|
|
163
154
|
end
|
|
164
155
|
|
|
165
156
|
def days_between(from, to)
|
|
166
|
-
Sequel.function(:datediff,
|
|
157
|
+
Sequel.function(:datediff, "day", from, to)
|
|
167
158
|
end
|
|
168
|
-
|
|
169
159
|
end
|
|
170
160
|
|
|
171
161
|
# Athena platform (Presto/Trino based) with Athena-specific function translations.
|
|
172
162
|
class Athena < Base
|
|
173
|
-
|
|
174
163
|
def date_diff(from, to)
|
|
175
164
|
# Athena/Presto uses date_diff with unit
|
|
176
|
-
Sequel.function(:date_diff,
|
|
165
|
+
Sequel.function(:date_diff, "day", from, to)
|
|
177
166
|
end
|
|
178
167
|
|
|
179
168
|
def days_between(from, to)
|
|
180
|
-
Sequel.function(:date_diff,
|
|
169
|
+
Sequel.function(:date_diff, "day", from, to)
|
|
181
170
|
end
|
|
182
|
-
|
|
183
171
|
end
|
|
184
172
|
|
|
185
173
|
# Map adapter schemes to platform classes
|
|
@@ -190,22 +178,21 @@ module Sequel
|
|
|
190
178
|
athena: Athena,
|
|
191
179
|
presto: Athena,
|
|
192
180
|
trino: Athena,
|
|
193
|
-
snowflake: Snowflake
|
|
181
|
+
snowflake: Snowflake
|
|
194
182
|
}.freeze
|
|
195
183
|
|
|
196
184
|
# Map adapter schemes to config file names
|
|
197
185
|
ADAPTER_CONFIG_NAMES = {
|
|
198
|
-
postgres:
|
|
199
|
-
postgresql:
|
|
200
|
-
spark:
|
|
201
|
-
athena:
|
|
202
|
-
presto:
|
|
203
|
-
trino:
|
|
204
|
-
snowflake:
|
|
186
|
+
postgres: "postgres",
|
|
187
|
+
postgresql: "postgres",
|
|
188
|
+
spark: "spark",
|
|
189
|
+
athena: "athena",
|
|
190
|
+
presto: "athena",
|
|
191
|
+
trino: "athena",
|
|
192
|
+
snowflake: "snowflake"
|
|
205
193
|
}.freeze
|
|
206
194
|
|
|
207
195
|
class << self
|
|
208
|
-
|
|
209
196
|
# Find the config directory, searching gem paths
|
|
210
197
|
def config_dir
|
|
211
198
|
@config_dir ||= find_config_dir
|
|
@@ -218,16 +205,15 @@ module Sequel
|
|
|
218
205
|
|
|
219
206
|
def find_config_dir
|
|
220
207
|
# Check relative to this file (gem's config)
|
|
221
|
-
gem_config = File.expand_path(
|
|
208
|
+
gem_config = File.expand_path("../../../config/platforms", __dir__)
|
|
222
209
|
return gem_config if File.directory?(gem_config)
|
|
223
210
|
|
|
224
211
|
# Fallback to working directory
|
|
225
|
-
local_config = File.join(Dir.pwd,
|
|
212
|
+
local_config = File.join(Dir.pwd, "config/platforms")
|
|
226
213
|
return local_config if File.directory?(local_config)
|
|
227
214
|
|
|
228
215
|
nil
|
|
229
216
|
end
|
|
230
|
-
|
|
231
217
|
end
|
|
232
218
|
|
|
233
219
|
# Build config paths for the given adapter
|
|
@@ -239,12 +225,12 @@ module Sequel
|
|
|
239
225
|
paths = []
|
|
240
226
|
|
|
241
227
|
if config_dir
|
|
242
|
-
base_config = File.join(config_dir,
|
|
228
|
+
base_config = File.join(config_dir, "base.csv")
|
|
243
229
|
paths << base_config if File.exist?(base_config)
|
|
244
230
|
|
|
245
231
|
adapter_name = ADAPTER_CONFIG_NAMES[adapter_scheme]
|
|
246
232
|
if adapter_name
|
|
247
|
-
rdbms_config = File.join(config_dir,
|
|
233
|
+
rdbms_config = File.join(config_dir, "rdbms", "#{adapter_name}.csv")
|
|
248
234
|
paths << rdbms_config if File.exist?(rdbms_config)
|
|
249
235
|
end
|
|
250
236
|
end
|
|
@@ -292,9 +278,7 @@ module Sequel
|
|
|
292
278
|
def platform
|
|
293
279
|
@platform
|
|
294
280
|
end
|
|
295
|
-
|
|
296
281
|
end
|
|
297
282
|
|
|
298
283
|
Database.register_extension(:platform, Platform)
|
|
299
|
-
|
|
300
284
|
end
|
|
@@ -13,18 +13,26 @@
|
|
|
13
13
|
# DB.set(work_mem: '256MB')
|
|
14
14
|
# # Executes: SET work_mem=256MB
|
|
15
15
|
#
|
|
16
|
+
# DB.set(memory_limit: Sequel.expr('1GB'))
|
|
17
|
+
# # Executes: SET memory_limit='1GB'
|
|
18
|
+
#
|
|
19
|
+
# Plain values are interpolated raw into the SET statement, so
|
|
20
|
+
# <tt>search_path: 'a,b,public'</tt> stays a list of schemas. When the database
|
|
21
|
+
# needs an SQL literal (for example DuckDB string settings), the caller wraps
|
|
22
|
+
# the value in +Sequel.expr+, and the extension passes it through +literal+.
|
|
23
|
+
#
|
|
24
|
+
# The +set_sql+ method returns the SET statements without executing them.
|
|
25
|
+
#
|
|
16
26
|
# The extension works with any database adapter and supports various value types
|
|
17
27
|
# including strings, numbers, booleans, and nil values.
|
|
18
28
|
#
|
|
19
29
|
# Related module: Sequel::Settable
|
|
20
30
|
|
|
21
31
|
module Sequel
|
|
22
|
-
|
|
23
32
|
# The Settable module provides database configuration functionality through
|
|
24
|
-
# SET statements. When loaded as an extension, it adds the +set+
|
|
25
|
-
# database connections.
|
|
33
|
+
# SET statements. When loaded as an extension, it adds the +set+ and
|
|
34
|
+
# +set_sql+ methods to database connections.
|
|
26
35
|
module Settable
|
|
27
|
-
|
|
28
36
|
# Execute SET statements for the given options hash.
|
|
29
37
|
#
|
|
30
38
|
# Each key-value pair in the options hash is converted to a SET statement
|
|
@@ -50,6 +58,10 @@ module Sequel
|
|
|
50
58
|
# # SET autocommit=true
|
|
51
59
|
# # SET custom_setting=
|
|
52
60
|
#
|
|
61
|
+
# @example Caller-quoted value
|
|
62
|
+
# DB.set(memory_limit: Sequel.expr('1GB'))
|
|
63
|
+
# # Executes: SET memory_limit='1GB'
|
|
64
|
+
#
|
|
53
65
|
# @return [void]
|
|
54
66
|
def set(opts = {})
|
|
55
67
|
set_sql(opts).each do |sql|
|
|
@@ -57,25 +69,26 @@ module Sequel
|
|
|
57
69
|
end
|
|
58
70
|
end
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# Generate SET SQL statements from options hash.
|
|
72
|
+
# Generate SET SQL statements from options hash, without executing them.
|
|
63
73
|
#
|
|
64
74
|
# Converts each key-value pair in the options hash into a SET SQL statement
|
|
65
|
-
# string.
|
|
75
|
+
# string. A value that is a +Sequel::SQL::Expression+ is passed through
|
|
76
|
+
# +literal+. Every other value is interpolated raw.
|
|
66
77
|
#
|
|
67
78
|
# @param opts [Hash] Hash of options to convert to SET statements
|
|
68
79
|
# @return [Array<String>] Array of SET SQL statement strings
|
|
69
80
|
#
|
|
70
81
|
# @example
|
|
71
|
-
# set_sql(timezone: 'UTC', port: 5432)
|
|
82
|
+
# DB.set_sql(timezone: 'UTC', port: 5432)
|
|
72
83
|
# # => ["SET timezone=UTC", "SET port=5432"]
|
|
84
|
+
#
|
|
85
|
+
# @example Caller-quoted value
|
|
86
|
+
# DB.set_sql(memory_limit: Sequel.expr('1GB'))
|
|
87
|
+
# # => ["SET memory_limit='1GB'"]
|
|
73
88
|
def set_sql(opts)
|
|
74
|
-
opts.map { |k, v| "SET #{k}=#{v}" }
|
|
89
|
+
opts.map { |k, v| "SET #{k}=#{v.is_a?(Sequel::SQL::Expression) ? literal(v) : v}" }
|
|
75
90
|
end
|
|
76
|
-
|
|
77
91
|
end
|
|
78
92
|
|
|
79
93
|
Database.register_extension(:settable, Settable)
|
|
80
|
-
|
|
81
94
|
end
|
|
@@ -8,9 +8,18 @@
|
|
|
8
8
|
#
|
|
9
9
|
# This is essential for lazy query building patterns where datasets
|
|
10
10
|
# reference tables that may not exist yet at query-build time. By
|
|
11
|
-
#
|
|
12
|
-
# this extension can determine which
|
|
13
|
-
# the database.
|
|
11
|
+
# inspecting the dataset's own SELECT list, or walking through from_self
|
|
12
|
+
# chains to an inner SELECT list, this extension can determine which
|
|
13
|
+
# columns to keep without touching the database.
|
|
14
|
+
#
|
|
15
|
+
# When static resolution fails and the database returns no columns (for
|
|
16
|
+
# example on Sequel.mock), select_remove raises
|
|
17
|
+
# Sequel::SmartSelectRemove::NoColumnsError instead of producing
|
|
18
|
+
# SELECT *, which would still contain the removed columns.
|
|
19
|
+
#
|
|
20
|
+
# When the columns are known but every one of them is removed, the result
|
|
21
|
+
# would also be SELECT *, so select_remove raises
|
|
22
|
+
# Sequel::SmartSelectRemove::AllColumnsRemovedError.
|
|
14
23
|
#
|
|
15
24
|
# You should load this extension into all of a database's datasets:
|
|
16
25
|
#
|
|
@@ -21,37 +30,85 @@
|
|
|
21
30
|
# Related module: Sequel::SmartSelectRemove
|
|
22
31
|
|
|
23
32
|
module Sequel
|
|
24
|
-
|
|
25
33
|
module SmartSelectRemove
|
|
34
|
+
# Raised when select_remove cannot determine the dataset's columns, so
|
|
35
|
+
# the result would be SELECT * and would still contain the removed columns.
|
|
36
|
+
class NoColumnsError < Sequel::Error
|
|
37
|
+
def initialize(dataset)
|
|
38
|
+
super("select_remove could not determine the columns of #{dataset.sql}; " \
|
|
39
|
+
"it would produce SELECT * and keep the removed columns")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Raised when select_remove would remove every column, so the result
|
|
44
|
+
# would be SELECT * and would still contain the removed columns.
|
|
45
|
+
class AllColumnsRemovedError < Sequel::Error
|
|
46
|
+
def initialize(dataset, cols)
|
|
47
|
+
super("select_remove(#{cols.map(&:inspect).join(', ')}) would remove every column of " \
|
|
48
|
+
"#{dataset.sql}; the result would be SELECT * and keep the removed columns")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
26
51
|
|
|
27
52
|
# Override select_remove to attempt static column resolution before
|
|
28
53
|
# falling back to the original implementation.
|
|
29
54
|
#
|
|
30
|
-
# When the dataset has
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
# that
|
|
55
|
+
# When the dataset has an explicit SELECT clause, resolves the output
|
|
56
|
+
# name of each entry and keeps the original expressions whose names
|
|
57
|
+
# are not removed, as the original select_remove does with the
|
|
58
|
+
# names that columns returns. When the dataset has no explicit SELECT
|
|
59
|
+
# clause, walks through from_self chains to find inner column
|
|
60
|
+
# expressions and resolves them to outer-scope symbol names. Both
|
|
61
|
+
# avoid the columns! call that the original select_remove uses,
|
|
62
|
+
# which would execute SQL.
|
|
63
|
+
#
|
|
64
|
+
# If any entry cannot be resolved (for example a literal string or a
|
|
65
|
+
# star), the original select_remove is used. Every such fallback
|
|
66
|
+
# first checks columns, and raises NoColumnsError when it is empty.
|
|
67
|
+
#
|
|
68
|
+
# On every path, if the result would have an empty select list because
|
|
69
|
+
# every column is removed, raises AllColumnsRemovedError. An empty
|
|
70
|
+
# select list renders as SELECT * and keeps the removed columns.
|
|
34
71
|
#
|
|
35
72
|
# @param cols [Array<Symbol>] columns to remove
|
|
36
73
|
# @return [Sequel::Dataset] dataset with columns removed
|
|
74
|
+
# @raise [NoColumnsError] if the fallback finds no columns
|
|
75
|
+
# @raise [AllColumnsRemovedError] if every column would be removed
|
|
37
76
|
def select_remove(*cols)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
77
|
+
sel = @opts[:select]
|
|
78
|
+
if sel && !sel.empty?
|
|
79
|
+
names = sel.map { |c| resolve_outer_column_name(c) }
|
|
80
|
+
unless names.any?(&:nil?)
|
|
81
|
+
kept = names.zip(sel).reject { |name, _| cols.include?(name) }.map(&:last)
|
|
82
|
+
return ensure_columns_remain(select(*(kept - cols)), cols)
|
|
83
|
+
end
|
|
84
|
+
elsif (inner_cols = resolve_selected_columns)
|
|
43
85
|
outer_cols = inner_cols.map { |c| resolve_outer_column_name(c) }
|
|
44
|
-
|
|
45
|
-
return super if outer_cols.any?(&:nil?)
|
|
46
|
-
|
|
47
|
-
return select(*(outer_cols - cols))
|
|
86
|
+
return ensure_columns_remain(select(*(outer_cols - cols)), cols) unless outer_cols.any?(&:nil?)
|
|
48
87
|
end
|
|
49
88
|
|
|
50
|
-
|
|
89
|
+
# Every fallback reaches this point. With no columns, the original
|
|
90
|
+
# select_remove would call select() and produce SELECT *.
|
|
91
|
+
raise NoColumnsError, self if columns.empty?
|
|
92
|
+
|
|
93
|
+
ensure_columns_remain(super, cols)
|
|
51
94
|
end
|
|
52
95
|
|
|
53
96
|
private
|
|
54
97
|
|
|
98
|
+
# Return ds unless its select list is empty or nil. Either renders as
|
|
99
|
+
# SELECT *, which would keep the removed columns.
|
|
100
|
+
#
|
|
101
|
+
# @param ds [Sequel::Dataset] the dataset select_remove would return
|
|
102
|
+
# @param cols [Array<Symbol>] the columns that were removed
|
|
103
|
+
# @return [Sequel::Dataset] ds
|
|
104
|
+
# @raise [AllColumnsRemovedError] if ds selects no columns
|
|
105
|
+
def ensure_columns_remain(ds, cols)
|
|
106
|
+
sel = ds.opts[:select]
|
|
107
|
+
raise AllColumnsRemovedError.new(self, cols) if sel.nil? || sel.empty?
|
|
108
|
+
|
|
109
|
+
ds
|
|
110
|
+
end
|
|
111
|
+
|
|
55
112
|
# Walk through from_self chains to find the innermost explicit
|
|
56
113
|
# SELECT list. Returns nil if no explicit selection is found.
|
|
57
114
|
#
|
|
@@ -75,12 +132,15 @@ module Sequel
|
|
|
75
132
|
# After from_self, inner expressions become subquery output columns
|
|
76
133
|
# referenced by their alias or base name in the outer scope.
|
|
77
134
|
#
|
|
135
|
+
# A star (:* or a qualified :*) selects every column of a table, so
|
|
136
|
+
# it has no single name and is unresolvable.
|
|
137
|
+
#
|
|
78
138
|
# @param col [Object] a column expression from the inner SELECT
|
|
79
139
|
# @return [Symbol, nil] the outer column name, or nil if unresolvable
|
|
80
140
|
def resolve_outer_column_name(col)
|
|
81
141
|
case col
|
|
82
142
|
when Symbol
|
|
83
|
-
col
|
|
143
|
+
col unless col == :*
|
|
84
144
|
when Sequel::SQL::AliasedExpression
|
|
85
145
|
a = col.alias
|
|
86
146
|
a.is_a?(Symbol) ? a : a.to_sym
|
|
@@ -90,12 +150,10 @@ module Sequel
|
|
|
90
150
|
col.value.to_sym
|
|
91
151
|
end
|
|
92
152
|
end
|
|
93
|
-
|
|
94
153
|
end
|
|
95
154
|
|
|
96
155
|
Database.register_extension(:smart_select_remove) do |db|
|
|
97
156
|
db.extension(:select_remove)
|
|
98
157
|
db.extend_datasets(SmartSelectRemove)
|
|
99
158
|
end
|
|
100
|
-
|
|
101
159
|
end
|
|
@@ -32,12 +32,10 @@
|
|
|
32
32
|
# Related module: Sequel::SqlRecorder
|
|
33
33
|
|
|
34
34
|
module Sequel
|
|
35
|
-
|
|
36
35
|
# Extension module that adds SQL recording capabilities to Sequel databases.
|
|
37
36
|
# When included, it provides a +sql_recorder+ method that returns an array
|
|
38
37
|
# of all SQL statements executed against the database.
|
|
39
38
|
module SqlRecorder
|
|
40
|
-
|
|
41
39
|
# Returns the array of recorded SQL statements.
|
|
42
40
|
#
|
|
43
41
|
# The array accumulates all SQL statements sent to the database since the
|
|
@@ -77,9 +75,7 @@ module Sequel
|
|
|
77
75
|
@sql_recorder ||= []
|
|
78
76
|
end
|
|
79
77
|
end
|
|
80
|
-
|
|
81
78
|
end
|
|
82
79
|
|
|
83
80
|
Database.register_extension(:sql_recorder, SqlRecorder)
|
|
84
|
-
|
|
85
81
|
end
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "digest"
|
|
4
4
|
|
|
5
5
|
module Sequel
|
|
6
|
-
|
|
7
6
|
# Provides efficient handling of large UNION operations.
|
|
8
7
|
#
|
|
9
8
|
# The unionize extension allows combining many datasets through UNION operations
|
|
@@ -20,14 +19,12 @@ module Sequel
|
|
|
20
19
|
# @example With options
|
|
21
20
|
# DB.unionize(datasets, chunk_size: 50, all: true, temp_table_prefix: 'my_union')
|
|
22
21
|
module Unionize
|
|
23
|
-
|
|
24
22
|
# Handles the chunking and union of multiple datasets.
|
|
25
23
|
#
|
|
26
24
|
# This class manages the process of splitting a large collection of datasets
|
|
27
25
|
# into smaller chunks, creating temporary tables/views for each chunk, and
|
|
28
26
|
# then recursively combining them until a single unified dataset is produced.
|
|
29
27
|
class Unionizer
|
|
30
|
-
|
|
31
28
|
# Default number of datasets to combine in each chunk
|
|
32
29
|
DEFAULT_CHUNK_SIZE = 100
|
|
33
30
|
|
|
@@ -36,7 +33,6 @@ module Sequel
|
|
|
36
33
|
# Each chunk handles a subset of datasets, creates a temporary table/view
|
|
37
34
|
# for the combined result, and provides access to the unified dataset.
|
|
38
35
|
class Chunk
|
|
39
|
-
|
|
40
36
|
# @!attribute [r] db
|
|
41
37
|
# @return [Sequel::Database] The database connection
|
|
42
38
|
# @!attribute [r] dses
|
|
@@ -90,7 +86,6 @@ module Sequel
|
|
|
90
86
|
raise "Unsupported database type: #{db.database_type}"
|
|
91
87
|
end
|
|
92
88
|
end
|
|
93
|
-
|
|
94
89
|
end
|
|
95
90
|
|
|
96
91
|
# @!attribute [r] db
|
|
@@ -111,7 +106,7 @@ module Sequel
|
|
|
111
106
|
@ds_set = ds_set
|
|
112
107
|
@opts = opts
|
|
113
108
|
opts[:chunk_size] ||= DEFAULT_CHUNK_SIZE
|
|
114
|
-
opts[:temp_table_prefix] ||=
|
|
109
|
+
opts[:temp_table_prefix] ||= "temp_union"
|
|
115
110
|
opts[:all] ||= false
|
|
116
111
|
opts[:from_self] = opts.fetch(:from_self, true)
|
|
117
112
|
end
|
|
@@ -132,7 +127,6 @@ module Sequel
|
|
|
132
127
|
|
|
133
128
|
unionize(chunks.each(&:create).map { |chunk| db[chunk.name] })
|
|
134
129
|
end
|
|
135
|
-
|
|
136
130
|
end
|
|
137
131
|
|
|
138
132
|
# Efficiently combines multiple datasets using UNION operations.
|
|
@@ -161,9 +155,7 @@ module Sequel
|
|
|
161
155
|
def unionize(ds_set, opts = {})
|
|
162
156
|
Unionizer.new(self, ds_set, opts).unionize
|
|
163
157
|
end
|
|
164
|
-
|
|
165
158
|
end
|
|
166
159
|
|
|
167
160
|
Database.register_extension(:unionize, Unionize)
|
|
168
|
-
|
|
169
161
|
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
module Sequel
|
|
2
|
-
|
|
3
2
|
# = Usable
|
|
4
3
|
#
|
|
5
4
|
# Sequel extension that provides a convenient +use+ method for switching
|
|
@@ -12,7 +11,6 @@ module Sequel
|
|
|
12
11
|
# db.use(:my_schema)
|
|
13
12
|
# # Executes: USE `my_schema`
|
|
14
13
|
module Usable
|
|
15
|
-
|
|
16
14
|
# Switches to the specified database or schema.
|
|
17
15
|
#
|
|
18
16
|
# Executes a USE statement to change the current database context.
|
|
@@ -36,9 +34,7 @@ module Sequel
|
|
|
36
34
|
def use_sql(schema_name)
|
|
37
35
|
"USE #{literal(schema_name)}"
|
|
38
36
|
end
|
|
39
|
-
|
|
40
37
|
end
|
|
41
38
|
|
|
42
39
|
Database.register_extension(:usable, Usable)
|
|
43
|
-
|
|
44
40
|
end
|
data/lib/sequelizer/cli.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
require
|
|
2
|
-
|
|
3
|
-
require_relative 'gemfile_modifier'
|
|
1
|
+
require "thor"
|
|
2
|
+
require_relative "options"
|
|
4
3
|
|
|
5
4
|
module Sequelizer
|
|
6
5
|
# = CLI
|
|
@@ -8,57 +7,38 @@ module Sequelizer
|
|
|
8
7
|
# Command line interface for Sequelizer gem using Thor.
|
|
9
8
|
# Provides commands for:
|
|
10
9
|
#
|
|
11
|
-
# * Updating Gemfile with database adapters
|
|
12
10
|
# * Initializing .env files with database configuration
|
|
13
11
|
# * Displaying current configuration
|
|
14
12
|
#
|
|
15
13
|
# @example
|
|
16
|
-
# sequelizer update_gemfile
|
|
17
14
|
# sequelizer init_env --adapter postgres --host localhost
|
|
18
15
|
# sequelizer config
|
|
19
16
|
class CLI < Thor
|
|
20
|
-
|
|
21
|
-
desc 'update_gemfile',
|
|
22
|
-
'adds or replaces a line in your Gemfile to include the correct database adapter to work with Sequel'
|
|
23
|
-
option 'dry-run', type: :boolean, desc: 'Only prints out what it would do, but makes no changes'
|
|
24
|
-
option 'skip-bundle', type: :boolean, desc: "Don't run `bundle install` after modifying Gemfile"
|
|
25
|
-
# Updates the Gemfile to include the appropriate database adapter gem.
|
|
26
|
-
#
|
|
27
|
-
# This command analyzes your current database configuration and adds or updates
|
|
28
|
-
# the corresponding database adapter gem in your Gemfile. It supports various
|
|
29
|
-
# adapters including PostgreSQL, MySQL, SQLite, and JDBC-based adapters.
|
|
30
|
-
#
|
|
31
|
-
# @option options [Boolean] dry-run Only prints what would be done without making changes
|
|
32
|
-
# @option options [Boolean] skip-bundle Skip running `bundle install` after modification
|
|
33
|
-
def update_gemfile
|
|
34
|
-
GemfileModifier.new(options).modify
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
desc 'init_env', 'creates a .env file with the parameters listed'
|
|
17
|
+
desc "init_env", "creates a .env file with the parameters listed"
|
|
38
18
|
option :adapter,
|
|
39
19
|
aliases: :a,
|
|
40
|
-
desc:
|
|
20
|
+
desc: "adapter for database"
|
|
41
21
|
option :host,
|
|
42
22
|
aliases: :h,
|
|
43
|
-
banner:
|
|
44
|
-
desc:
|
|
23
|
+
banner: "localhost",
|
|
24
|
+
desc: "host for database"
|
|
45
25
|
option :username,
|
|
46
26
|
aliases: :u,
|
|
47
|
-
desc:
|
|
27
|
+
desc: "username for database"
|
|
48
28
|
option :password,
|
|
49
29
|
aliases: :P,
|
|
50
|
-
desc:
|
|
30
|
+
desc: "password for database"
|
|
51
31
|
option :port,
|
|
52
32
|
aliases: :p,
|
|
53
33
|
type: :numeric,
|
|
54
|
-
banner:
|
|
55
|
-
desc:
|
|
34
|
+
banner: "5432",
|
|
35
|
+
desc: "port for database"
|
|
56
36
|
option :database,
|
|
57
37
|
aliases: :d,
|
|
58
|
-
desc:
|
|
38
|
+
desc: "database for database"
|
|
59
39
|
option :search_path,
|
|
60
40
|
aliases: :s,
|
|
61
|
-
desc:
|
|
41
|
+
desc: "schema for database (PostgreSQL only)"
|
|
62
42
|
# Creates a .env file with database configuration parameters.
|
|
63
43
|
#
|
|
64
44
|
# This command generates a .env file with SEQUELIZER_* environment variables
|
|
@@ -73,18 +53,18 @@ module Sequelizer
|
|
|
73
53
|
# @option options [String] :search_path PostgreSQL schema search path
|
|
74
54
|
# @raise [SystemExit] if .env file already exists
|
|
75
55
|
def init_env
|
|
76
|
-
if File.exist?(
|
|
56
|
+
if File.exist?(".env")
|
|
77
57
|
puts ".env already exists! I'm too cowardly to overwrite it!"
|
|
78
58
|
puts "Here's what I would have put in there:"
|
|
79
59
|
puts make_env(options)
|
|
80
60
|
exit(1)
|
|
81
61
|
end
|
|
82
|
-
File.open(
|
|
62
|
+
File.open(".env", "w") do |file|
|
|
83
63
|
file.puts make_env(options)
|
|
84
64
|
end
|
|
85
65
|
end
|
|
86
66
|
|
|
87
|
-
desc
|
|
67
|
+
desc "config", "prints out the connection parameters"
|
|
88
68
|
# Displays the current database configuration and extensions.
|
|
89
69
|
#
|
|
90
70
|
# This command shows the resolved configuration options that would be used
|
|
@@ -103,6 +83,5 @@ module Sequelizer
|
|
|
103
83
|
"SEQUELIZER_#{key.upcase}=#{value}"
|
|
104
84
|
end.join("\n")
|
|
105
85
|
end
|
|
106
|
-
|
|
107
86
|
end
|
|
108
87
|
end
|