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
@@ -1,27 +0,0 @@
1
- module ActiveHouse
2
- module Limitable
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- private
7
-
8
- def build_limit_query_part
9
- return if @limit[:limit].nil?
10
- if @limit[:offset]
11
- "LIMIT #{@limit[:limit]}, #{@limit[:offset]}"
12
- else
13
- "LIMIT #{@limit[:limit]}"
14
- end
15
- end
16
- end
17
-
18
- def initialize(*)
19
- @limit = { offset: nil, limit: nil }
20
- super
21
- end
22
-
23
- def limit(limit_value, offset_value = nil)
24
- chain_query limit: { offset: offset_value || @limit[:offset], limit: limit_value }
25
- end
26
- end
27
- end
@@ -1,100 +0,0 @@
1
- require 'active_support/concern'
2
-
3
- module ActiveHouse
4
- module Modeling
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- class_attribute :_attribute_opts, instance_writer: false
9
- self._attribute_opts = {}
10
-
11
- private
12
-
13
- def parse_attribute_method_name(method_name)
14
- name, is_setter = method_name.to_s.match(/\A(.+)?(=)?\z/).captures
15
- name = name.to_sym
16
- is_setter = !is_setter.nil?
17
- [name, is_setter]
18
- end
19
-
20
- def attribute_method?(name, is_setter, *args)
21
- (_attribute_opts.key?(name) || @_attributes.key?(name)) && (is_setter ? args.size == 1 : true)
22
- end
23
-
24
- def get_attribute(name)
25
- @_attributes[name]
26
- end
27
-
28
- def set_attribute(name, value)
29
- opts = _attribute_opts.fetch(name, {})
30
- value = opts[:cast].call(value) if opts[:cast]
31
- @_attributes[name] = value
32
- end
33
- end
34
-
35
- class_methods do
36
- def attribute(name, options = {})
37
- name = name.to_sym
38
- self._attribute_opts = _attribute_opts.merge(name => options)
39
- define_method(name) do
40
- get_attribute(name)
41
- end
42
- define_method("#{name}=") do |value|
43
- set_attribute(name, value)
44
- end
45
- end
46
-
47
- def attributes(*names)
48
- options = names.extract_options!
49
- names.each { |name| attribute(name, options.dup) }
50
- end
51
-
52
- def load!(params)
53
- new.tap do |model|
54
- params.each { |name, value| model[name] = value }
55
- end
56
- end
57
- end
58
-
59
- def initialize(params = {})
60
- @_attributes = {}
61
- assign_attributes(params) unless params.nil?
62
- end
63
-
64
- def as_json(*_args)
65
- to_h
66
- end
67
-
68
- def to_h
69
- @_attributes.dup
70
- end
71
-
72
- def [](key)
73
- get_attribute(key.to_sym)
74
- end
75
-
76
- def []=(key, value)
77
- set_attribute(key.to_sym, value)
78
- end
79
-
80
- def assign_attributes(params)
81
- params.each do |key, val|
82
- public_send("#{key}=", val)
83
- end
84
- end
85
-
86
- def respond_to_missing?(method_name, *args)
87
- name, is_setter = parse_attribute_method_name(method_name)
88
- attribute_method?(name, is_setter, *args)
89
- end
90
-
91
- def method_missing(method_name, *args, &block)
92
- name, is_setter = parse_attribute_method_name(method_name)
93
- if attribute_method?(name, is_setter, *args)
94
- is_setter ? set_attribute(name, args.first) : get_attribute(name)
95
- else
96
- super
97
- end
98
- end
99
- end
100
- end
@@ -1,45 +0,0 @@
1
- require 'active_support/core_ext/object/try'
2
-
3
- module ActiveHouse
4
- module Orderable
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- private
9
-
10
- def build_order_by_query_part
11
- "ORDER BY #{@ordering.join(', ')}" unless @ordering.empty?
12
- end
13
- end
14
-
15
- def initialize(*)
16
- @ordering = []
17
- super
18
- end
19
-
20
- def order_by(*clauses)
21
- raise ArgumentError, 'wrong number of arguments' if clauses.empty?
22
- formatter_clauses = clauses.map do |clause|
23
- if clause.is_a?(String)
24
- clause
25
- elsif clause.is_a?(Symbol)
26
- clause.to_s
27
- elsif clause.is_a?(Hash)
28
- if clause.keys.one?
29
- direction = clause.values.first
30
- raise ArgumentError, 'direction must be asc or desc' unless [:asc, :desc].include?(direction.try!(:to_sym))
31
- "#{clause.keys.first} #{direction.to_s.upcase}"
32
- else
33
- clause.assert_valid_keys(:field, :direction, :collate)
34
- [
35
- clause.fetch(:field),
36
- clause[:direction].try!(:to_s).try!(:upcase),
37
- clause.key?(:collate) ? "COLLATE '#{clause[:collate]}'" : nil
38
- ].reject(&:nil?).join(' ')
39
- end
40
- end
41
- end
42
- chain_query ordering: (@ordering + formatter_clauses).uniq
43
- end
44
- end
45
- end
@@ -1,22 +0,0 @@
1
- require_relative 'chainable'
2
- require_relative 'scopeable'
3
- require_relative 'collectable'
4
-
5
- module ActiveHouse
6
- class Query
7
- attr_reader :model_class
8
-
9
- def initialize(model_class = ActiveHouse::Model)
10
- @model_class = model_class
11
- super()
12
- end
13
-
14
- def connection
15
- model_class.connection
16
- end
17
-
18
- include ActiveHouse::Chainable
19
- include ActiveHouse::Collectable
20
- include ActiveHouse::Scopeable
21
- end
22
- end
@@ -1,21 +0,0 @@
1
- require 'active_support/concern'
2
- require 'active_support/core_ext/module/delegation'
3
-
4
- module ActiveHouse
5
- module Querying
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- class_attribute :_query_class, instance_accessor: false
10
- self._query_class = ActiveHouse::Query
11
- end
12
-
13
- class_methods do
14
- delegate :to_a, :select, :where, :group_by, :limit, :order_by, :having, :from, to: :all
15
-
16
- def all
17
- _query_class.new(self)
18
- end
19
- end
20
- end
21
- end
@@ -1,42 +0,0 @@
1
- require 'active_support/concern'
2
-
3
- module ActiveHouse
4
- module Scopeable
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- private
9
-
10
- def apply_scope(name, *args)
11
- scope = model_class._scopes.fetch(name.to_sym)
12
- instance_exec(*args, &scope)
13
- end
14
-
15
- def scope?(name)
16
- model_class._scopes.key?(name.to_sym)
17
- end
18
-
19
- def apply_default_scope
20
- return if model_class._default_scope.nil?
21
- apply_scope(model_class._default_scope)
22
- end
23
- end
24
-
25
- def initialize(*)
26
- super
27
- with_current_query { apply_default_scope }
28
- end
29
-
30
- def respond_to_missing?(method_name, *_args)
31
- scope?(method_name) || super
32
- end
33
-
34
- def method_missing(method_name, *args, &_block)
35
- if scope?(method_name)
36
- apply_scope(method_name, *args)
37
- else
38
- super
39
- end
40
- end
41
- end
42
- end
@@ -1,37 +0,0 @@
1
- require 'active_support/concern'
2
-
3
- module ActiveHouse
4
- module Scoping
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- class_attribute :_default_scope, instance_accessor: false
9
- class_attribute :_scopes, instance_accessor: false
10
- self._scopes = {}
11
- end
12
-
13
- class_methods do
14
- def default_scope(name)
15
- self._default_scope = name.to_sym
16
- end
17
-
18
- def scope(name, block)
19
- self._scopes = _scopes.merge(name.to_sym => block)
20
- end
21
-
22
- def respond_to_missing?(method_name, *_args)
23
- _scopes.key?(method_name.to_sym)
24
- end
25
-
26
- def method_missing(method_name, *args, &_block)
27
- method_name = method_name.to_sym
28
- if _scopes.key?(method_name)
29
- scope = _scopes.fetch(method_name)
30
- all.instance_exec(*args, &scope)
31
- else
32
- super
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,35 +0,0 @@
1
- module ActiveHouse
2
- module Selectable
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- private
7
-
8
- def build_select_query_part
9
- if !@fields.empty?
10
- "SELECT\n#{@fields.join(",\n")}"
11
- else
12
- 'SELECT *'
13
- end
14
- end
15
- end
16
-
17
- def initialize(*)
18
- @fields = []
19
- super
20
- end
21
-
22
- def select(*fields)
23
- raise ArgumentError, 'wrong number of arguments' if fields.empty?
24
- formatted_fields = fields.map do |field|
25
- if field.is_a?(Symbol) && model_class._attribute_opts.key?(field)
26
- opts = model_class._attribute_opts.fetch(field)
27
- opts.key?(:select) ? "#{opts[:select]} AS #{field}" : field.to_s
28
- else
29
- field.to_s
30
- end
31
- end
32
- chain_query fields: (@fields + formatted_fields).uniq
33
- end
34
- end
35
- end
@@ -1,43 +0,0 @@
1
- module ActiveHouse
2
- module Unionable
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- private
7
-
8
- def build_union_query_part
9
- "UNION ALL\n#{@unions.values.map(&:to_query).join("\n")}" unless @unions.values.empty?
10
- end
11
- end
12
-
13
- def initialize(*)
14
- @unions = {}
15
- super
16
- end
17
-
18
- def union(name, query)
19
- query = query.all if query.is_a?(ActiveHouse::Model)
20
- raise ArgumentError, 'argument must be model or query object' unless query.is_a?(ActiveHouse::Query)
21
- new_unions = @unions.map { |n, q| [n, q.dup] }.to_h
22
- new_unions[name] = query.dup
23
- chain_query unions: new_unions
24
- end
25
-
26
- def update_union(name)
27
- raise ArgumentError, "can't find union by name #{name}" unless @unions.key?(name)
28
- new_union = yield union_for(name)
29
- union(name, new_union)
30
- end
31
-
32
- def union_for(name)
33
- raise ArgumentError, "can't find union by name #{name}" unless @unions.key?(name)
34
- @unions[name].dup
35
- end
36
-
37
- def except_union(name)
38
- new_unions = @unions.map { |n, q| [n, q.dup] }.to_h
39
- new_unions.delete(name)
40
- chain_query unions: new_unions
41
- end
42
- end
43
- end
@@ -1,57 +0,0 @@
1
- require_relative 'prepared_statement'
2
- require 'active_support/core_ext/array/wrap'
3
-
4
- module ActiveHouse
5
- module Whereable
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- private
10
-
11
- def format_condition(*conditions)
12
- raise ArgumentError, 'wrong number of arguments' if conditions.empty?
13
- return ActiveHouse::PreparedStatement.prepare_sql(*conditions) if conditions.size > 1
14
- condition = conditions.first
15
- if condition.is_a?(Hash)
16
- condition.map do |field, value|
17
- "#{field} #{sign_for_condition(value)} #{ActiveHouse::PreparedStatement.format_value(value)}"
18
- end
19
- else
20
- condition.to_s
21
- end
22
- end
23
-
24
- def sign_for_condition(value)
25
- if value.is_a?(Array)
26
- 'IN'
27
- elsif value.nil?
28
- 'IS'
29
- else
30
- '='
31
- end
32
- end
33
-
34
- def build_where_query_part
35
- "WHERE\n" + @conditions.join(" AND\n") unless @conditions.empty?
36
- end
37
- end
38
-
39
- def initialize(*)
40
- @conditions = []
41
- super
42
- end
43
-
44
- def where(*conditions)
45
- raise ArgumentError, 'wrong number of arguments' if conditions.empty?
46
- formatted_conditions = Array.wrap(format_condition(*conditions))
47
- chain_query conditions: (@conditions + formatted_conditions).uniq
48
- end
49
-
50
- def where_not(*conditions)
51
- raise ArgumentError, 'wrong number of arguments' if conditions.empty?
52
- formatted_conditions = Array.wrap(format_condition(*conditions))
53
- negative_condition = "NOT (#{formatted_conditions.join(' AND ')})"
54
- chain_query conditions: (@conditions + [negative_condition]).uniq
55
- end
56
- end
57
- end