wallaby-active_record 0.2.2 → 0.2.7

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 (23) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/lib/adapters/wallaby/active_record/cancancan_provider.rb +1 -1
  4. data/lib/adapters/wallaby/active_record/default_provider.rb +1 -1
  5. data/lib/adapters/wallaby/active_record/model_decorator/fields_builder/association_builder.rb +6 -4
  6. data/lib/adapters/wallaby/active_record/model_decorator/fields_builder/polymorphic_builder.rb +3 -2
  7. data/lib/adapters/wallaby/active_record/model_decorator/fields_builder/sti_builder.rb +17 -13
  8. data/lib/adapters/wallaby/active_record/model_decorator/fields_builder.rb +3 -2
  9. data/lib/adapters/wallaby/active_record/model_decorator/title_field_finder.rb +6 -9
  10. data/lib/adapters/wallaby/active_record/model_decorator.rb +28 -26
  11. data/lib/adapters/wallaby/active_record/model_finder.rb +23 -25
  12. data/lib/adapters/wallaby/active_record/model_pagination_provider.rb +5 -13
  13. data/lib/adapters/wallaby/active_record/model_service_provider/permitter.rb +1 -1
  14. data/lib/adapters/wallaby/active_record/model_service_provider/querier/escaper.rb +14 -0
  15. data/lib/adapters/wallaby/active_record/model_service_provider/querier/transformer.rb +45 -13
  16. data/lib/adapters/wallaby/active_record/model_service_provider/querier/wrapper.rb +8 -6
  17. data/lib/adapters/wallaby/active_record/model_service_provider/querier.rb +3 -3
  18. data/lib/adapters/wallaby/active_record/model_service_provider/validator.rb +6 -4
  19. data/lib/adapters/wallaby/active_record/model_service_provider.rb +8 -17
  20. data/lib/adapters/wallaby/active_record/pundit_provider.rb +2 -2
  21. data/lib/adapters/wallaby/active_record.rb +2 -1
  22. data/lib/wallaby/active_record/version.rb +1 -1
  23. metadata +8 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 93579d0cc4c2a81356d19acc3a24a7cac7160406f4c09c829de95f10d3db1020
4
- data.tar.gz: d591a516f5c2fc04d7b6f46af992498e093d5d3f706d03c639a77a11eeeba339
3
+ metadata.gz: 55cc61191c3d68eabf0bb98b4977d10c7d5063736e95cba4b4cb446bf1ecebb7
4
+ data.tar.gz: 8d03e8a115f52bd386e87bd6ba2a8a95fdec39743a1a040396f8f1b06ac1c0fe
5
5
  SHA512:
6
- metadata.gz: 9197ae20142ea0190ed68314ef6eb5c7ec4915febe072f62f0144bb6f42dddbada38adadf05b83eba0ed9744d2c3bc050f2836b25a46c394ab553decaa4f0dee
7
- data.tar.gz: 0a59dcd809acb177822b3665b576b18eefdb0ef55b4fdcfdc6a3cf9344ce73fa1ddc4cb608c47de4d630b6149d0f1a36569eee8c63253830ddad92aae3c3f514
6
+ metadata.gz: '0685f26c6acf1c511be09cfe68258bce7ca3cd01263047205fcdbfc2e81da7ca1239af3f0725510401d02f6a2c2629003e79a41760a8e672acaa710cd566d8db'
7
+ data.tar.gz: fa1497666790dba1d421f1194ce3e3ffc4851e3425a7a2da5701af9f5d4573d1df9bbf3a9ee656aa3490f81ed363af4a6758121d6c3cbd761f3d52707f84f6bb
data/README.md CHANGED
@@ -7,7 +7,8 @@
7
7
  [![Test Coverage](https://api.codeclimate.com/v1/badges/9ba0a610043a2e1a9e74/test_coverage)](https://codeclimate.com/github/wallaby-rails/wallaby-active_record/test_coverage)
8
8
  [![Inch CI](https://inch-ci.org/github/wallaby-rails/wallaby-active_record.svg?branch=master)](https://inch-ci.org/github/wallaby-rails/wallaby-active_record)
9
9
 
10
- Wallaby::ActiveRecord is the ActiveRecord adapter for [Wallaby::Core](https://github.com/wallaby-rails/wallaby-core).
10
+ Wallaby::ActiveRecord is the ActiveRecord adapter that implements the [Wallaby::Core](https://github.com/wallaby-rails/wallaby-core)
11
+ interfaces to handle ActiveRecord model/instance(s) in all the CRUD/authorization/pagination operations.
11
12
 
12
13
  ## Install
13
14
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Wallaby
4
4
  class ActiveRecord
5
- # Cancancan provider for ActiveRecord
5
+ # Cancancan provider for {Wallaby::ActiveRecord}
6
6
  class CancancanProvider < CancancanAuthorizationProvider
7
7
  end
8
8
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Wallaby
4
4
  class ActiveRecord
5
- # Default provider for ActiveRecord
5
+ # Default provider for {Wallaby::ActiveRecord}
6
6
  class DefaultProvider < DefaultAuthorizationProvider
7
7
  end
8
8
  end
@@ -4,7 +4,7 @@ module Wallaby
4
4
  class ActiveRecord
5
5
  class ModelDecorator
6
6
  class FieldsBuilder
7
- # To build the metadata for associations
7
+ # To build the metadata for associations fields
8
8
  class AssociationBuilder
9
9
  # Update the metadata
10
10
  # @param metadata [Hash]
@@ -18,7 +18,7 @@ module Wallaby
18
18
  metadata[:foreign_key] = foreign_key_for(reflection, type)
19
19
  end
20
20
 
21
- private
21
+ protected
22
22
 
23
23
  # @param reflection [ActiveRecord::Reflection]
24
24
  # @param type [Symbol]
@@ -35,13 +35,15 @@ module Wallaby
35
35
  end
36
36
 
37
37
  # @param reflection [ActiveRecord::Reflection]
38
- # @return [Boolean] whether it's a through relation
38
+ # @return [true] if it's a through relation
39
+ # @return [false] otherwise
39
40
  def through?(reflection)
40
41
  reflection.is_a? ::ActiveRecord::Reflection::ThroughReflection
41
42
  end
42
43
 
43
44
  # @param reflection [ActiveRecord::Reflection]
44
- # @return [Boolean] whether it has scope
45
+ # @return [true] if it has scope
46
+ # @return [false] otherwise
45
47
  def scope?(reflection)
46
48
  reflection.scope.present?
47
49
  end
@@ -19,7 +19,7 @@ module Wallaby
19
19
  end
20
20
  end
21
21
 
22
- private
22
+ protected
23
23
 
24
24
  # @param reflection [ActiveRecord::Reflection]
25
25
  # @return [Array<Class>] a list of classes for this polymorphism
@@ -38,7 +38,8 @@ module Wallaby
38
38
 
39
39
  # @param model_class [Class]
40
40
  # @param polymorphic_name [String] polymorphic name
41
- # @return [Boolean] if polymorphism defined?
41
+ # @return [true] if polymorphism defined?
42
+ # @return [false] otherwise
42
43
  def polymorphic_defined?(model_class, polymorphic_name)
43
44
  polymorphic_name_sym = polymorphic_name.try(:to_sym)
44
45
  model_class.reflections.any? do |_field_name, reflection|
@@ -4,44 +4,48 @@ module Wallaby
4
4
  class ActiveRecord
5
5
  class ModelDecorator
6
6
  class FieldsBuilder
7
- # To build the metadata for sti column
7
+ # This class updates the field metadata's value of **type** and **sti_class_list**
8
+ # for STI (Single Table Inheritance) model
8
9
  class StiBuilder
9
10
  # @param model_class [Class]
10
11
  def initialize(model_class)
11
12
  @model_class = model_class
12
13
  end
13
14
 
14
- # update the metadata
15
+ # Update the field metadata's value for **type** and **sti_class_list**
15
16
  # @param metadata [Hash]
16
17
  # @param column [ActiveRecord::ConnectionAdapters::Column]
17
18
  def update(metadata, column)
18
19
  return unless @model_class.inheritance_column == column.name
19
20
 
20
21
  metadata[:type] = 'sti'
21
- metadata[:sti_class_list] = sti_list(find_parent_of(@model_class))
22
+ metadata[:sti_class_list] = sti_list(find_sti_parent_of(@model_class))
22
23
  end
23
24
 
24
- private
25
+ protected
25
26
 
27
+ # Return the alphabet-order STI list
28
+ # by traversing the inheritance tree for given model.
26
29
  # @param klass [Class]
27
- # @return [Array<Class>] a list of STI classes for this model
30
+ # @return [Array<Class>]
28
31
  def sti_list(klass)
29
- list = klass.descendants << klass
30
- list.sort_by(&:name)
32
+ (klass.descendants << klass).sort_by(&:name)
31
33
  end
32
34
 
35
+ # Find out which parent is the one that can give us the STI list.
33
36
  # @param klass [Class]
34
- # @return [Class] the top parent class in the STI hierarchy
35
- def find_parent_of(klass)
37
+ # @return [Class]
38
+ def find_sti_parent_of(klass)
36
39
  parent = klass
37
- parent = parent.superclass until top_parent?(parent.superclass)
40
+ parent = parent.superclass until not_sti_parent?(parent.superclass)
38
41
  parent
39
42
  end
40
43
 
41
44
  # @param klass [Class]
42
- # @return [Boolean] whether the class is ActiveRecord base class
43
- def top_parent?(klass)
44
- klass == ModelFinder.base || klass.try(:abstract_class?)
45
+ # @return [true] if klass is ActiveRecord::Base or abstract
46
+ # @return [false] otherwise
47
+ def not_sti_parent?(klass)
48
+ klass == ::ActiveRecord::Base || klass.try(:abstract_class?)
45
49
  end
46
50
  end
47
51
  end
@@ -3,7 +3,7 @@
3
3
  module Wallaby
4
4
  class ActiveRecord
5
5
  class ModelDecorator
6
- # To search and build the metadata for fields
6
+ # To build the metadata for fields
7
7
  class FieldsBuilder
8
8
  # @param model_class [Class]
9
9
  def initialize(model_class)
@@ -22,7 +22,8 @@ module Wallaby
22
22
  end
23
23
  end
24
24
 
25
- # @return [Hash<String, Hash>] a hash for general fields
25
+ # @return [Hash<String, Hash>] a hash for association fields
26
+ # (e.g. belongs_to / has_one / has_many / has_and_belongs_to_many)
26
27
  def association_fields
27
28
  @model_class.reflections.each_with_object({}) do |(name, ref), fields|
28
29
  metadata = {
@@ -16,15 +16,12 @@ module Wallaby
16
16
 
17
17
  # @return [String] field name that can be used as title
18
18
  def find
19
- possible_title_fields = @fields.select do |_field_name, metadata|
20
- TITLE_FIELD_TYPES.include? metadata[:type]
21
- end
22
- target_field = possible_title_fields.keys.find do |field_name|
23
- TITLE_NAMES.any? { |v| field_name.to_s.index v }
24
- end
25
- target_field \
26
- || possible_title_fields.keys.first \
27
- || @model_class.primary_key
19
+ FieldUtils.first_field_by(
20
+ {
21
+ name: /title|name|label|string/,
22
+ type: 'string'
23
+ }, @fields
24
+ ) || @model_class.primary_key
28
25
  end
29
26
  end
30
27
  end
@@ -2,24 +2,25 @@
2
2
 
3
3
  module Wallaby
4
4
  class ActiveRecord
5
- # Modal decorator for ActiveRecord
5
+ # Modal decorator for {Wallaby::ActiveRecord}
6
6
  class ModelDecorator < ::Wallaby::ModelDecorator
7
- # Data types to exclude for index page
8
- INDEX_EXCLUSIVE_DATA_TYPES =
9
- (['', 'medium', 'long'] * 2)
10
- .zip(%w(blob text) * 3).map(&:join)
11
- .concat(%w(binary citext hstore json jsonb tsvector xml)).freeze
7
+ # Data types to exclude for {#index_field_names}
8
+ INDEX_EXCLUSIVE_DATA_TYPES = %w(
9
+ binary citext hstore json jsonb tsvector xml
10
+ blob mediumblob longblob text mediumtext longtext
11
+ ).freeze
12
12
 
13
- # Class to exclude for show page
13
+ # Classes to exclude for {#show_field_names}
14
14
  SHOW_EXCLUSIVE_CLASS_NAMES = %w(ActiveStorage::Attachment ActiveStorage::Blob).freeze
15
15
 
16
- # Data types to exclude for form page
16
+ # Fields to exclude for {#form_field_names}
17
17
  FORM_EXCLUSIVE_DATA_TYPES = %w(created_at updated_at).freeze
18
18
 
19
- # Origin metadata directly coming from ActiveRecord.
19
+ # Original metadata information of the primative and association fields
20
+ # pulling out from the ActiveRecord model.
20
21
  #
21
- # It needs to be frozen so that we can keep the metadata integrity
22
- # @example sample fields:
22
+ # It needs to be frozen so that we can keep the metadata intact.
23
+ # @example sample fields metadata:
23
24
  # model_decorator.fields
24
25
  # # =>
25
26
  # {
@@ -27,28 +28,29 @@ module Wallaby
27
28
  # id: { name: 'id', type: 'integer', label: 'Id' },
28
29
  # # association field
29
30
  # category: {
30
- # 'name' => 'category',
31
- # 'type' => 'belongs_to',
32
- # 'label' => 'Category',
33
- # 'is_association' => true,
34
- # 'is_through' => false,
35
- # 'has_scope' => false,
36
- # 'foreign_key' => 'category_id',
37
- # 'class' => Category
31
+ # name: 'category',
32
+ # type: 'belongs_to',
33
+ # label: 'Category',
34
+ # is_association: true,
35
+ # is_through: false,
36
+ # has_scope: false,
37
+ # foreign_key: 'category_id',
38
+ # class: Category
38
39
  # }
39
40
  # }
40
41
  # @return [ActiveSupport::HashWithIndifferentAccess] metadata
41
42
  def fields
43
+ # NOTE: Need to check the database and table's existence before building up the metadata
44
+ # so that the database creation and migration related task can be executed.
42
45
  @fields ||= ::ActiveSupport::HashWithIndifferentAccess.new.tap do |hash|
43
- # NOTE: Need to check database and table's existence
44
- # before pulling out the metadata from model.
45
- # So that the database and migration related task can be executed.
46
- next unless ::ActiveRecord::Base.connected? && @model_class.table_exists?
46
+ next hash.default = {} unless @model_class.table_exists?
47
47
 
48
48
  hash.merge! general_fields
49
49
  hash.merge! association_fields
50
50
  hash.except!(*foreign_keys_from_associations)
51
51
  end.freeze
52
+ rescue ::ActiveRecord::NoDatabaseError
53
+ Hash.new({}).with_indifferent_access
52
54
  end
53
55
 
54
56
  # A copy of {#fields} for index page
@@ -86,7 +88,8 @@ module Wallaby
86
88
  end.keys
87
89
  end
88
90
 
89
- # @return [Array<String>] a list of field names for form (new/edit) page (note: complex fields are excluded).
91
+ # @return [Array<String>] a list of field names for form (new/edit) page
92
+ # (note: timestamps fields (e.g. created_at/updated_at) and complex relation fields are excluded).
90
93
  def form_field_names
91
94
  @form_field_names ||=
92
95
  form_fields.reject do |field_name, metadata|
@@ -109,9 +112,8 @@ module Wallaby
109
112
  # To guess the title for resource.
110
113
  #
111
114
  # It will go through the fields and try to find out the one that looks
112
- # like a name or text to represent this resource. Otherwise, it will fall
115
+ # like a name or text representing this resource. Otherwise, it will fall
113
116
  # back to primary key.
114
- #
115
117
  # @param resource [Object]
116
118
  # @return [String] the title of given resource
117
119
  def guess_title(resource)
@@ -2,43 +2,41 @@
2
2
 
3
3
  module Wallaby
4
4
  class ActiveRecord
5
- # Model finder
5
+ # Finder to return all the appropriate ActiveRecord models.
6
6
  class ModelFinder < ::Wallaby::ModelFinder
7
- # @return [Array<Class>] a list of ActiveRecord subclasses
7
+ # Return a list of ActiveRecord::Base subclasses that aren't one of the following types:
8
+ #
9
+ # 1. abstract class
10
+ # 2. anonymous class
11
+ # 3. the HABTM relation class
12
+ # @return [Array<Class>]
8
13
  def all
9
- self.class.base.descendants.reject do |model_class|
10
- abstract?(model_class) || anonymous?(model_class) || habtm?(model_class)
14
+ ::ActiveRecord::Base.descendants.reject do |model_class|
15
+ defined?(::ApplicationRecord) && model_class == ::ApplicationRecord ||
16
+ model_class.abstract_class? ||
17
+ anonymous?(model_class) ||
18
+ model_class.name.index('HABTM') ||
19
+ invalid_class_name?(model_class)
11
20
  end.sort_by(&:to_s)
12
21
  end
13
22
 
14
- # This is only for ActiveRecord
15
- # @return [ApplicationRecord, ActiveRecord::Base] base ActiveRecord class
16
- def self.base
17
- return ::ApplicationRecord if defined? ::ApplicationRecord
23
+ protected
18
24
 
19
- ::ActiveRecord::Base
20
- end
21
-
22
- private
23
-
24
- # Is model class abstract?
25
25
  # @param model_class [Class]
26
- # @return [Boolean]
27
- def abstract?(model_class)
28
- model_class.abstract_class?
29
- end
30
-
31
26
  # @see Wallaby::ModuleUtils.anonymous_class?
32
27
  def anonymous?(model_class)
33
- ModuleUtils.anonymous_class? model_class
28
+ ModuleUtils.anonymous_class?(model_class).tap do |result|
29
+ Logger.warn "Anonymous class is detected for table #{model_class.try :table_name}" if result
30
+ end
34
31
  end
35
32
 
36
- # Check and see if given model class is intermediate class that generated
37
- # for has and belongs to many assocation
33
+ # To exclude classes that have invalid class name, e.g. **primary::SchemaMigration** from Rails test
38
34
  # @param model_class [Class]
39
- # @return [Boolean]
40
- def habtm?(model_class)
41
- model_class.name.index('HABTM')
35
+ def invalid_class_name?(model_class)
36
+ model_class.name.constantize
37
+ false
38
+ rescue NameError
39
+ true
42
40
  end
43
41
  end
44
42
  end
@@ -8,25 +8,17 @@ module Wallaby
8
8
  # @return [true] if paginatable
9
9
  # @return [false] if not paginatable
10
10
  def paginatable?
11
- paginatable =
12
- # kaminari
13
- @collection.respond_to?(:total_count) || \
14
- @collection.respond_to?(:total_entries) # will_paginate
15
- Rails.logger.warn "#{@collection.inspect} is not paginatable.\nfrom #{__FILE__}:#{__LINE__}" unless paginatable
16
-
17
- paginatable
11
+ (@collection.respond_to?(:unscope) && @collection.respond_to?(:count)).tap do |paginatable|
12
+ Logger.warn "#{@collection} is not paginatable." unless paginatable
13
+ end
18
14
  end
19
15
 
20
16
  # @return [Integer] total count for the collection
21
17
  def total
22
- # kaminari
23
- @collection.try(:total_count) || \
24
- @collection.try(:total_entries) # will_paginate
18
+ @collection.unscope(:offset, :limit).count
25
19
  end
26
20
 
27
- # @return [Integer] page size from parameters or
28
- # {https://rubydoc.info/gems/wallaby-core/Wallaby/Configuration/Pagination#page_size-instance_method page_size}
29
- # Wallaby configuration
21
+ # @return [Integer] page size from parameters or Wallaby configuration
30
22
  def page_size
31
23
  (@params[:per] || Wallaby.configuration.pagination.page_size).to_i
32
24
  end
@@ -3,7 +3,7 @@
3
3
  module Wallaby
4
4
  class ActiveRecord
5
5
  class ModelServiceProvider
6
- # Filter the params
6
+ # Whitelist the params for mass-assignment
7
7
  class Permitter
8
8
  # @param model_decorator [Wallaby::ModelDecorator]
9
9
  def initialize(model_decorator)
@@ -11,6 +11,14 @@ module Wallaby
11
11
  PCT = '%' # :nodoc:
12
12
 
13
13
  class << self
14
+ # @example Return the escaped keyword if the first/last char of the keyword is `%`/`_`
15
+ # Wallaby::ActiveRecord::ModelServiceProvider::Querier::Escaper.execute('%something_else%')
16
+ # # => '%something\_else%'
17
+ # @example Return the escaped keyword wrapped with `%` if the first/last char of the keyword is NOT `%`/`_`
18
+ # Wallaby::ActiveRecord::ModelServiceProvider::Querier::Escaper.execute('keyword')
19
+ # # => '%keyword%'
20
+ # @param keyword [String]
21
+ # @return [String] escaped string for LIKE query
14
22
  def execute(keyword)
15
23
  first = keyword.first
16
24
  last = keyword.last
@@ -23,6 +31,12 @@ module Wallaby
23
31
  "#{starting}#{escaped}#{ending}"
24
32
  end
25
33
 
34
+ protected
35
+
36
+ # @param first_condition [Boolean] first condition
37
+ # @param first_char [Boolean] first char
38
+ # @param second_condition [nil, String] second condition
39
+ # @param default_sign [String]
26
40
  def sign(
27
41
  first_condition, first_char, second_condition, default_sign = PCT
28
42
  )
@@ -34,9 +34,21 @@ module Wallaby
34
34
  ':!()' => :not_between
35
35
  }.freeze
36
36
 
37
+ SEQUENCE_JOIN_OPERATORS = { # :nodoc:
38
+ ':' => :or,
39
+ ':=' => :or,
40
+ ':!' => :and,
41
+ ':!=' => :and,
42
+ ':<>' => :and
43
+ }.freeze
44
+
45
+ BETWEEN_OPERATORS = { # :nodoc:
46
+ ':()' => true,
47
+ ':!()' => true
48
+ }.freeze
49
+
37
50
  # For single null
38
51
  rule null: simple(:value)
39
- rule null: sequence(:value)
40
52
 
41
53
  # For single boolean
42
54
  rule(boolean: simple(:value)) { /true/i.match? value }
@@ -51,8 +63,7 @@ module Wallaby
51
63
  rule left: simple(:left), op: simple(:op), right: simple(:right) do
52
64
  oped = op.try :to_str
53
65
  operator = SIMPLE_OPERATORS[oped]
54
- # skip if the operator is unknown
55
- next unless operator
66
+ next Transformer.warn "Unknown operator #{oped} for %<exp>s", instance_values unless operator
56
67
 
57
68
  lefted = left.try :to_str
58
69
  convert =
@@ -68,24 +79,45 @@ module Wallaby
68
79
  rule left: simple(:left), op: simple(:op), right: sequence(:right) do
69
80
  oped = op.try :to_str
70
81
  operator = SEQUENCE_OPERATORS[oped]
71
- next unless operator
82
+ next Transformer.warn "Unknown operator #{oped} for %<exp>s", instance_values unless operator
72
83
 
73
84
  exps = Wrapper.new
74
85
  lefted = left.try :to_str
75
- if right.include? nil
76
- nil_operator = SIMPLE_OPERATORS[oped]
77
- next unless nil_operator
86
+ if BETWEEN_OPERATORS[oped] # BETWEEN related operators
87
+ next Transformer.warn 'Invalid values for %<exp>s', instance_values unless right.first && right.second
78
88
 
79
- exps.push left: lefted, op: nil_operator, right: right.delete(nil)
89
+ convert = Range.new right.first, right.second
90
+ exps.push left: lefted, op: operator, right: convert
91
+ else
92
+ join = SEQUENCE_JOIN_OPERATORS[oped]
93
+ if right.include? nil
94
+ exps.push left: lefted, op: SIMPLE_OPERATORS[oped], right: right.delete(nil), join: join
95
+ end
96
+ exps.push left: lefted, op: operator, right: right, join: join
80
97
  end
81
- convert = Range.new right.try(:first), right.try(:second) if %w(:() :!()).include?(oped)
82
- exps.push left: lefted, op: operator, right: convert || right
83
98
  exps
84
99
  end
85
100
 
86
- def transform(query_string)
87
- result = apply Parser.new.parse(query_string || EMPTY_STRING)
88
- result.is_a?(Array) ? result : [result]
101
+ class << self
102
+ # @param query_string [String]
103
+ # @return [Array]
104
+ def execute(query_string)
105
+ result = new.apply Parser.new.parse(query_string || EMPTY_STRING)
106
+ result.is_a?(Array) ? result : [result]
107
+ end
108
+
109
+ # @param message [String]
110
+ # @param exp [Hash,nil] transformed expression
111
+ # @return [nil]
112
+ def warn(message, exp = nil)
113
+ Logger.warn message, exp: to_origin(exp), sourcing: 2
114
+ end
115
+
116
+ # @param exp [Hash,nil] transformed expression
117
+ # @return [String] origin expression
118
+ def to_origin(exp)
119
+ "'#{exp['left']}#{exp['op']}#{exp['right']}'"
120
+ end
89
121
  end
90
122
  end
91
123
  end
@@ -4,18 +4,20 @@ module Wallaby
4
4
  class ActiveRecord
5
5
  class ModelServiceProvider
6
6
  class Querier
7
- # Build up query using the results
7
+ # Wrapper for the {Wallaby::ActiveRecord::ModelServiceProvider::Querier::Transformer} result.
8
+ # It's only used by {Wallaby::ActiveRecord::ModelServiceProvider::Querier} to tell it apart
9
+ # with non-{Wallaby::ActiveRecord::ModelServiceProvider::Querier::Transformer} result
8
10
  class Wrapper
9
11
  attr_reader :list
10
- delegate :push, :each, to: :list
12
+ delegate :push, to: :list
13
+ delegate :each, to: :list
14
+ delegate :last, to: :list
15
+ delegate :[], to: :last
11
16
 
17
+ # @param list [Array]
12
18
  def initialize(list = [])
13
19
  @list = list
14
20
  end
15
-
16
- def [](key)
17
- list.last[key]
18
- end
19
21
  end
20
22
  end
21
23
  end
@@ -26,7 +26,7 @@ module Wallaby
26
26
  scope.where query
27
27
  end
28
28
 
29
- private
29
+ protected
30
30
 
31
31
  # @return [Arel::Table] arel table
32
32
  def table
@@ -36,7 +36,7 @@ module Wallaby
36
36
  # @param params [ActionController::Parameters]
37
37
  # @return [Array<String, Array, Array>] filter_name, keywords, field_queries
38
38
  def extract(params)
39
- expressions = Transformer.new.transform params[:q]
39
+ expressions = Transformer.execute params[:q]
40
40
  keywords = expressions.select { |v| v.is_a? String }
41
41
  field_queries = expressions.select { |v| v.is_a? Wrapper }
42
42
  filter_name = params[:filter]
@@ -149,7 +149,7 @@ module Wallaby
149
149
  query = nil
150
150
  exps.each do |exp|
151
151
  sub = table[exp[:left]].try(exp[:op], exp[:right])
152
- query = query.try(:or, sub) || sub
152
+ query = query.try(exp[:join], sub) || sub
153
153
  end
154
154
  query
155
155
  end
@@ -3,7 +3,7 @@
3
3
  module Wallaby
4
4
  class ActiveRecord
5
5
  class ModelServiceProvider
6
- # Validator
6
+ # Validate values for record create / update
7
7
  class Validator
8
8
  # @param model_decorator [Wallaby::ModelDecorator]
9
9
  def initialize(model_decorator)
@@ -11,7 +11,8 @@ module Wallaby
11
11
  end
12
12
 
13
13
  # @param resource [Object] resource object
14
- # @return [Boolean] whether the resource object is valid
14
+ # @return [true] if the resource object is valid
15
+ # @return [false] otherwise
15
16
  def valid?(resource)
16
17
  resource.attributes.each do |field_name, values|
17
18
  metadata = @model_decorator.fields[field_name]
@@ -22,10 +23,11 @@ module Wallaby
22
23
  resource.errors.blank?
23
24
  end
24
25
 
25
- private
26
+ protected
26
27
 
27
28
  # @param values [Array]
28
- # @return [Boolean] whether the values are valid range values
29
+ # @return [true] if the values are valid range values
30
+ # @return [false] otherwise
29
31
  def valid_range_type?(values, metadata)
30
32
  !metadata \
31
33
  || !%w(daterange tsrange tstzrange).include?(metadata[:type]) \
@@ -8,7 +8,6 @@ module Wallaby
8
8
  # @param action [String, Symbol]
9
9
  # @param authorizer
10
10
  # @return [ActionController::Parameters] whitelisted parameters
11
- # @see Wallaby::ModelServiceProvider#permit
12
11
  def permit(params, action, authorizer)
13
12
  authorized_fields = authorizer.permit_params action, @model_class
14
13
  params.require(param_key).permit(authorized_fields || permitted_fields)
@@ -18,7 +17,6 @@ module Wallaby
18
17
  # @param params [ActionController::Parameters]
19
18
  # @param authorizer [Ability] for now
20
19
  # @return [ActiveRecord::Relation] relation
21
- # @see Wallaby::ModelServiceProvider#collection
22
20
  def collection(params, authorizer)
23
21
  query = querier.search params
24
22
  query = query.order params[:sort] if params[:sort].present?
@@ -28,19 +26,15 @@ module Wallaby
28
26
  # @param query [ActiveRecord::Relation]
29
27
  # @param params [ActionController::Parameters]
30
28
  # @return [ActiveRecord::Relation] paginated query
31
- # @see Wallaby::ModelServiceProvider#paginate
32
29
  def paginate(query, params)
33
- # NOTE: do not take out the `.to_i` as will_paginate requires an integer `per_page`
34
30
  per = (params[:per] || Wallaby.configuration.pagination.page_size).to_i
35
- query = query.page params[:page] if query.respond_to? :page
36
- query = query.per per if query.respond_to? :per # kaminari
37
- query = query.per_page per if query.respond_to? :per_page # will_paginate
31
+ page = [params[:page].to_i, 1].max # starting from page 1
32
+ query = query.offset((page - 1) * per).limit(per)
38
33
  query
39
34
  end
40
35
 
41
36
  # @note No mass assignment happens here!
42
37
  # @return [Object] new resource object
43
- # @see Wallaby::ModelServiceProvider#new
44
38
  def new(_params, _authorizer)
45
39
  @model_class.new
46
40
  end
@@ -50,7 +44,6 @@ module Wallaby
50
44
  # @param id [Integer, String]
51
45
  # @return [Object] persisted resource object
52
46
  # @raise [Wallaby::ResourceNotFound] when record is not found
53
- # @see Wallaby::ModelServiceProvider#find
54
47
  def find(id, _params, _authorizer)
55
48
  @model_class.find id
56
49
  rescue ::ActiveRecord::RecordNotFound
@@ -61,7 +54,6 @@ module Wallaby
61
54
  # @param resource [Object]
62
55
  # @param params [ActionController::Parameters]
63
56
  # @param authorizer [Wallaby::ModelAuthorizer]
64
- # @see Wallaby::ModelServiceProvider#create
65
57
  def create(resource, params, authorizer)
66
58
  save __callee__, resource, params, authorizer
67
59
  end
@@ -70,14 +62,12 @@ module Wallaby
70
62
  # @param resource [Object]
71
63
  # @param params [ActionController::Parameters]
72
64
  # @param authorizer [Wallaby::ModelAuthorizer]
73
- # @see Wallaby::ModelServiceProvider#update
74
65
  def update(resource, params, authorizer)
75
66
  save __callee__, resource, params, authorizer
76
67
  end
77
68
 
78
69
  # Remove a record from database
79
70
  # @param resource [Object]
80
- # @see Wallaby::ModelServiceProvider#destroy
81
71
  def destroy(resource, _params, _authorizer)
82
72
  resource.destroy
83
73
  end
@@ -109,7 +99,8 @@ module Wallaby
109
99
 
110
100
  # See if a resource is valid
111
101
  # @param resource [Object]
112
- # @return [Boolean]
102
+ # @return [true] if valid
103
+ # @return [false] otherwise
113
104
  def valid?(resource)
114
105
  validator.valid? resource
115
106
  end
@@ -137,22 +128,22 @@ module Wallaby
137
128
  permitter.simple_field_names << permitter.compound_hashed_fields
138
129
  end
139
130
 
140
- # @see Wallaby::ModelServiceProvider::Permitter
131
+ # @return [Wallaby::ActiveRecord::ModelServiceProvider::Permitter]
141
132
  def permitter
142
133
  @permitter ||= Permitter.new @model_decorator
143
134
  end
144
135
 
145
- # @see Wallaby::ModelServiceProvider::Querier
136
+ # @return [Wallaby::ActiveRecord::ModelServiceProvider::Querier]
146
137
  def querier
147
138
  @querier ||= Querier.new @model_decorator
148
139
  end
149
140
 
150
- # @see Wallaby::ModelServiceProvider::Normalizer
141
+ # @return [Wallaby::ActiveRecord::ModelServiceProvider::Normalizer]
151
142
  def normalizer
152
143
  @normalizer ||= Normalizer.new @model_decorator
153
144
  end
154
145
 
155
- # @see Wallaby::ModelServiceProvider::Validator
146
+ # @return [Wallaby::ActiveRecord::ModelServiceProvider::Validator]
156
147
  def validator
157
148
  @validator ||= Validator.new @model_decorator
158
149
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Wallaby
4
4
  class ActiveRecord
5
- # Pundit provider for ActiveRecord
5
+ # Pundit provider for {Wallaby::ActiveRecord}
6
6
  class PunditProvider < PunditAuthorizationProvider
7
7
  # Filter a scope
8
8
  # @param _action [Symbol, String]
@@ -11,7 +11,7 @@ module Wallaby
11
11
  def accessible_for(_action, scope)
12
12
  Pundit.policy_scope! user, scope
13
13
  rescue Pundit::NotDefinedError
14
- Rails.logger.warn "Cannot find scope policy for #{scope.inspect}.\nfrom #{__FILE__}:#{__LINE__}"
14
+ Logger.warn "Cannot find scope policy for `#{scope}`."
15
15
  scope
16
16
  end
17
17
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wallaby
4
- # ActiveRecord mode
4
+ # The Wallaby::ActiveRecord mode that implements the {Wallaby::Core} interfaces
5
+ # to handle ActiveRecord model/instance in all CRUD operations
5
6
  class ActiveRecord < Mode
6
7
  end
7
8
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Wallaby
4
4
  module ActiveRecordGem
5
- VERSION = '0.2.2' # :nodoc:
5
+ VERSION = '0.2.7' # :nodoc:
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wallaby-active_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tian Chen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-19 00:00:00.000000000 Z
11
+ date: 2022-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.2.0
33
+ version: 0.2.3
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.2.0
40
+ version: 0.2.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: cancancan
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -132,7 +132,7 @@ metadata:
132
132
  homepage_uri: https://github.com/wallaby-rails/wallaby-active_record
133
133
  source_code_uri: https://github.com/wallaby-rails/wallaby-active_record
134
134
  changelog_uri: https://github.com/wallaby-rails/wallaby-active_record/blob/master/CHANGELOG.md
135
- post_install_message:
135
+ post_install_message:
136
136
  rdoc_options: []
137
137
  require_paths:
138
138
  - lib
@@ -147,8 +147,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
147
  - !ruby/object:Gem::Version
148
148
  version: '0'
149
149
  requirements: []
150
- rubygems_version: 3.0.3
151
- signing_key:
150
+ rubygems_version: 3.1.2
151
+ signing_key:
152
152
  specification_version: 4
153
153
  summary: Wallaby's ActiveRecord ORM adapter
154
154
  test_files: []