sequelizer 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -0
- data/LICENSE +21 -0
- data/README.md +28 -14
- data/lib/sequel/extensions/cold_col.rb +39 -15
- data/lib/sequel/extensions/funky.rb +1 -1
- data/lib/sequel/extensions/make_readyable.rb +18 -8
- data/lib/sequel/extensions/platform.rb +8 -9
- data/lib/sequel/extensions/smart_select_remove.rb +101 -0
- data/lib/sequelizer/options.rb +10 -5
- data/lib/sequelizer/version.rb +1 -1
- metadata +7 -52
- data/.beads/.gitignore +0 -54
- data/.beads/.jsonl.lock +0 -0
- data/.beads/.migration-hint-ts +0 -1
- data/.beads/README.md +0 -81
- data/.beads/config.yaml +0 -42
- data/.beads/issues.jsonl +0 -20
- data/.beads/metadata.json +0 -7
- data/.coderabbit.yaml +0 -94
- data/.devcontainer/.p10k.zsh +0 -1713
- data/.devcontainer/.zshrc +0 -29
- data/.devcontainer/Dockerfile +0 -137
- data/.devcontainer/copy-claude-credentials.sh +0 -32
- data/.devcontainer/devcontainer.json +0 -102
- data/.devcontainer/init-firewall.sh +0 -123
- data/.devcontainer/setup-credentials.sh +0 -95
- data/.github/dependabot.yml +0 -18
- data/.github/workflows/dependabot-auto-merge.yml +0 -36
- data/.github/workflows/test.yml +0 -49
- data/.gitignore +0 -40
- data/.overcommit.yml +0 -73
- data/.rubocop.yml +0 -167
- data/AGENTS.md +0 -126
- data/CLAUDE.md +0 -230
- data/Gemfile +0 -12
- data/Gemfile.lock +0 -189
- data/Guardfile +0 -28
- data/LICENSE.txt +0 -22
- data/Rakefile +0 -35
- data/examples/database.with_one_set_of_options.yml +0 -15
- data/examples/database.yml +0 -30
- data/examples/dot_env.txt +0 -10
- data/sequelizer.gemspec +0 -38
- data/test/lib/sequel/extensions/test_cold_col.rb +0 -251
- data/test/lib/sequel/extensions/test_db_opts.rb +0 -42
- data/test/lib/sequel/extensions/test_make_readyable.rb +0 -258
- data/test/lib/sequel/extensions/test_more_sql.rb +0 -132
- data/test/lib/sequel/extensions/test_platform.rb +0 -222
- data/test/lib/sequel/extensions/test_settable.rb +0 -109
- data/test/lib/sequel/extensions/test_sql_recorder.rb +0 -231
- data/test/lib/sequel/extensions/test_unionize.rb +0 -76
- data/test/lib/sequel/extensions/test_usable.rb +0 -15
- data/test/lib/sequelizer/test_connection_maker.rb +0 -123
- data/test/lib/sequelizer/test_env_config.rb +0 -37
- data/test/lib/sequelizer/test_gemfile_modifier.rb +0 -88
- data/test/lib/sequelizer/test_options.rb +0 -111
- data/test/lib/sequelizer/test_yaml_config.rb +0 -83
- data/test/test_helper.rb +0 -45
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 348bea43e8571c35056619a31d45731f55b48a24cb4b93e94f23ecf7eba3a4af
|
|
4
|
+
data.tar.gz: 170ae6de8d06dc7f8030fd97151b1ff7b5666a6d94849a4fe3e056a863938a65
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 497923374b34e892918aa86dea037c0b25323dc8d829398bb0e97d77386c13e248b68d47f4c7c31650d099fdf85d9cf62203703c2576f31310054f9937df9119
|
|
7
|
+
data.tar.gz: f6a8dd133701a962fab9b16a0c0df30a4897d9c08526db07ec7ddef9029eb7140adcfbbab44974be7da2d970f2203308aa419b7112baad046947a50ad4ad93f5
|
data/CHANGELOG.md
CHANGED
|
@@ -2,14 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.3.0] - 2026-10-01
|
|
6
|
+
|
|
7
|
+
### Breaking changes
|
|
8
|
+
|
|
9
|
+
- Drop support for Ruby 3.2 ([feef6de](https://github.com/outcomesinsights/sequelizer/commit/feef6de5c155dc0dd39642ad1686ff9bab0211de)): sequelizer now requires Ruby >= 3.3.0.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Add smart_select_remove Sequel extension ([a1366ec](https://github.com/outcomesinsights/sequelizer/commit/a1366ec8f68e64728b3c794de15c2fd78cfa9e2e))
|
|
14
|
+
- DuckDB support in make_readyable and cold_col extensions ([9433d98](https://github.com/outcomesinsights/sequelizer/commit/9433d982bc0855df11ac6f48a915e861fd78a572))
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Extract available_tables to fix AbcSize in ReadyMaker#run ([60c6a68](https://github.com/outcomesinsights/sequelizer/commit/60c6a6803afbfde2b0747fd19e3bcd346bf2d1ef))
|
|
19
|
+
- Simplify cold_col find_columns and remove rescue nil guards ([752eab1](https://github.com/outcomesinsights/sequelizer/commit/752eab14595af23974ea56a976dd99e29d9d5552))
|
|
20
|
+
- Remove OptionalAdapterSupport, add sequel-duckdb to bundle ([74d6d16](https://github.com/outcomesinsights/sequelizer/commit/74d6d16f564742138a32e111d7b6107289abec75))
|
|
21
|
+
- Let Sequel handle adapter loading, remove pre-require ([c2b592d](https://github.com/outcomesinsights/sequelizer/commit/c2b592d1965e24370dae2f5cfb515097358cd3da))
|
|
22
|
+
- Ship only runtime files in the gem: lib/, the sequelizer executable, the platform CSVs, and the docs and licence ([1cc49b6](https://github.com/outcomesinsights/sequelizer/commit/1cc49b69dec0c6c879a469f0774c1196c467ed17))
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Fall back to database query in cold_col for unregistered tables ([d07f7c5](https://github.com/outcomesinsights/sequelizer/commit/d07f7c5e482074e631828afbf558a767d6695b66))
|
|
27
|
+
- Replace rescue modifier with explicit begin/rescue in cold_col ([6fced2b](https://github.com/outcomesinsights/sequelizer/commit/6fced2b4957277b5c6d45fabf11e89d0b476a8e5))
|
|
28
|
+
- Handle string SQL in cold_col create_table_as and create_view_sql ([8f30602](https://github.com/outcomesinsights/sequelizer/commit/8f306028857e3838370fc623cd619a9a79c8c06f))
|
|
29
|
+
- Handle Array search_path in after_connect ([c376825](https://github.com/outcomesinsights/sequelizer/commit/c3768251695286668ca49dcbb84aa12c3bbb7f69))
|
|
30
|
+
|
|
5
31
|
## 0.2.0
|
|
6
32
|
|
|
7
33
|
### Added
|
|
34
|
+
|
|
8
35
|
- funky Sequel extension for database-specific function abstraction
|
|
9
36
|
- kvcsv as a runtime dependency
|
|
10
37
|
- Platform configuration fixtures in config/platforms/
|
|
11
38
|
|
|
12
39
|
### Changed
|
|
40
|
+
|
|
13
41
|
- Broadened activesupport dependency from ~> 7.0 to >= 7, < 9
|
|
14
42
|
- Broadened hashie dependency from ~> 3.2 to >= 3.2, < 6.0
|
|
15
43
|
- Broadened dotenv dependency from ~> 2.1 to >= 2.1, < 4.0
|
|
@@ -17,11 +45,13 @@ All notable changes to this project will be documented in this file.
|
|
|
17
45
|
- Added multi-Ruby CI matrix (3.2, 3.3, 3.4, 4.0) with separate lint job
|
|
18
46
|
|
|
19
47
|
### Fixed
|
|
48
|
+
|
|
20
49
|
- Adapter extraction from URL scheme for search_path processing
|
|
21
50
|
|
|
22
51
|
## 0.1.6
|
|
23
52
|
|
|
24
53
|
### Removed
|
|
54
|
+
|
|
25
55
|
- JDBC adapter support (jdbc_hive2, jdbc_impala, jdbc_postgres) - not needed for foreseeable future
|
|
26
56
|
- Native Impala adapter support - not needed for foreseeable future
|
|
27
57
|
- Kerberos authentication functionality for enterprise databases
|
|
@@ -29,9 +59,11 @@ All notable changes to this project will be documented in this file.
|
|
|
29
59
|
- 16 test methods related to JDBC and Impala adapters
|
|
30
60
|
|
|
31
61
|
### Added
|
|
62
|
+
|
|
32
63
|
- pg gem as development dependency to support PostgreSQL testing
|
|
33
64
|
|
|
34
65
|
### Changed
|
|
66
|
+
|
|
35
67
|
- Simplified ConnectionMaker class by removing adapter-specific configuration methods
|
|
36
68
|
- Improved test coverage from 84.95% to 93.54% by removing unused code paths
|
|
37
69
|
- Updated documentation to reflect focus on standard Sequel adapters
|
|
@@ -45,11 +77,13 @@ All notable changes to this project will be documented in this file.
|
|
|
45
77
|
## [0.1.0] - 2016-11-08
|
|
46
78
|
|
|
47
79
|
### Added
|
|
80
|
+
|
|
48
81
|
- Connections are cached by options to avoid over-allocation
|
|
49
82
|
- URL or URI option represent connection string
|
|
50
83
|
- sequelizer.yml is passed through ERB
|
|
51
84
|
|
|
52
85
|
### Changed
|
|
86
|
+
|
|
53
87
|
- Format of this [CHANGELOG](http://keepachangelog.com/en/0.3.0/)
|
|
54
88
|
- Prefer environment variables over other options
|
|
55
89
|
- Use config/sequelizer.yml instead of config/database.yml
|
|
@@ -57,34 +91,41 @@ All notable changes to this project will be documented in this file.
|
|
|
57
91
|
## [0.0.6] - 2015-08-21
|
|
58
92
|
|
|
59
93
|
### Added
|
|
94
|
+
|
|
60
95
|
- Support for ruby-oci8 (Oracle) in update_gemfile command
|
|
61
96
|
- Read user-level configuration from ~/.config/sequelizer/database.yml
|
|
62
97
|
|
|
63
98
|
### Fixed
|
|
99
|
+
|
|
64
100
|
- Bug where options passed as symbols where sometimes ignored.
|
|
65
101
|
|
|
66
102
|
## [0.0.5] - 2014-08-29
|
|
67
103
|
|
|
68
104
|
### Added
|
|
105
|
+
|
|
69
106
|
- Support for TinyTDS (SQL Server) in update_gemfile command
|
|
70
107
|
|
|
71
108
|
### Fixed
|
|
109
|
+
|
|
72
110
|
- timeout is always converted to integer before passing to Sequel.connect
|
|
73
111
|
|
|
74
112
|
## [0.0.4] - 2014-08-18
|
|
75
113
|
|
|
76
114
|
### Added
|
|
115
|
+
|
|
77
116
|
- `init_env` command to bin/sequelizer
|
|
78
117
|
- Prefer `search_path` over `schema_search_path` option
|
|
79
118
|
|
|
80
119
|
## [0.0.3] - 2014-07-10
|
|
81
120
|
|
|
82
121
|
### Added
|
|
122
|
+
|
|
83
123
|
- Ability to view configuration by running `sequelizer config`
|
|
84
124
|
|
|
85
125
|
## [0.0.2] - 2014-07-10
|
|
86
126
|
|
|
87
127
|
### Added
|
|
128
|
+
|
|
88
129
|
- This [CHANGELOG](http://keepachangelog.com/)
|
|
89
130
|
- Behavior to merge options from all sources (#3)
|
|
90
131
|
- Dependency on hashie gem
|
|
@@ -93,9 +134,11 @@ All notable changes to this project will be documented in this file.
|
|
|
93
134
|
- Reference to issues #1, #3 in README
|
|
94
135
|
|
|
95
136
|
### Fixed
|
|
137
|
+
|
|
96
138
|
- Prevented TestEnvConfig from polluting environment variables
|
|
97
139
|
|
|
98
140
|
## [0.0.1] - 2014-07-10
|
|
99
141
|
|
|
100
142
|
### Added
|
|
143
|
+
|
|
101
144
|
- The project itself
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014-2026 Outcomes Insights, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
|
@@ -12,35 +12,46 @@ I normally use this gem when I'm writing a quick script or a Thor-based command
|
|
|
12
12
|
|
|
13
13
|
Add this line to your application's Gemfile:
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
```
|
|
16
|
+
gem 'sequelizer'
|
|
17
|
+
```
|
|
16
18
|
|
|
17
19
|
And then execute:
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
```
|
|
22
|
+
$ bundle
|
|
23
|
+
```
|
|
20
24
|
|
|
21
25
|
Or install it yourself as:
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
```
|
|
28
|
+
$ gem install sequelizer
|
|
29
|
+
```
|
|
24
30
|
|
|
25
31
|
## Usage
|
|
26
32
|
|
|
27
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.
|
|
28
34
|
|
|
29
|
-
Sequelizer comes with a handy command that will print out your connection parameters.
|
|
35
|
+
Sequelizer comes with a handy command that will print out your connection parameters. Just run:
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
```
|
|
38
|
+
bundle exec sequelizer config
|
|
39
|
+
```
|
|
32
40
|
|
|
33
|
-
You'll also need to make sure the gem for your database is installed.
|
|
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.
|
|
34
42
|
|
|
35
|
-
Sequelizer comes with a handy command that will update your Gemfile for you.
|
|
43
|
+
Sequelizer comes with a handy command that will update your Gemfile for you. Once you've specified your database configuration, run
|
|
36
44
|
|
|
37
|
-
|
|
45
|
+
```
|
|
46
|
+
bundle exec sequelizer update_gemfile
|
|
47
|
+
```
|
|
38
48
|
|
|
39
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.
|
|
40
50
|
|
|
41
51
|
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`
|
|
42
52
|
|
|
43
53
|
Observe:
|
|
54
|
+
|
|
44
55
|
```ruby
|
|
45
56
|
require 'sequelizer'
|
|
46
57
|
|
|
@@ -59,17 +70,19 @@ end
|
|
|
59
70
|
|
|
60
71
|
`new_db` will create a new connection to the database on each call.
|
|
61
72
|
|
|
62
|
-
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.
|
|
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:
|
|
63
74
|
|
|
64
|
-
|
|
75
|
+
```
|
|
76
|
+
passed_options > .env > manually defined environment variables > config/database.yml > ~/.config/sequelizer/database.yml
|
|
77
|
+
```
|
|
65
78
|
|
|
66
|
-
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.
|
|
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.
|
|
67
80
|
|
|
68
81
|
Take a look at the examples directory for a few ways you can specify your database configuration options.
|
|
69
82
|
|
|
70
83
|
## Frustrations
|
|
71
84
|
|
|
72
|
-
I can't seem to figure out a way to avoid having to specify the database gem in the a user's bundler file.
|
|
85
|
+
I can't seem to figure out a way to avoid having to specify the database gem in the a user's bundler file. If anyone has ideas on how to automagically load the correct database gem based on the database options fed to Sequelizer, please let me know (#1)!
|
|
73
86
|
|
|
74
87
|
## Contributing
|
|
75
88
|
|
|
@@ -82,9 +95,10 @@ I can't seem to figure out a way to avoid having to specify the database gem in
|
|
|
82
95
|
## Thanks
|
|
83
96
|
|
|
84
97
|
- [Outcomes Insights, Inc.](http://outins.com)
|
|
85
|
-
|
|
98
|
+
- Many thanks for allowing me to release a portion of my work as Open Source Software!
|
|
86
99
|
- Jeremy Evans
|
|
87
|
-
|
|
100
|
+
- For writing Sequel!
|
|
88
101
|
|
|
89
102
|
## License
|
|
103
|
+
|
|
90
104
|
Released under the MIT license, Copyright (c) 2014 Outcomes Insights, Inc.
|
|
@@ -88,37 +88,27 @@ module Sequel
|
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
# Find column information for a given table/view name.
|
|
91
|
-
#
|
|
91
|
+
# Searches all registries in priority order:
|
|
92
92
|
# 1. Created views (highest priority - most recent)
|
|
93
93
|
# 2. Created tables (medium priority - session specific)
|
|
94
94
|
# 3. Loaded schemas (lowest priority - external definitions)
|
|
95
95
|
#
|
|
96
|
-
# @param name [String, Symbol
|
|
96
|
+
# @param name [String, Symbol, Sequel::SQL::Identifier, Sequel::SQL::QualifiedIdentifier]
|
|
97
97
|
# @return [Array<Symbol>, nil] array of column names as symbols, or nil if not found
|
|
98
98
|
def find_columns(name)
|
|
99
|
-
table_name = name.to_s
|
|
100
99
|
literal_name = @db.literal(name)
|
|
100
|
+
table_name = name_to_string(name)
|
|
101
101
|
|
|
102
|
-
# Search through registries in priority order
|
|
103
102
|
[@created_views, @created_tables, @schemas].each do |registry|
|
|
104
103
|
next unless registry
|
|
105
104
|
|
|
106
|
-
# Try literal representation first (most common for created tables/views)
|
|
107
105
|
if (columns = Sequel.synchronize { registry[literal_name] })
|
|
108
106
|
return columns.map { |c, _| c }
|
|
109
107
|
end
|
|
110
108
|
|
|
111
|
-
# Try string representation (for manually added schemas)
|
|
112
109
|
if (columns = Sequel.synchronize { registry[table_name] })
|
|
113
110
|
return columns.map { |c, _| c }
|
|
114
111
|
end
|
|
115
|
-
|
|
116
|
-
# Try finding by Sequel::LiteralString key (for test setup compatibility)
|
|
117
|
-
registry.each_key do |key|
|
|
118
|
-
if key.respond_to?(:to_s) && key.to_s == literal_name && (columns = Sequel.synchronize { registry[key] })
|
|
119
|
-
return columns.map { |c, _| c }
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
112
|
end
|
|
123
113
|
|
|
124
114
|
nil
|
|
@@ -140,6 +130,22 @@ module Sequel
|
|
|
140
130
|
Sequel.synchronize { @schemas = schemas_hash }
|
|
141
131
|
end
|
|
142
132
|
|
|
133
|
+
private
|
|
134
|
+
|
|
135
|
+
# Extract a plain string name from any Sequel name type.
|
|
136
|
+
# Sequel::SQL::Identifier#to_s returns an inspect-like string, not the value,
|
|
137
|
+
# so we must unwrap expression types to get a usable lookup key.
|
|
138
|
+
def name_to_string(name)
|
|
139
|
+
case name
|
|
140
|
+
when Sequel::SQL::QualifiedIdentifier
|
|
141
|
+
"#{name_to_string(name.table)}.#{name_to_string(name.column)}"
|
|
142
|
+
when Sequel::SQL::Identifier
|
|
143
|
+
name.value.to_s
|
|
144
|
+
else
|
|
145
|
+
name.to_s
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
143
149
|
end
|
|
144
150
|
|
|
145
151
|
# Sets up the cold column tracking when the extension is loaded
|
|
@@ -172,7 +178,12 @@ module Sequel
|
|
|
172
178
|
|
|
173
179
|
def create_table_as(name, sql, options = {})
|
|
174
180
|
super.tap do |_|
|
|
175
|
-
|
|
181
|
+
columns = begin
|
|
182
|
+
columns_from_sql(sql)
|
|
183
|
+
rescue StandardError
|
|
184
|
+
nil
|
|
185
|
+
end
|
|
186
|
+
record_table(name, columns) if columns
|
|
176
187
|
end
|
|
177
188
|
end
|
|
178
189
|
|
|
@@ -190,7 +201,12 @@ module Sequel
|
|
|
190
201
|
|
|
191
202
|
def create_view_sql(name, source, options)
|
|
192
203
|
super.tap do |_|
|
|
193
|
-
|
|
204
|
+
columns = begin
|
|
205
|
+
columns_from_sql(source)
|
|
206
|
+
rescue StandardError
|
|
207
|
+
nil
|
|
208
|
+
end
|
|
209
|
+
record_view(name, columns) if columns && !options[:dont_record]
|
|
194
210
|
end
|
|
195
211
|
end
|
|
196
212
|
|
|
@@ -348,6 +364,14 @@ module Sequel
|
|
|
348
364
|
return columns
|
|
349
365
|
end
|
|
350
366
|
|
|
367
|
+
# Fall back to database query for real tables cold_col doesn't know about
|
|
368
|
+
begin
|
|
369
|
+
columns = db[name].columns!
|
|
370
|
+
return columns if columns && !columns.empty?
|
|
371
|
+
rescue StandardError
|
|
372
|
+
nil
|
|
373
|
+
end
|
|
374
|
+
|
|
351
375
|
raise("Failed to find columns for #{literal(name)}")
|
|
352
376
|
end
|
|
353
377
|
|
|
@@ -87,13 +87,9 @@ module Sequel
|
|
|
87
87
|
only_tables = Array(opts[:only])
|
|
88
88
|
created_views = Array(opts[:except]) || []
|
|
89
89
|
(opts[:search_path] || []).flatten.each do |schema|
|
|
90
|
-
schema = schema.to_sym unless schema.is_a?(Pathname)
|
|
90
|
+
schema = schema.to_sym unless schema.is_a?(Pathname) || schema.is_a?(Sequel::SQL::QualifiedIdentifier)
|
|
91
91
|
source = get_source(db, schema)
|
|
92
|
-
tables =
|
|
93
|
-
source.tables - created_views
|
|
94
|
-
else
|
|
95
|
-
source.tables(schema: schema) - created_views
|
|
96
|
-
end
|
|
92
|
+
tables = available_tables(source, schema, created_views)
|
|
97
93
|
tables &= only_tables unless only_tables.empty?
|
|
98
94
|
tables.each do |table|
|
|
99
95
|
create_view(source, table, schema)
|
|
@@ -102,6 +98,20 @@ module Sequel
|
|
|
102
98
|
end
|
|
103
99
|
end
|
|
104
100
|
|
|
101
|
+
# Returns tables (and views) from the source that haven't already been created.
|
|
102
|
+
#
|
|
103
|
+
# @param source [Sequel::Database, FileSourcerer] the source handler
|
|
104
|
+
# @param schema [Symbol, Pathname] the schema or file path
|
|
105
|
+
# @param created_views [Array<Symbol>] tables/views already created
|
|
106
|
+
# @return [Array<Symbol>] available table names
|
|
107
|
+
def available_tables(source, schema, created_views)
|
|
108
|
+
if schema.is_a?(Pathname)
|
|
109
|
+
source.tables - created_views
|
|
110
|
+
else
|
|
111
|
+
(source.tables(schema: schema) + source.views(schema: schema)) - created_views
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
105
115
|
# Creates a temporary view for the given table.
|
|
106
116
|
#
|
|
107
117
|
# @param source [Object] the source (database or FileSourcerer)
|
|
@@ -110,9 +120,9 @@ module Sequel
|
|
|
110
120
|
def create_view(source, table, schema)
|
|
111
121
|
if schema.to_s =~ %r{/}
|
|
112
122
|
source.create_view(table, temp: true)
|
|
123
|
+
elsif db.database_type == :duckdb
|
|
124
|
+
source.create_or_replace_view(table, db[Sequel.qualify(schema, table)], temp: true)
|
|
113
125
|
else
|
|
114
|
-
# For schema-based tables, just create temporary views
|
|
115
|
-
# This extension is primarily for Spark SQL-based databases
|
|
116
126
|
source.create_view(table, db[Sequel.qualify(schema, table)], temp: true)
|
|
117
127
|
end
|
|
118
128
|
end
|
|
@@ -265,20 +265,19 @@ module Sequel
|
|
|
265
265
|
platform_class.new(db, *config_paths)
|
|
266
266
|
end
|
|
267
267
|
|
|
268
|
-
#
|
|
269
|
-
#
|
|
268
|
+
# Returns the effective database type for platform selection.
|
|
269
|
+
#
|
|
270
|
+
# For real connections, database_type is authoritative. For mock
|
|
271
|
+
# connections whose shared adapter isn't installed (e.g. snowflake,
|
|
272
|
+
# athena), database_type returns :mock; fall back to opts[:host].
|
|
270
273
|
#
|
|
271
274
|
# @param db [Sequel::Database] Database connection
|
|
272
|
-
# @return [Symbol] Effective
|
|
275
|
+
# @return [Symbol] Effective database type
|
|
273
276
|
def self.effective_adapter(db)
|
|
274
|
-
return db.adapter_scheme unless db.adapter_scheme == :mock
|
|
275
|
-
|
|
276
|
-
# Mock databases: try database_type first (set for known types like postgres, spark)
|
|
277
277
|
db_type = db.database_type
|
|
278
|
-
return db_type
|
|
278
|
+
return db_type unless db_type == :mock
|
|
279
279
|
|
|
280
|
-
|
|
281
|
-
db.opts[:host]
|
|
280
|
+
db.opts[:host]&.to_sym
|
|
282
281
|
end
|
|
283
282
|
|
|
284
283
|
# Extension hook - called when extension is loaded
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# The smart_select_remove extension overrides select_remove to resolve
|
|
5
|
+
# column information from the dataset's expression tree before falling
|
|
6
|
+
# back to the original select_remove behavior (which executes SQL via
|
|
7
|
+
# columns!).
|
|
8
|
+
#
|
|
9
|
+
# This is essential for lazy query building patterns where datasets
|
|
10
|
+
# reference tables that may not exist yet at query-build time. By
|
|
11
|
+
# walking through from_self chains and inspecting inner SELECT lists,
|
|
12
|
+
# this extension can determine which columns to keep without touching
|
|
13
|
+
# the database.
|
|
14
|
+
#
|
|
15
|
+
# You should load this extension into all of a database's datasets:
|
|
16
|
+
#
|
|
17
|
+
# DB.extension(:smart_select_remove)
|
|
18
|
+
#
|
|
19
|
+
# This automatically loads the select_remove extension as well.
|
|
20
|
+
#
|
|
21
|
+
# Related module: Sequel::SmartSelectRemove
|
|
22
|
+
|
|
23
|
+
module Sequel
|
|
24
|
+
|
|
25
|
+
module SmartSelectRemove
|
|
26
|
+
|
|
27
|
+
# Override select_remove to attempt static column resolution before
|
|
28
|
+
# falling back to the original implementation.
|
|
29
|
+
#
|
|
30
|
+
# When the dataset has no explicit SELECT clause, walks through
|
|
31
|
+
# from_self chains to find inner column expressions and resolves
|
|
32
|
+
# them to outer-scope symbol names. This avoids the columns! call
|
|
33
|
+
# that the original select_remove uses, which would execute SQL.
|
|
34
|
+
#
|
|
35
|
+
# @param cols [Array<Symbol>] columns to remove
|
|
36
|
+
# @return [Sequel::Dataset] dataset with columns removed
|
|
37
|
+
def select_remove(*cols)
|
|
38
|
+
# If there's an explicit select, original behavior handles it
|
|
39
|
+
return super if @opts[:select] && !@opts[:select].empty?
|
|
40
|
+
|
|
41
|
+
# Try to resolve columns by walking the from_self chain
|
|
42
|
+
if (inner_cols = resolve_selected_columns)
|
|
43
|
+
outer_cols = inner_cols.map { |c| resolve_outer_column_name(c) }
|
|
44
|
+
# All columns must be resolvable; bail to super if any are opaque
|
|
45
|
+
return super if outer_cols.any?(&:nil?)
|
|
46
|
+
|
|
47
|
+
return select(*(outer_cols - cols))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
super
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
# Walk through from_self chains to find the innermost explicit
|
|
56
|
+
# SELECT list. Returns nil if no explicit selection is found.
|
|
57
|
+
#
|
|
58
|
+
# @param ds [Sequel::Dataset] the dataset to inspect
|
|
59
|
+
# @return [Array, nil] the inner SELECT expressions, or nil
|
|
60
|
+
def resolve_selected_columns(ds = self)
|
|
61
|
+
opts = ds.opts
|
|
62
|
+
if (sel = opts[:select]) && !sel.empty?
|
|
63
|
+
sel
|
|
64
|
+
elsif (from = opts[:from]&.first)
|
|
65
|
+
case from
|
|
66
|
+
when Sequel::Dataset
|
|
67
|
+
resolve_selected_columns(from)
|
|
68
|
+
when Sequel::SQL::AliasedExpression
|
|
69
|
+
resolve_selected_columns(from.expression) if from.expression.is_a?(Sequel::Dataset)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Map an inner SELECT expression to its outer-scope column name.
|
|
75
|
+
# After from_self, inner expressions become subquery output columns
|
|
76
|
+
# referenced by their alias or base name in the outer scope.
|
|
77
|
+
#
|
|
78
|
+
# @param col [Object] a column expression from the inner SELECT
|
|
79
|
+
# @return [Symbol, nil] the outer column name, or nil if unresolvable
|
|
80
|
+
def resolve_outer_column_name(col)
|
|
81
|
+
case col
|
|
82
|
+
when Symbol
|
|
83
|
+
col
|
|
84
|
+
when Sequel::SQL::AliasedExpression
|
|
85
|
+
a = col.alias
|
|
86
|
+
a.is_a?(Symbol) ? a : a.to_sym
|
|
87
|
+
when Sequel::SQL::QualifiedIdentifier
|
|
88
|
+
resolve_outer_column_name(col.column)
|
|
89
|
+
when Sequel::SQL::Identifier
|
|
90
|
+
col.value.to_sym
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
Database.register_extension(:smart_select_remove) do |db|
|
|
97
|
+
db.extension(:select_remove)
|
|
98
|
+
db.extend_datasets(SmartSelectRemove)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
data/lib/sequelizer/options.rb
CHANGED
|
@@ -147,17 +147,22 @@ module Sequelizer
|
|
|
147
147
|
# 1. Create each schema in the search path if it doesn't exist
|
|
148
148
|
# 2. Set the search_path for the connection
|
|
149
149
|
#
|
|
150
|
-
# @param search_path [String]
|
|
150
|
+
# @param search_path [String, Array<String>] PostgreSQL schema names as a
|
|
151
|
+
# comma-separated string, an Array of schema names, or a mixed Array
|
|
152
|
+
# containing comma-separated strings
|
|
151
153
|
# @return [Proc] callback to execute after connection
|
|
152
|
-
# @example
|
|
154
|
+
# @example String input
|
|
153
155
|
# callback = after_connect('public,app_schema')
|
|
154
|
-
#
|
|
156
|
+
# @example Array input
|
|
157
|
+
# callback = after_connect(['public', 'app_schema'])
|
|
155
158
|
def after_connect(search_path)
|
|
159
|
+
schemas = Array(search_path).flat_map { |p| p.to_s.split(',') }.map(&:strip)
|
|
160
|
+
path_string = schemas.join(', ')
|
|
156
161
|
proc do |conn|
|
|
157
|
-
|
|
162
|
+
schemas.each do |schema|
|
|
158
163
|
conn.execute("CREATE SCHEMA IF NOT EXISTS #{schema}")
|
|
159
164
|
end
|
|
160
|
-
conn.execute("SET search_path TO #{
|
|
165
|
+
conn.execute("SET search_path TO #{path_string}")
|
|
161
166
|
end
|
|
162
167
|
end
|
|
163
168
|
|