click_house 1.7.0 → 2.0.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.
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