active_house 0.4.0 → 0.5.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -0
  3. data/active_house.gemspec +1 -0
  4. data/lib/active_house.rb +1 -1
  5. data/lib/active_house/connection.rb +3 -3
  6. data/lib/active_house/exceptions.rb +9 -0
  7. data/lib/active_house/{logger.rb → logging.rb} +1 -1
  8. data/lib/active_house/model.rb +14 -12
  9. data/lib/active_house/modeling/attributes.rb +102 -0
  10. data/lib/active_house/modeling/connection.rb +38 -0
  11. data/lib/active_house/modeling/query.rb +29 -0
  12. data/lib/active_house/modeling/scope.rb +42 -0
  13. data/lib/active_house/prepared_statement.rb +34 -2
  14. data/lib/active_house/query_builder.rb +38 -0
  15. data/lib/active_house/querying/array_join.rb +42 -0
  16. data/lib/active_house/querying/collect.rb +80 -0
  17. data/lib/active_house/querying/from.rb +30 -0
  18. data/lib/active_house/querying/group_by.rb +30 -0
  19. data/lib/active_house/querying/having.rb +41 -0
  20. data/lib/active_house/querying/limit.rb +35 -0
  21. data/lib/active_house/querying/order_by.rb +58 -0
  22. data/lib/active_house/querying/scope.rb +45 -0
  23. data/lib/active_house/querying/select.rb +35 -0
  24. data/lib/active_house/querying/union.rb +67 -0
  25. data/lib/active_house/querying/where.rb +50 -0
  26. data/lib/active_house/version.rb +1 -1
  27. metadata +34 -22
  28. data/lib/active_house/array_joinable.rb +0 -31
  29. data/lib/active_house/chainable.rb +0 -151
  30. data/lib/active_house/collectable.rb +0 -44
  31. data/lib/active_house/connecting.rb +0 -36
  32. data/lib/active_house/connection_error.rb +0 -6
  33. data/lib/active_house/error.rb +0 -4
  34. data/lib/active_house/fromable.rb +0 -29
  35. data/lib/active_house/groupable.rb +0 -23
  36. data/lib/active_house/havingable.rb +0 -50
  37. data/lib/active_house/limitable.rb +0 -27
  38. data/lib/active_house/modeling.rb +0 -100
  39. data/lib/active_house/orderable.rb +0 -45
  40. data/lib/active_house/query.rb +0 -22
  41. data/lib/active_house/querying.rb +0 -21
  42. data/lib/active_house/scopeable.rb +0 -42
  43. data/lib/active_house/scoping.rb +0 -37
  44. data/lib/active_house/selectable.rb +0 -35
  45. data/lib/active_house/unionable.rb +0 -43
  46. data/lib/active_house/whereable.rb +0 -57
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7200836f06d8f9970958725e34d7114396628bfc
4
- data.tar.gz: 5af9fe43759f8bfec281614e90d1ddb77d03bbbe
3
+ metadata.gz: 460006ab1e148781921648c680e33a79790e35cd
4
+ data.tar.gz: eb9ee437906deca34b1c6bb3bb172dc4bfcdab7b
5
5
  SHA512:
6
- metadata.gz: b2b52863ddcbb884f18cdaaccd9c48562f470c5a06fe6b66863cbe28befdfc009419159b559a22796044c3bc35cec6bcfe564c79dbed123bb982a8f6158cfc8c
7
- data.tar.gz: 88331b558031b0e5f6b3418b666127c81ba7378216693c84b976885fc726301e8c5334efee9c0b3d63e681353600083cbfbbeb3ac5da16f3099a04ef9ccd1572
6
+ metadata.gz: 190813fb7b150e48c7c75c1a53ef12e5dc589ab60b109cf65463644ba3e4c17dd0c94b6fd927e778811dd1e631c0163ec5e6ef7fa5b72425aa34fd68eaca89fc
7
+ data.tar.gz: 16fdecaf5792d2641aca7cd2b3e777d195894cbabe593b2ef1719ad16f83313fc547b3863829bcf764896b75b6721e77f90a08a420574f6d5ca46eb8d7c757f7
data/.rubocop.yml CHANGED
@@ -37,3 +37,12 @@ Layout/IndentArray:
37
37
 
38
38
  Layout/IndentHash:
39
39
  IndentationWidth: 4
40
+
41
+ Layout/EmptyLinesAroundModuleBody:
42
+ Enabled: false
43
+
44
+ Layout/EmptyLinesAroundBlockBody:
45
+ Enabled: false
46
+
47
+ Style/AccessModifierDeclarations:
48
+ Enabled: false
data/active_house.gemspec CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency 'activemodel'
26
26
  spec.add_dependency 'activesupport'
27
27
  spec.add_dependency 'clickhouse', '~> 0.1.10'
28
+ spec.add_dependency 'plain_model', '~> 0.2'
28
29
 
29
30
  spec.add_development_dependency 'bundler', '~> 1.16'
30
31
  spec.add_development_dependency 'minitest', '~> 5.0'
data/lib/active_house.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'active_house/version'
2
2
  require 'active_house/configuration'
3
- require 'active_house/query'
3
+ require 'active_house/query_builder'
4
4
  require 'active_house/model'
5
5
 
6
6
  module ActiveHouse
@@ -1,7 +1,7 @@
1
- require_relative 'connection_error'
2
- require_relative 'prepared_statement'
3
1
  require 'clickhouse/cluster'
4
2
  require 'clickhouse/connection'
3
+ require_relative 'exceptions'
4
+ require_relative 'prepared_statement'
5
5
 
6
6
  module ActiveHouse
7
7
  class Connection
@@ -72,7 +72,7 @@ module ActiveHouse
72
72
 
73
73
  def ensure_connected!
74
74
  @connection = establish_connection unless connection_alive?
75
- raise ActiveHouse::ConnectionError unless connection_alive?
75
+ raise ActiveHouse::Exceptions::ConnectionError unless connection_alive?
76
76
  end
77
77
 
78
78
  def establish_connection
@@ -0,0 +1,9 @@
1
+ module ActiveHouse
2
+ module Exceptions
3
+ class Error < ::StandardError
4
+ end
5
+
6
+ class ConnectionError < Error
7
+ end
8
+ end
9
+ end
@@ -1,7 +1,7 @@
1
1
  require 'active_support/concern'
2
2
 
3
3
  module ActiveHouse
4
- module Logger
4
+ module Logging
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  class_methods do
@@ -1,20 +1,22 @@
1
- require_relative 'scoping'
2
- require_relative 'querying'
3
- require_relative 'modeling'
4
- require_relative 'connecting'
5
- require_relative 'logger'
6
1
  require 'active_model/conversion'
7
2
  require 'active_model/naming'
3
+ require 'plain_model/modeling/base'
4
+ require 'plain_model/modeling/queryable'
5
+ require_relative 'modeling/scope'
6
+ require_relative 'modeling/query'
7
+ require_relative 'modeling/attributes'
8
+ require_relative 'modeling/connection'
9
+ require_relative 'logging'
8
10
 
9
11
  module ActiveHouse
10
12
  class Model
11
- include ActiveHouse::Scoping
12
- include ActiveHouse::Querying
13
- include ActiveHouse::Modeling
14
- include ActiveHouse::Connecting
15
- include ActiveHouse::Logger
16
- include ActiveModel::Conversion
17
- extend ActiveModel::Naming
13
+ extend PlainModel::Modeling::Queryable
14
+ include PlainModel::Modeling::Base
15
+ include ActiveHouse::Modeling::Scope
16
+ include ActiveHouse::Modeling::Query
17
+ include ActiveHouse::Modeling::Attributes
18
+ include ActiveHouse::Modeling::Connection
19
+ include ActiveHouse::Logging
18
20
 
19
21
  class_attribute :_table_name, instance_accessor: false
20
22
 
@@ -0,0 +1,102 @@
1
+ require 'active_support/concern'
2
+
3
+ module ActiveHouse
4
+ module Modeling
5
+ module Attributes
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute :_attribute_opts, instance_writer: false
10
+ self._attribute_opts = {}
11
+
12
+ private
13
+
14
+ def parse_attribute_method_name(method_name)
15
+ name, is_setter = method_name.to_s.match(/\A(.+)?(=)?\z/).captures
16
+ name = name.to_sym
17
+ is_setter = !is_setter.nil?
18
+ [name, is_setter]
19
+ end
20
+
21
+ def attribute_method?(name, is_setter, *args)
22
+ (_attribute_opts.key?(name) || @_attributes.key?(name)) && (is_setter ? args.size == 1 : true)
23
+ end
24
+
25
+ def get_attribute(name)
26
+ @_attributes[name]
27
+ end
28
+
29
+ def set_attribute(name, value)
30
+ opts = _attribute_opts.fetch(name, {})
31
+ value = opts[:cast].call(value) if opts[:cast]
32
+ @_attributes[name] = value
33
+ end
34
+ end
35
+
36
+ class_methods do
37
+ def attribute(name, options = {})
38
+ name = name.to_sym
39
+ self._attribute_opts = _attribute_opts.merge(name => options)
40
+ define_method(name) do
41
+ get_attribute(name)
42
+ end
43
+ define_method("#{name}=") do |value|
44
+ set_attribute(name, value)
45
+ end
46
+ end
47
+
48
+ def attributes(*names)
49
+ options = names.extract_options!
50
+ names.each { |name| attribute(name, options.dup) }
51
+ end
52
+
53
+ def load!(params)
54
+ new.tap do |model|
55
+ params.each { |name, value| model[name] = value }
56
+ end
57
+ end
58
+ end
59
+
60
+ def initialize(params = {})
61
+ @_attributes = {}
62
+ assign_attributes(params) unless params.nil?
63
+ end
64
+
65
+ def as_json(*_args)
66
+ to_h
67
+ end
68
+
69
+ def to_h
70
+ @_attributes.dup
71
+ end
72
+
73
+ def [](key)
74
+ get_attribute(key.to_sym)
75
+ end
76
+
77
+ def []=(key, value)
78
+ set_attribute(key.to_sym, value)
79
+ end
80
+
81
+ def assign_attributes(params)
82
+ params.each do |key, val|
83
+ public_send("#{key}=", val)
84
+ end
85
+ end
86
+
87
+ def respond_to_missing?(method_name, *args)
88
+ name, is_setter = parse_attribute_method_name(method_name)
89
+ attribute_method?(name, is_setter, *args)
90
+ end
91
+
92
+ def method_missing(method_name, *args, &block)
93
+ name, is_setter = parse_attribute_method_name(method_name)
94
+ if attribute_method?(name, is_setter, *args)
95
+ is_setter ? set_attribute(name, args.first) : get_attribute(name)
96
+ else
97
+ super
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,38 @@
1
+ require 'active_support/core_ext/class/attribute'
2
+ require 'active_support/concern'
3
+ require_relative '../connection'
4
+ require_relative '../configuration'
5
+
6
+ module ActiveHouse
7
+ module Modeling
8
+ module Connection
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ class_attribute :_connection_class, instance_accessor: false
13
+ class_attribute :_connection, instance_accessor: false
14
+ self._connection_class = ActiveHouse::Connection
15
+ end
16
+
17
+ class_methods do
18
+ def ensure_connection
19
+ establish_connection if _connection.nil?
20
+ end
21
+
22
+ def establish_connection(name_or_config = nil)
23
+ config = if name_or_config.is_a?(Hash)
24
+ name_or_config.symbolize_keys
25
+ else
26
+ ActiveHouse.configuration.connection_config_for(name_or_config)
27
+ end
28
+ self._connection = _connection_class.new(config)
29
+ end
30
+
31
+ def connection
32
+ ensure_connection
33
+ _connection
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,29 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/core_ext/module/delegation'
3
+
4
+ module ActiveHouse
5
+ module Modeling
6
+ module Query
7
+ extend ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ delegate :select,
11
+ :array_join,
12
+ :left_array_join,
13
+ :group_by,
14
+ :limit,
15
+ :order_by,
16
+ :having,
17
+ :from,
18
+ :union,
19
+ :where,
20
+ :where_not,
21
+ to: :all
22
+
23
+ def _query_builder
24
+ ::ActiveHouse::QueryBuilder.new(self)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,42 @@
1
+ require 'active_support/concern'
2
+
3
+ module ActiveHouse
4
+ module Modeling
5
+ module Scope
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute :_default_scope, instance_accessor: false
10
+ class_attribute :_scopes, instance_accessor: false
11
+ self._scopes = {}
12
+ end
13
+
14
+ class_methods do
15
+ def default_scope(name)
16
+ self._default_scope = name.to_sym
17
+ end
18
+
19
+ def scope(name, block)
20
+ self._scopes = _scopes.merge(name.to_sym => block)
21
+ end
22
+
23
+ def respond_to_missing?(method_name, *_args)
24
+ scope?(method_name) || super
25
+ end
26
+
27
+ def method_missing(method_name, *args, &_block)
28
+ if scope?(method_name)
29
+ scope = _scopes.fetch(method_name.to_sym)
30
+ all.instance_exec(*args, &scope)
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ def scope?(name)
37
+ _scopes.key?(name.to_sym)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -18,9 +18,9 @@ module ActiveHouse
18
18
  "'#{value.gsub("'", "\\'")}'"
19
19
  elsif value.is_a?(Time)
20
20
  if value.respond_to?(:zone)
21
- "toDateTime('#{value.strftime('%Y-%m-%d %H:%M:%S')}', '#{value.zone}')"
21
+ "toDateTime('#{value.strftime('%F %T')}', '#{value.zone}')"
22
22
  else
23
- "toDateTime('#{value.strftime('%Y-%m-%d %H:%M:%S')}')"
23
+ "toDateTime('#{value.strftime('%F %T')}')"
24
24
  end
25
25
  else
26
26
  value.to_s
@@ -33,5 +33,37 @@ module ActiveHouse
33
33
  parts.push('') if sql.end_with?('?')
34
34
  parts
35
35
  end
36
+
37
+ # @param condition [Hash]
38
+ def self.build_condition(condition)
39
+ return [condition.to_s] unless condition.is_a?(Hash)
40
+
41
+ condition.map do |field, value|
42
+ "#{field} #{sign_for_condition(value)} #{format_value(value)}"
43
+ end
44
+ end
45
+
46
+ def self.sign_for_condition(value)
47
+ if value.is_a?(Array)
48
+ 'IN'
49
+ elsif value.nil?
50
+ 'IS'
51
+ else
52
+ '='
53
+ end
54
+ end
55
+
56
+ def self.format_fields(model_class, fields)
57
+ raise ArgumentError, 'wrong number of arguments' if fields.empty?
58
+
59
+ fields.map do |field|
60
+ if field.is_a?(Symbol) && model_class._attribute_opts.key?(field)
61
+ opts = model_class._attribute_opts.fetch(field)
62
+ opts.key?(:select) ? "#{opts[:select]} AS #{field}" : field.to_s
63
+ else
64
+ field.to_s
65
+ end
66
+ end
67
+ end
36
68
  end
37
69
  end
@@ -0,0 +1,38 @@
1
+ require 'plain_model/querying/base'
2
+ require 'plain_model/querying/except'
3
+ require 'plain_model/querying/with_model'
4
+ require_relative 'querying/select'
5
+ require_relative 'querying/from'
6
+ require_relative 'querying/where'
7
+ require_relative 'querying/order_by'
8
+ require_relative 'querying/group_by'
9
+ require_relative 'querying/having'
10
+ require_relative 'querying/limit'
11
+ require_relative 'querying/union'
12
+ require_relative 'querying/array_join'
13
+ require_relative 'querying/scope'
14
+ require_relative 'querying/collect'
15
+
16
+ module ActiveHouse
17
+ class QueryBuilder
18
+ include PlainModel::Querying::Base
19
+ include PlainModel::Querying::Except
20
+ include PlainModel::Querying::WithModel
21
+
22
+ include ActiveHouse::Querying::Select
23
+ include ActiveHouse::Querying::From
24
+ include ActiveHouse::Querying::Where
25
+ include ActiveHouse::Querying::OrderBy
26
+ include ActiveHouse::Querying::GroupBy
27
+ include ActiveHouse::Querying::Having
28
+ include ActiveHouse::Querying::Limit
29
+ include ActiveHouse::Querying::Union
30
+ include ActiveHouse::Querying::ArrayJoin
31
+ include ActiveHouse::Querying::Scope
32
+ include ActiveHouse::Querying::Collect
33
+
34
+ def initialize(model_class = nil)
35
+ super(model_class || ActiveHouse::Model)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,42 @@
1
+ module ActiveHouse
2
+ module Querying
3
+ module ArrayJoin
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ private :build_array_join_query_part
8
+ end
9
+
10
+ def build_array_join_query_part
11
+ parts = []
12
+ parts << "ARRAY JOIN #{values[:array_join].join(', ')}" unless values[:array_join].empty?
13
+ parts << "LEFT ARRAY JOIN #{values[:array_join].join(', ')}" unless values[:left_array_join].empty?
14
+ parts.join("\n")
15
+ end
16
+
17
+ def initial_values
18
+ super.merge array_join: [], left_array_join: []
19
+ end
20
+
21
+ def array_join!(*fields)
22
+ formatted_fields = ActiveHouse::PreparedStatement.format_fields(model_class, fields)
23
+ values[:array_join] = (values[:array_join] + formatted_fields).uniq
24
+ self
25
+ end
26
+
27
+ def array_join(*fields)
28
+ dup.array_join!(*fields)
29
+ end
30
+
31
+ def left_array_join!(*fields)
32
+ formatted_fields = ActiveHouse::PreparedStatement.format_fields(model_class, fields)
33
+ values[:left_array_join] = (values[:left_array_join] + formatted_fields).uniq
34
+ self
35
+ end
36
+
37
+ def left_array_join(*fields)
38
+ dup.left_array_join!(*fields)
39
+ end
40
+ end
41
+ end
42
+ end