ar_virtual_field 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4ca9b36a6e1b3b4432979509a61c611962b2a696ea0494bc27b856c57436fa29
4
+ data.tar.gz: 85d952b60c94fbe1be24cefec6432364fac2f144f739040a92575eddfa7ee556
5
+ SHA512:
6
+ metadata.gz: d072a6c0ee93c4d07114bb8bc9066000c19655484c8a8379e44e2f6bf0819fadd2a5d960078c9241f5dcc72c0202accb250f31b331bf001251c1a89c3051a9b9
7
+ data.tar.gz: fe351b6577315a727b74e6dbe8c6cf4f685ecf0785002b2fc1e067e1cac9c633e0b64654fe9f31142d7a7b220998b41cf6c95ca094a6939edca9188eb5588ea6
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Pavel Egorov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # Active Record Virtual Field
2
+
3
+ Gem provides an easy mechanism to define virtual fields within an ActiveRecord model.
4
+ It allows defining attributes that are not directly stored in the database, but are instead computed or fetched using SQL queries.
5
+ Gem handles both the definition of these fields and the creation of scopes to query models with the virtual field included.
6
+
7
+ ## Installation
8
+
9
+ Add gem to Gemfile:
10
+
11
+ ```ruby
12
+ gem 'ar_virtual_field'
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Defining a Virtual Field
18
+
19
+ To define a virtual field, use the virtual_field method in your model:
20
+
21
+ ```ruby
22
+ virtual_field :virtual_attribute,
23
+ scope: -> { joins(:related_model).where(related_models: { some_column: value }) },
24
+ select: -> { "SUM(related_models.some_value)" },
25
+ get: -> { calculate_some_value },
26
+ default: 0
27
+ ```
28
+
29
+ Parameters:
30
+ - `name`: The name of the virtual field.
31
+ - `scope`: A lambda defining a scope that fetches the virtual field value (optional).
32
+ - `select`: SQL selection logic (can be a string or a lambda returning an SQL string) to define how the field is computed.
33
+ - `get`: A method to retrieve the value of the virtual field when the field isn't fetched via SQL.
34
+ - `default`: A default value for the virtual field if the result is nil.
35
+
36
+ Example:
37
+
38
+ ```ruby
39
+ class User < ApplicationRecord
40
+ virtual_field :total_orders,
41
+ scope: -> { joins(:orders).group(:id) },
42
+ select: -> { "COUNT(orders.id)" },
43
+ get: -> { orders.count },
44
+ default: 0
45
+ end
46
+ ```
47
+
48
+ ### Using the scope in queries:
49
+ ```ruby
50
+ users_with_orders = User.with_total_orders
51
+ ```
52
+
53
+ ### Scopes and Querying:
54
+
55
+ - `with_#{name}`: Automatically generated scope to include the virtual field in queries. You can use this scope in your ActiveRecord queries like so:
56
+
57
+ ```ruby
58
+ User.with_total_orders.where(total_orders: 5)
59
+ ```
60
+
61
+ This will include the total_orders virtual field in the SQL query and allow filtering by it.
62
+
63
+ ## Development
64
+
65
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
66
+
67
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
68
+
69
+ ## Contributing
70
+
71
+ Bug reports and pull requests are welcome on GitHub at https://github.com//ar_virtual_field. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com//ar_virtual_field/blob/main/CODE_OF_CONDUCT.md).
72
+
73
+ ## License
74
+
75
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
76
+
77
+ ## Code of Conduct
78
+
79
+ Everyone interacting in the ArVirtualField project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com//ar_virtual_field/blob/main/CODE_OF_CONDUCT.md).
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArVirtualField
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArVirtualField
4
+ module HelperMethods
5
+ def self.select_append(relation, *values)
6
+ if relation.select_values.empty?
7
+ values.unshift(relation.arel_table[Arel.star])
8
+ end
9
+
10
+ relation.select(*values)
11
+ end
12
+ end
13
+
14
+ def virtual_field(name, scope:, select: nil, get:, default:)
15
+ name = name.to_s
16
+ current_class = self
17
+ unwrap_arel_expression = -> (exp) { exp.is_a?(Arel::Nodes::NodeExpression) ? exp : Arel.sql(exp) }
18
+
19
+ select_lambda =
20
+ case select
21
+ when Proc
22
+ -> { unwrap_arel_expression.(select.()) }
23
+ else
24
+ arel = unwrap_arel_expression.(select)
25
+ -> { arel }
26
+ end
27
+
28
+ if scope
29
+ scope_name = :"_scope_#{name}"
30
+
31
+ scope(scope_name, scope)
32
+
33
+ scope(:"with_#{name}", -> do
34
+ scope_query = current_class.send(scope_name)
35
+
36
+ if scope_query.group_values.present?
37
+ scope_query = scope_query.reselect(select_lambda.().as(name), "#{table_name}.id")
38
+ new_scope = joins("LEFT JOIN (#{scope_query.to_sql}) #{name}_outer ON #{name}_outer.id = #{table_name}.id")
39
+ HelperMethods.select_append(new_scope, "#{name}_outer.#{name} AS #{name}")
40
+ else
41
+ HelperMethods.select_append(send(scope_name), select_lambda.().as(name))
42
+ end
43
+ end)
44
+ else
45
+ scope(:"with_#{name}", -> do
46
+ HelperMethods.select_append(self, select_lambda.().as(name))
47
+ end)
48
+ end
49
+
50
+ method_name = :"ar_virtual_field_#{name}"
51
+
52
+ define_method(method_name, &get)
53
+ define_method(name) do
54
+ if ActiveRecord::Base.connection.query_cache_enabled
55
+ attributes.key?(name) ? (self[name] || default) : send(method_name)
56
+ else
57
+ send(method_name)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ ActiveSupport.on_load(:active_record) do
64
+ ActiveRecord::Base.extend(ArVirtualField)
65
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ar_virtual_field
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Pavel Egorov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-09-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 6.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 6.1.0
27
+ description: Adds .virtual_field method to make it easy to define virtual fields
28
+ email:
29
+ - moonmeander47@ya.ru
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE.txt
35
+ - README.md
36
+ - lib/ar_virtual_field.rb
37
+ - lib/ar_virtual_field/version.rb
38
+ homepage: https://github.com/emfy0/ar_virtual_field
39
+ licenses:
40
+ - MIT
41
+ metadata:
42
+ homepage_uri: https://github.com/emfy0/ar_virtual_field
43
+ source_code_uri: https://github.com/emfy0/ar_virtual_field
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 3.0.0
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.4.10
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Provide an easy mechanism to define virtual fields within an ActiveRecord
63
+ model
64
+ test_files: []