active_house 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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