click_house 1.7.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +15 -4
  3. data/CHANGELOG.md +8 -0
  4. data/Gemfile.lock +22 -31
  5. data/Gemfile_faraday1 +11 -0
  6. data/Gemfile_faraday1.lock +111 -0
  7. data/Gemfile_faraday2 +1 -0
  8. data/Gemfile_faraday2.lock +88 -0
  9. data/Makefile +25 -0
  10. data/README.md +5 -19
  11. data/click_house.gemspec +4 -3
  12. data/lib/click_house/ast/parser.rb +53 -0
  13. data/lib/click_house/ast/statement.rb +99 -0
  14. data/lib/click_house/ast/ticker.rb +42 -0
  15. data/lib/click_house/ast.rb +9 -0
  16. data/lib/click_house/config.rb +17 -1
  17. data/lib/click_house/connection.rb +3 -2
  18. data/lib/click_house/definition/column_set.rb +3 -2
  19. data/lib/click_house/extend/configurable.rb +2 -0
  20. data/lib/click_house/extend/type_definition.rb +1 -11
  21. data/lib/click_house/middleware/parse_csv.rb +5 -6
  22. data/lib/click_house/middleware/parse_json.rb +16 -0
  23. data/lib/click_house/middleware/parse_json_oj.rb +22 -0
  24. data/lib/click_house/middleware/raise_error.rb +6 -12
  25. data/lib/click_house/middleware/response_base.rb +45 -0
  26. data/lib/click_house/middleware.rb +3 -0
  27. data/lib/click_house/response/result_set.rb +56 -43
  28. data/lib/click_house/response.rb +1 -0
  29. data/lib/click_house/type/array_type.rb +6 -12
  30. data/lib/click_house/type/base_type.rb +25 -1
  31. data/lib/click_house/type/date_time64_type.rb +5 -1
  32. data/lib/click_house/type/date_time_type.rb +5 -1
  33. data/lib/click_house/type/decimal_type.rb +15 -1
  34. data/lib/click_house/type/low_cardinality_type.rb +4 -10
  35. data/lib/click_house/type/map_type.rb +15 -0
  36. data/lib/click_house/type/nullable_type.rb +6 -8
  37. data/lib/click_house/type/string_type.rb +1 -1
  38. data/lib/click_house/type/tuple_type.rb +15 -0
  39. data/lib/click_house/type.rb +2 -0
  40. data/lib/click_house/version.rb +1 -1
  41. data/lib/click_house.rb +9 -2
  42. metadata +37 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49f4230ea84634e1cfed295d8cc41239d1212bb48807b68636ce82c6cba08039
4
- data.tar.gz: e78054a1f0e3094746adfea54b8fcf649d306cbaa1fce636e822a073ac446376
3
+ metadata.gz: 87293ae8c38bd7182d525925ca9c36c4660c004465d0d7b4ce9f27f166ef6c6d
4
+ data.tar.gz: 93bb17fe88aae7e0dae175a4b03dced840a6e8d57b507d78f91833e470cd8cbf
5
5
  SHA512:
6
- metadata.gz: 280540bf287f99f4fc87e90c47bd94312cc4a82047ada6f193ca4e77b84527c7733e2260f8cb7c960a04d726ffbe449612cf9ee3f297bf30cc6ba27e2ccb9b7c
7
- data.tar.gz: 8a4e4213c46c99181a521e749e57fd63857cb0f135fa41ef9e25781947ecbef4eb8844a9062305a5080abeea85e4dee652d50b432e9c1b1cd65f12bf43006624
6
+ metadata.gz: e7309f25dddb0c7f6e6c032098b6b47b324cbc8c731ff15958bf38f835e3dcacc222cb2f7e7c59a1aeec32b952afb4916e23cacdaf323a624d0c4a6e07e7a114
7
+ data.tar.gz: dbe36582b28d40ab85bf02067495296609b27600fa4ff3b1b0d7e81bb3890af512ffb4a5a7d045f7b155753c75e31c0353801fbc256767d2a594743a63090aae
@@ -14,7 +14,7 @@ jobs:
14
14
 
15
15
  strategy:
16
16
  matrix:
17
- ruby-version: [3.1, '3.0', 2.7, 2.6]
17
+ ruby-version: [3.1, '3.0', 2.7]
18
18
 
19
19
  steps:
20
20
  - uses: actions/checkout@v2
@@ -23,10 +23,21 @@ jobs:
23
23
  uses: ruby/setup-ruby@v1
24
24
  with:
25
25
  ruby-version: ${{ matrix.ruby-version }}
26
- bundler-cache: true # 'bundle install' and cache
27
26
 
28
- - name: Run tests
29
- run: bundle exec rspec
27
+ - name: Setup v1
28
+ run: make faraday1 bundle
29
+
30
+ - name: Setup v2
31
+ run: make faraday2 bundle
32
+
33
+ - name: Run tests with faraday v.1 JSON
34
+ run: make faraday1 rspec
35
+ - name: Run tests with faraday v.2 JSON
36
+ run: make faraday2 rspec
37
+ - name: Run tests with faraday v.1 OJ
38
+ run: make faraday1 oj rspec
39
+ - name: Run tests with faraday v.2 OJ
40
+ run: make faraday2 oj rspec
30
41
 
31
42
  rubocop:
32
43
  runs-on: ubuntu-latest
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 2.0.0
2
+ * Fixed `Bigdecimal` casting with high precision
3
+ * Added nested `type casting like Array(Array(Array(Nullable(T))))`
4
+ * Added `Map(T1, T2)` support
5
+ * Added `Tuple(T1, T2)` support
6
+ * Added support for `Faraday` v1 and v2
7
+ * Added support for `Oj` parser
8
+
1
9
  # 1.6.3
2
10
  * [PR](https://github.com/shlima/click_house/pull/38) Add option format for insert
3
11
  * [PR](https://github.com/shlima/click_house/pull/34) Support X-ClickHouse-Exception-Code header
data/Gemfile.lock CHANGED
@@ -1,44 +1,32 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- click_house (1.7.0)
5
- faraday (>= 1.7)
6
- faraday_middleware
4
+ click_house (2.0.0)
5
+ activesupport
6
+ faraday (>= 1.7, < 3)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
+ activesupport (7.0.4)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 1.6, < 2)
14
+ minitest (>= 5.1)
15
+ tzinfo (~> 2.0)
11
16
  ast (2.4.2)
12
17
  coderay (1.1.3)
18
+ concurrent-ruby (1.1.10)
13
19
  diff-lcs (1.5.0)
14
- faraday (1.10.2)
15
- faraday-em_http (~> 1.0)
16
- faraday-em_synchrony (~> 1.0)
17
- faraday-excon (~> 1.1)
18
- faraday-httpclient (~> 1.0)
19
- faraday-multipart (~> 1.0)
20
- faraday-net_http (~> 1.0)
21
- faraday-net_http_persistent (~> 1.0)
22
- faraday-patron (~> 1.0)
23
- faraday-rack (~> 1.0)
24
- faraday-retry (~> 1.0)
20
+ faraday (2.7.1)
21
+ faraday-net_http (>= 2.0, < 3.1)
25
22
  ruby2_keywords (>= 0.0.4)
26
- faraday-em_http (1.0.0)
27
- faraday-em_synchrony (1.0.0)
28
- faraday-excon (1.1.0)
29
- faraday-httpclient (1.0.1)
30
- faraday-multipart (1.0.4)
31
- multipart-post (~> 2)
32
- faraday-net_http (1.0.1)
33
- faraday-net_http_persistent (1.2.0)
34
- faraday-patron (1.0.0)
35
- faraday-rack (1.0.0)
36
- faraday-retry (1.0.3)
37
- faraday_middleware (1.2.0)
38
- faraday (~> 1.0)
23
+ faraday-net_http (3.0.2)
24
+ i18n (1.12.0)
25
+ concurrent-ruby (~> 1.0)
39
26
  json (2.6.2)
40
27
  method_source (1.0.0)
41
- multipart-post (2.2.3)
28
+ minitest (5.16.3)
29
+ oj (3.13.23)
42
30
  parallel (1.22.1)
43
31
  parser (3.1.2.1)
44
32
  ast (~> 2.4.1)
@@ -47,7 +35,7 @@ GEM
47
35
  method_source (~> 1.0)
48
36
  rainbow (3.1.1)
49
37
  rake (13.0.6)
50
- regexp_parser (2.6.0)
38
+ regexp_parser (2.6.1)
51
39
  rexml (3.2.5)
52
40
  rspec (3.12.0)
53
41
  rspec-core (~> 3.12.0)
@@ -62,7 +50,7 @@ GEM
62
50
  diff-lcs (>= 1.2.0, < 2.0)
63
51
  rspec-support (~> 3.12.0)
64
52
  rspec-support (3.12.0)
65
- rubocop (1.38.0)
53
+ rubocop (1.39.0)
66
54
  json (~> 2.3)
67
55
  parallel (~> 1.10)
68
56
  parser (>= 3.1.2.1)
@@ -74,11 +62,13 @@ GEM
74
62
  unicode-display_width (>= 1.4.0, < 3.0)
75
63
  rubocop-ast (1.23.0)
76
64
  parser (>= 3.1.1.0)
77
- rubocop-performance (1.15.0)
65
+ rubocop-performance (1.15.1)
78
66
  rubocop (>= 1.7.0, < 2.0)
79
67
  rubocop-ast (>= 0.4.0)
80
68
  ruby-progressbar (1.11.0)
81
69
  ruby2_keywords (0.0.5)
70
+ tzinfo (2.0.5)
71
+ concurrent-ruby (~> 1.0)
82
72
  unicode-display_width (2.3.0)
83
73
 
84
74
  PLATFORMS
@@ -87,6 +77,7 @@ PLATFORMS
87
77
  DEPENDENCIES
88
78
  bundler
89
79
  click_house!
80
+ oj
90
81
  pry
91
82
  rake
92
83
  rspec
data/Gemfile_faraday1 ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # lock faraday to v1
8
+ gem 'faraday_middleware'
9
+
10
+ # Specify your gem's dependencies in click_house.gemspec
11
+ gemspec
@@ -0,0 +1,111 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ click_house (1.7.0)
5
+ activesupport
6
+ faraday (>= 1.7, < 3)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (7.0.4)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 1.6, < 2)
14
+ minitest (>= 5.1)
15
+ tzinfo (~> 2.0)
16
+ ast (2.4.2)
17
+ coderay (1.1.3)
18
+ concurrent-ruby (1.1.10)
19
+ diff-lcs (1.5.0)
20
+ faraday (1.10.2)
21
+ faraday-em_http (~> 1.0)
22
+ faraday-em_synchrony (~> 1.0)
23
+ faraday-excon (~> 1.1)
24
+ faraday-httpclient (~> 1.0)
25
+ faraday-multipart (~> 1.0)
26
+ faraday-net_http (~> 1.0)
27
+ faraday-net_http_persistent (~> 1.0)
28
+ faraday-patron (~> 1.0)
29
+ faraday-rack (~> 1.0)
30
+ faraday-retry (~> 1.0)
31
+ ruby2_keywords (>= 0.0.4)
32
+ faraday-em_http (1.0.0)
33
+ faraday-em_synchrony (1.0.0)
34
+ faraday-excon (1.1.0)
35
+ faraday-httpclient (1.0.1)
36
+ faraday-multipart (1.0.4)
37
+ multipart-post (~> 2)
38
+ faraday-net_http (1.0.1)
39
+ faraday-net_http_persistent (1.2.0)
40
+ faraday-patron (1.0.0)
41
+ faraday-rack (1.0.0)
42
+ faraday-retry (1.0.3)
43
+ faraday_middleware (1.2.0)
44
+ faraday (~> 1.0)
45
+ i18n (1.12.0)
46
+ concurrent-ruby (~> 1.0)
47
+ json (2.6.2)
48
+ method_source (1.0.0)
49
+ minitest (5.16.3)
50
+ multipart-post (2.2.3)
51
+ oj (3.13.23)
52
+ parallel (1.22.1)
53
+ parser (3.1.2.1)
54
+ ast (~> 2.4.1)
55
+ pry (0.14.1)
56
+ coderay (~> 1.1)
57
+ method_source (~> 1.0)
58
+ rainbow (3.1.1)
59
+ rake (13.0.6)
60
+ regexp_parser (2.6.1)
61
+ rexml (3.2.5)
62
+ rspec (3.12.0)
63
+ rspec-core (~> 3.12.0)
64
+ rspec-expectations (~> 3.12.0)
65
+ rspec-mocks (~> 3.12.0)
66
+ rspec-core (3.12.0)
67
+ rspec-support (~> 3.12.0)
68
+ rspec-expectations (3.12.0)
69
+ diff-lcs (>= 1.2.0, < 2.0)
70
+ rspec-support (~> 3.12.0)
71
+ rspec-mocks (3.12.0)
72
+ diff-lcs (>= 1.2.0, < 2.0)
73
+ rspec-support (~> 3.12.0)
74
+ rspec-support (3.12.0)
75
+ rubocop (1.39.0)
76
+ json (~> 2.3)
77
+ parallel (~> 1.10)
78
+ parser (>= 3.1.2.1)
79
+ rainbow (>= 2.2.2, < 4.0)
80
+ regexp_parser (>= 1.8, < 3.0)
81
+ rexml (>= 3.2.5, < 4.0)
82
+ rubocop-ast (>= 1.23.0, < 2.0)
83
+ ruby-progressbar (~> 1.7)
84
+ unicode-display_width (>= 1.4.0, < 3.0)
85
+ rubocop-ast (1.23.0)
86
+ parser (>= 3.1.1.0)
87
+ rubocop-performance (1.15.1)
88
+ rubocop (>= 1.7.0, < 2.0)
89
+ rubocop-ast (>= 0.4.0)
90
+ ruby-progressbar (1.11.0)
91
+ ruby2_keywords (0.0.5)
92
+ tzinfo (2.0.5)
93
+ concurrent-ruby (~> 1.0)
94
+ unicode-display_width (2.3.0)
95
+
96
+ PLATFORMS
97
+ x86_64-darwin-21
98
+
99
+ DEPENDENCIES
100
+ bundler
101
+ click_house!
102
+ faraday_middleware
103
+ oj
104
+ pry
105
+ rake
106
+ rspec
107
+ rubocop
108
+ rubocop-performance
109
+
110
+ BUNDLED WITH
111
+ 2.3.7
data/Gemfile_faraday2 ADDED
@@ -0,0 +1 @@
1
+ Gemfile
@@ -0,0 +1,88 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ click_house (1.7.0)
5
+ activesupport
6
+ faraday (>= 1.7, < 3)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (7.0.4)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 1.6, < 2)
14
+ minitest (>= 5.1)
15
+ tzinfo (~> 2.0)
16
+ ast (2.4.2)
17
+ coderay (1.1.3)
18
+ concurrent-ruby (1.1.10)
19
+ diff-lcs (1.5.0)
20
+ faraday (2.7.1)
21
+ faraday-net_http (>= 2.0, < 3.1)
22
+ ruby2_keywords (>= 0.0.4)
23
+ faraday-net_http (3.0.2)
24
+ i18n (1.12.0)
25
+ concurrent-ruby (~> 1.0)
26
+ json (2.6.2)
27
+ method_source (1.0.0)
28
+ minitest (5.16.3)
29
+ oj (3.13.23)
30
+ parallel (1.22.1)
31
+ parser (3.1.2.1)
32
+ ast (~> 2.4.1)
33
+ pry (0.14.1)
34
+ coderay (~> 1.1)
35
+ method_source (~> 1.0)
36
+ rainbow (3.1.1)
37
+ rake (13.0.6)
38
+ regexp_parser (2.6.1)
39
+ rexml (3.2.5)
40
+ rspec (3.12.0)
41
+ rspec-core (~> 3.12.0)
42
+ rspec-expectations (~> 3.12.0)
43
+ rspec-mocks (~> 3.12.0)
44
+ rspec-core (3.12.0)
45
+ rspec-support (~> 3.12.0)
46
+ rspec-expectations (3.12.0)
47
+ diff-lcs (>= 1.2.0, < 2.0)
48
+ rspec-support (~> 3.12.0)
49
+ rspec-mocks (3.12.0)
50
+ diff-lcs (>= 1.2.0, < 2.0)
51
+ rspec-support (~> 3.12.0)
52
+ rspec-support (3.12.0)
53
+ rubocop (1.39.0)
54
+ json (~> 2.3)
55
+ parallel (~> 1.10)
56
+ parser (>= 3.1.2.1)
57
+ rainbow (>= 2.2.2, < 4.0)
58
+ regexp_parser (>= 1.8, < 3.0)
59
+ rexml (>= 3.2.5, < 4.0)
60
+ rubocop-ast (>= 1.23.0, < 2.0)
61
+ ruby-progressbar (~> 1.7)
62
+ unicode-display_width (>= 1.4.0, < 3.0)
63
+ rubocop-ast (1.23.0)
64
+ parser (>= 3.1.1.0)
65
+ rubocop-performance (1.15.1)
66
+ rubocop (>= 1.7.0, < 2.0)
67
+ rubocop-ast (>= 0.4.0)
68
+ ruby-progressbar (1.11.0)
69
+ ruby2_keywords (0.0.5)
70
+ tzinfo (2.0.5)
71
+ concurrent-ruby (~> 1.0)
72
+ unicode-display_width (2.3.0)
73
+
74
+ PLATFORMS
75
+ x86_64-darwin-21
76
+
77
+ DEPENDENCIES
78
+ bundler
79
+ click_house!
80
+ oj
81
+ pry
82
+ rake
83
+ rspec
84
+ rubocop
85
+ rubocop-performance
86
+
87
+ BUNDLED WITH
88
+ 2.3.7
data/Makefile CHANGED
@@ -1,12 +1,37 @@
1
1
  .PHONY: help
2
2
 
3
+ .BUNDLE_GEMFILE:=
4
+ .REQUIRE:=./spec/spec_helper
5
+
3
6
  help:
4
7
  @echo 'Available targets:'
5
8
  @echo ' make dockerize OR make ARGS="--build" dockerize'
6
9
  @echo ' make release'
10
+ @echo ' '
11
+ @echo ' make faraday1 bundle'
12
+ @echo ' make faraday2 bundle'
13
+ @echo ' '
14
+ @echo ' make faraday1 rspec'
15
+ @echo ' make faraday2 rspec'
16
+ @echo ' make faraday2 oj rspec'
7
17
 
8
18
  dockerize:
9
19
  docker-compose up ${ARGS}
10
20
 
11
21
  release:
12
22
  bin/release.sh
23
+
24
+ faraday1:
25
+ $(eval .BUNDLE_GEMFILE=Gemfile_faraday1)
26
+
27
+ faraday2:
28
+ $(eval .BUNDLE_GEMFILE=Gemfile_faraday2)
29
+
30
+ oj:
31
+ $(eval .REQUIRE=./spec/oj_helper)
32
+
33
+ bundle:
34
+ BUNDLE_GEMFILE=${.BUNDLE_GEMFILE} bundle
35
+
36
+ rspec:
37
+ BUNDLE_GEMFILE=${.BUNDLE_GEMFILE} rspec --require ${.REQUIRE} spec
data/README.md CHANGED
@@ -65,6 +65,11 @@ ClickHouse.config do |config|
65
65
 
66
66
  # if you want to add settings to all queries
67
67
  config.global_params = { mutations_sync: 1 }
68
+
69
+ # choose a ruby JSON parser
70
+ config.json_parser = ClickHouse::Middleware::ParseJson
71
+ # or Oj parser
72
+ config.json_parser = ClickHouse::Middleware::ParseJsonOj
68
73
  end
69
74
  ```
70
75
 
@@ -337,25 +342,6 @@ end
337
342
  ClickHouse.add_type('Date', DateType.new)
338
343
  ```
339
344
 
340
- Actually `serialize` function is not used for now, but you may use it manually:
341
-
342
- ```ruby
343
- time_type = ClickHouse::Type::DateTimeType.new
344
- string_type = ClickHouse::Type::FixedStringType.new
345
-
346
- ClickHouse.connection.insert('table', columns: %i[name time]) do |buffer|
347
- buffer << [string_type.serialize('a' * 1000, 20), time_type.serialize(Time.current, 'Europe/Moscow')]
348
- end
349
-
350
- ## alternatively
351
- data = @records.map do |record|
352
- {
353
- id: record.id,
354
- time: ClickHouse.types['DateTime(%s)'].serialize(Time.current)
355
- }
356
- end
357
- ```
358
-
359
345
  If native type supports arguments, define *String* type with `%s`
360
346
  argument and *Numeric* type with `%d` argument:
361
347
 
data/click_house.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.summary = 'Modern Ruby database driver for ClickHouse'
11
11
  spec.description = 'Yandex ClickHouse database interface for Ruby'
12
12
  spec.homepage = 'https://github.com/shlima/click_house'
13
- spec.required_ruby_version = '>= 2.6.0'
13
+ spec.required_ruby_version = '>= 2.7.0'
14
14
 
15
15
  # Specify which files should be added to the gem when it is released.
16
16
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -19,10 +19,11 @@ Gem::Specification.new do |spec|
19
19
  end
20
20
  spec.require_paths = ['lib']
21
21
 
22
- spec.add_dependency 'faraday', '>= 1.7'
23
- spec.add_dependency 'faraday_middleware'
22
+ spec.add_dependency 'faraday', '>= 1.7', '< 3'
23
+ spec.add_dependency 'activesupport'
24
24
  spec.add_development_dependency 'bundler'
25
25
  spec.add_development_dependency 'rake'
26
+ spec.add_development_dependency 'oj'
26
27
  spec.add_development_dependency 'rspec'
27
28
  spec.add_development_dependency 'pry'
28
29
  spec.add_development_dependency 'rubocop'
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stringio'
4
+
5
+ module ClickHouse
6
+ module Ast
7
+ class Parser
8
+ OPEN = '('
9
+ CLOSED = ')'
10
+ COMMA = ','
11
+ SPACE = ' '
12
+
13
+ attr_reader :input
14
+
15
+ # @param input [String]
16
+ def initialize(input)
17
+ @input = input
18
+ end
19
+
20
+ # @refs https://clickhouse.com/docs/en/sql-reference/data-types/
21
+ # Map(String, Decimal(10, 5))
22
+ # Array(Array(Array(Array(Nullable(Int, String)))))
23
+ def parse
24
+ ticker = Ticker.new
25
+ control = false
26
+
27
+ input.each_char do |char|
28
+ # cases like (1,<space after comma> 3)
29
+ next if control && char == SPACE
30
+
31
+ case char
32
+ when OPEN
33
+ control = true
34
+ ticker.open
35
+ when CLOSED
36
+ control = true
37
+ ticker.close
38
+ when COMMA
39
+ control = true
40
+ ticker.comma
41
+ else
42
+ control = false
43
+ ticker.char(char)
44
+ end
45
+ end
46
+
47
+ # if a single type like "Int"
48
+ ticker.current.name! unless control
49
+ ticker.current
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stringio'
4
+
5
+ module ClickHouse
6
+ module Ast
7
+ class Statement
8
+ PLACEHOLDER_S = '%s'
9
+ PLACEHOLDER_D = '%d'
10
+ DIGIT_RE = /\A\d+\Z/.freeze
11
+
12
+ attr_reader :name
13
+ attr_accessor :caster
14
+
15
+ def initialize(name: '')
16
+ @buffer = ''
17
+ @name = name
18
+ @opened = false
19
+ end
20
+
21
+ # @param value [String]
22
+ def print(value)
23
+ @buffer = "#{@buffer}#{value}"
24
+ end
25
+
26
+ def name!
27
+ @name = @buffer
28
+ @buffer = ''
29
+ end
30
+
31
+ def argument!
32
+ add_argument(Statement.new(name: @buffer))
33
+ @buffer = ''
34
+ end
35
+
36
+ # @param st [Statement]
37
+ def add_argument(st)
38
+ arguments.push(st)
39
+ end
40
+
41
+ # @param other [Statement]
42
+ def merge(other)
43
+ if other.named?
44
+ add_argument(other)
45
+ else
46
+ @arguments = arguments.concat(other.arguments)
47
+ end
48
+ end
49
+
50
+ def named?
51
+ !@name.empty?
52
+ end
53
+
54
+ def buffer?
55
+ !@buffer.empty?
56
+ end
57
+
58
+ # @return [Array<Statement>]
59
+ def arguments
60
+ @arguments ||= []
61
+ end
62
+
63
+ def placeholder
64
+ return @placeholder if defined?(@placeholder)
65
+
66
+ @placeholder = digit? ? PLACEHOLDER_D : PLACEHOLDER_S
67
+ end
68
+
69
+ def digit?
70
+ name.match?(DIGIT_RE)
71
+ end
72
+
73
+ def value
74
+ @value ||=
75
+ case placeholder
76
+ when PLACEHOLDER_D
77
+ Integer(name)
78
+ when PLACEHOLDER_S
79
+ # remove leading and trailing quotes
80
+ name[1..-2]
81
+ else
82
+ raise "unknown value extractor for <#{placeholder}>"
83
+ end
84
+ end
85
+
86
+ def to_s
87
+ out = StringIO.new
88
+ out.print(name.empty? ? 'NO_NAME' : name)
89
+ out.print("<#{@buffer}>") unless @buffer.empty?
90
+
91
+ if arguments.any?
92
+ out.print("(#{arguments.join(',')})")
93
+ end
94
+
95
+ out.string
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stringio'
4
+
5
+ module ClickHouse
6
+ module Ast
7
+ class Ticker
8
+ attr_reader :root, :current
9
+
10
+ def initialize
11
+ @current = Statement.new
12
+ end
13
+
14
+ def open
15
+ current.name!
16
+ opened.push(current)
17
+ @current = Statement.new
18
+ end
19
+
20
+ def comma
21
+ current.argument! if current.buffer?
22
+ opened.last.merge(current)
23
+ @current = Statement.new
24
+ end
25
+
26
+ def close
27
+ current.argument! unless current.named?
28
+ opened.last.merge(current)
29
+ @current = opened.pop
30
+ end
31
+
32
+ # @param char [String]
33
+ def char(char)
34
+ current.print(char)
35
+ end
36
+
37
+ def opened
38
+ @opened ||= []
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClickHouse
4
+ module Ast
5
+ autoload :Statement, 'click_house/ast/statement'
6
+ autoload :Ticker, 'click_house/ast/ticker'
7
+ autoload :Parser, 'click_house/ast/parser'
8
+ end
9
+ end