click_house-client 0.10.0 → 0.11.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/Gemfile.lock +2 -2
- data/README.md +27 -0
- data/gemfiles/Gemfile-rails-7.2 +3 -0
- data/lib/click_house/client/query_builder.rb +49 -0
- data/lib/click_house/client/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 20e1cebe2da3ec70c0a9ab7be6e5e53d2f2462b4787fd7e7389adfdbe4c64ea9
|
|
4
|
+
data.tar.gz: 0bdebe100594f4025f53a5c28723ef776d10ff327283166f70c9990a3323bb62
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 58e7ed6985feda6a89dd33a1eac938509d3515016eea6c92ea38621c327a94d6e997dd166d67b3b7a2ddd1350edee0e3997055301159c01e8b0e3cac75531707
|
|
7
|
+
data.tar.gz: fd25cb3026f5be1d693181cbab8c13915abdad23ac0acd31e4d098b4477c35d6ef99e010e3e4c1477eb00b729bbdaecc5d4a2b40f36d1a35d147f4cdd6f1402f
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
click_house-client (0.
|
|
4
|
+
click_house-client (0.11.0)
|
|
5
5
|
activerecord (>= 7.0, < 9.0)
|
|
6
6
|
activesupport (>= 7.0, < 9.0)
|
|
7
7
|
addressable (~> 2.8)
|
|
@@ -136,7 +136,7 @@ CHECKSUMS
|
|
|
136
136
|
benchmark (0.4.1) sha256=d4ef40037bba27f03b28013e219b950b82bace296549ec15a78016552f8d2cce
|
|
137
137
|
bigdecimal (3.2.2) sha256=39085f76b495eb39a79ce07af716f3a6829bc35eb44f2195e2753749f2fa5adc
|
|
138
138
|
byebug (12.0.0) sha256=d4a150d291cca40b66ec9ca31f754e93fed8aa266a17335f71bb0afa7fca1a1e
|
|
139
|
-
click_house-client (0.
|
|
139
|
+
click_house-client (0.11.0)
|
|
140
140
|
concurrent-ruby (1.3.5) sha256=813b3e37aca6df2a21a3b9f1d497f8cbab24a2b94cab325bffe65ee0f6cbebc6
|
|
141
141
|
connection_pool (2.5.3) sha256=cfd74a82b9b094d1ce30c4f1a346da23ee19dc8a062a16a85f58eab1ced4305b
|
|
142
142
|
diff-lcs (1.5.0) sha256=49b934001c8c6aedb37ba19daec5c634da27b318a7a3c654ae979d6ba1929b67
|
data/README.md
CHANGED
|
@@ -233,6 +233,33 @@ query
|
|
|
233
233
|
# => "SELECT * FROM `users` LEFT OUTER JOIN (SELECT `orders`.`id`, `orders`.`user_id` FROM `orders`) `o` ON `users`.`id` = `o`.`user_id`"
|
|
234
234
|
```
|
|
235
235
|
|
|
236
|
+
### Common Table Expressions (CTEs)
|
|
237
|
+
|
|
238
|
+
Use `#as_cte(name)` to wrap a query as a named CTE node, then attach it to a
|
|
239
|
+
main query with `#with(cte)`. The CTE can then be referenced by name in `FROM`
|
|
240
|
+
and IN-subquery positions, which is useful when the same subquery is needed in
|
|
241
|
+
more than one place.
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
inner = ClickHouse::Client::QueryBuilder.new('builds').select(:id, :stage_id)
|
|
245
|
+
query_builder = ClickHouse::Client::QueryBuilder.new('finished_builds').select(:id)
|
|
246
|
+
|
|
247
|
+
query_builder.with(inner.as_cte(:finished_builds)).to_sql
|
|
248
|
+
# => "WITH finished_builds AS (SELECT `builds`.`id`, `builds`.`stage_id` FROM `builds`) SELECT `finished_builds`.`id` FROM `finished_builds`"
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Chained calls accumulate, unlike `Arel::SelectManager#with` which would keep
|
|
252
|
+
only the last CTE:
|
|
253
|
+
|
|
254
|
+
```ruby
|
|
255
|
+
query_builder.with(inner.as_cte(:a)).with(inner.as_cte(:b)).to_sql
|
|
256
|
+
# => "WITH a AS (...), b AS (...) SELECT ..."
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
`#with` returns a new `QueryBuilder` (immutable), requires an `Arel::Nodes::Cte`
|
|
260
|
+
(build it via `#as_cte`), and raises if the same CTE name is declared more than
|
|
261
|
+
once.
|
|
262
|
+
|
|
236
263
|
### Complete Example
|
|
237
264
|
|
|
238
265
|
Here's a comprehensive example combining multiple QueryBuilder features:
|
data/gemfiles/Gemfile-rails-7.2
CHANGED
|
@@ -5,6 +5,9 @@ source "https://rubygems.org"
|
|
|
5
5
|
gemspec path: ".."
|
|
6
6
|
|
|
7
7
|
gem "rails", "~> 7.2"
|
|
8
|
+
# i18n >= 1.15 calls Fiber#[] (Ruby 3.2+) but declares no required_ruby_version,
|
|
9
|
+
# so it resolves on Ruby 3.1 and then crashes at load.
|
|
10
|
+
gem "i18n", "< 1.15"
|
|
8
11
|
gem "gitlab-styles", "~> 12.0.1"
|
|
9
12
|
gem "rake", "~> 13.0"
|
|
10
13
|
gem "rspec", "~> 3.0"
|
|
@@ -198,6 +198,46 @@ module ClickHouse
|
|
|
198
198
|
end
|
|
199
199
|
end
|
|
200
200
|
|
|
201
|
+
# Wraps this query as a CTE node with the given name, so it can be passed
|
|
202
|
+
# to #with: `query_builder.with(sub_query.as_cte(:foo))`. The name is
|
|
203
|
+
# rendered as a SQL identifier, not a quoted value.
|
|
204
|
+
#
|
|
205
|
+
# The manager is cloned so later in-place mutations on this builder (e.g.
|
|
206
|
+
# #limit or #offset) do not alter the captured CTE body.
|
|
207
|
+
#
|
|
208
|
+
# @param name [String, Symbol] name the CTE is referenced by
|
|
209
|
+
# @return [Arel::Nodes::Cte]
|
|
210
|
+
def as_cte(name)
|
|
211
|
+
Arel::Nodes::Cte.new(Arel::Nodes::SqlLiteral.new(name.to_s), to_arel.clone)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Attaches a CTE node, emitting `WITH name AS (...)` before the SELECT.
|
|
215
|
+
# The CTE can then be referenced by name in FROM and IN-subquery positions,
|
|
216
|
+
# which is useful when the same subquery is needed in more than one place.
|
|
217
|
+
#
|
|
218
|
+
# Build the node with #as_cte, for example
|
|
219
|
+
# `query_builder.with(sub_query.as_cte(:foo))`.
|
|
220
|
+
#
|
|
221
|
+
# Chained calls accumulate: `query_builder.with(a).with(b)` emits both
|
|
222
|
+
# CTEs. This differs from `Arel::SelectManager#with`, which replaces any
|
|
223
|
+
# previously set CTE and would keep only `b`.
|
|
224
|
+
#
|
|
225
|
+
# @param cte [Arel::Nodes::Cte] a CTE node from #as_cte
|
|
226
|
+
# @return [ClickHouse::Client::QueryBuilder]
|
|
227
|
+
def with(cte)
|
|
228
|
+
unless cte.is_a?(Arel::Nodes::Cte)
|
|
229
|
+
raise ArgumentError, "expected Arel::Nodes::Cte, got #{cte.class}. " \
|
|
230
|
+
'Use #as_cte(name) to create one.'
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
clone.tap do |new_instance|
|
|
234
|
+
existing = new_instance.manager.ast.with
|
|
235
|
+
all_ctes = existing ? existing.children + [cte] : [cte]
|
|
236
|
+
validate_unique_cte_names!(all_ctes)
|
|
237
|
+
new_instance.manager.ast.with = Arel::Nodes::With.new(all_ctes)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
201
241
|
# Adds a JOIN clause. Pass `type: :outer` for `LEFT OUTER JOIN`.
|
|
202
242
|
# To join a subquery, pre-alias it via `QueryBuilder.new(sub, 'x').table`
|
|
203
243
|
# or `sub.to_arel.as('x')` and pass that.
|
|
@@ -464,6 +504,15 @@ module ClickHouse
|
|
|
464
504
|
|
|
465
505
|
raise ArgumentError, "Invalid join type '#{type}'. Must be :inner or :outer"
|
|
466
506
|
end
|
|
507
|
+
|
|
508
|
+
def validate_unique_cte_names!(ctes)
|
|
509
|
+
names = ctes.map { |cte| cte.name.to_s }
|
|
510
|
+
duplicates = names.tally.select { |_, count| count > 1 }.keys
|
|
511
|
+
|
|
512
|
+
return if duplicates.empty?
|
|
513
|
+
|
|
514
|
+
raise ArgumentError, "duplicate CTE name(s): #{duplicates.join(', ')}"
|
|
515
|
+
end
|
|
467
516
|
end
|
|
468
517
|
end
|
|
469
518
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: click_house-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- group::optimize
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|