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.
- checksums.yaml +4 -4
- data/.rubocop.yml +9 -0
- data/active_house.gemspec +1 -0
- data/lib/active_house.rb +1 -1
- data/lib/active_house/connection.rb +3 -3
- data/lib/active_house/exceptions.rb +9 -0
- data/lib/active_house/{logger.rb → logging.rb} +1 -1
- data/lib/active_house/model.rb +14 -12
- data/lib/active_house/modeling/attributes.rb +102 -0
- data/lib/active_house/modeling/connection.rb +38 -0
- data/lib/active_house/modeling/query.rb +29 -0
- data/lib/active_house/modeling/scope.rb +42 -0
- data/lib/active_house/prepared_statement.rb +34 -2
- data/lib/active_house/query_builder.rb +38 -0
- data/lib/active_house/querying/array_join.rb +42 -0
- data/lib/active_house/querying/collect.rb +80 -0
- data/lib/active_house/querying/from.rb +30 -0
- data/lib/active_house/querying/group_by.rb +30 -0
- data/lib/active_house/querying/having.rb +41 -0
- data/lib/active_house/querying/limit.rb +35 -0
- data/lib/active_house/querying/order_by.rb +58 -0
- data/lib/active_house/querying/scope.rb +45 -0
- data/lib/active_house/querying/select.rb +35 -0
- data/lib/active_house/querying/union.rb +67 -0
- data/lib/active_house/querying/where.rb +50 -0
- data/lib/active_house/version.rb +1 -1
- metadata +34 -22
- data/lib/active_house/array_joinable.rb +0 -31
- data/lib/active_house/chainable.rb +0 -151
- data/lib/active_house/collectable.rb +0 -44
- data/lib/active_house/connecting.rb +0 -36
- data/lib/active_house/connection_error.rb +0 -6
- data/lib/active_house/error.rb +0 -4
- data/lib/active_house/fromable.rb +0 -29
- data/lib/active_house/groupable.rb +0 -23
- data/lib/active_house/havingable.rb +0 -50
- data/lib/active_house/limitable.rb +0 -27
- data/lib/active_house/modeling.rb +0 -100
- data/lib/active_house/orderable.rb +0 -45
- data/lib/active_house/query.rb +0 -22
- data/lib/active_house/querying.rb +0 -21
- data/lib/active_house/scopeable.rb +0 -42
- data/lib/active_house/scoping.rb +0 -37
- data/lib/active_house/selectable.rb +0 -35
- data/lib/active_house/unionable.rb +0 -43
- data/lib/active_house/whereable.rb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 460006ab1e148781921648c680e33a79790e35cd
|
4
|
+
data.tar.gz: eb9ee437906deca34b1c6bb3bb172dc4bfcdab7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 190813fb7b150e48c7c75c1a53ef12e5dc589ab60b109cf65463644ba3e4c17dd0c94b6fd927e778811dd1e631c0163ec5e6ef7fa5b72425aa34fd68eaca89fc
|
7
|
+
data.tar.gz: 16fdecaf5792d2641aca7cd2b3e777d195894cbabe593b2ef1719ad16f83313fc547b3863829bcf764896b75b6721e77f90a08a420574f6d5ca46eb8d7c757f7
|
data/.rubocop.yml
CHANGED
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,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
|
data/lib/active_house/model.rb
CHANGED
@@ -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
|
-
|
12
|
-
include
|
13
|
-
include ActiveHouse::Modeling
|
14
|
-
include ActiveHouse::
|
15
|
-
include ActiveHouse::
|
16
|
-
include
|
17
|
-
|
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('%
|
21
|
+
"toDateTime('#{value.strftime('%F %T')}', '#{value.zone}')"
|
22
22
|
else
|
23
|
-
"toDateTime('#{value.strftime('%
|
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
|