graphql-smart_select 0.1.2

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: 5ca57cd0d224feeea180728e03b39548353d7ce6b325c73b71c074d51c4d9832
4
+ data.tar.gz: 556d21cf7668437c3610cfe3c8da774612c559a4de3308773c8ee483082fd863
5
+ SHA512:
6
+ metadata.gz: 8e4a31c7aa8ee42ff911ad401f1823c4ce3c29db929706cf53eaf6755e980b8a5496d1a8c21894928ce26befe27acb89a453cf4f81759117191e3f743c32929e
7
+ data.tar.gz: 6eed5d0b7fa5531105280d575a3830d963e7c0bdc7429bf9d6d864b08f33b97e770be3aacf3c2f6c3c7746a433d45243b82c492b0a75c83231a227d65ee535c6
data/CHANGELOG.md ADDED
File without changes
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Alexander Abroskin
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,108 @@
1
+ [![Build Status](https://travis-ci.org/Arkweid/graphql-smart_select.svg?branch=master)](https://travis-ci.org/Arkweid/graphql-smart_select)
2
+
3
+ # GraphQL::SmartSelect
4
+
5
+ Plugin for [graphql-ruby](https://github.com/rmosolgo/graphql-ruby) which helps to select only the required fields from the database.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'graphql-smart_select'
13
+ ```
14
+
15
+ ## Problem explanation
16
+
17
+ Consider the following query:
18
+ ```
19
+ query {
20
+ posts {
21
+ id
22
+ title
23
+ }
24
+ }
25
+ ```
26
+
27
+ Ruby interface for serve this query:
28
+ ```ruby
29
+ module GraphqlAPI
30
+ module Types
31
+ class Query < GraphQL::Schema::Object
32
+ field :posts, Types::Post, null: false
33
+
34
+ def posts
35
+ Post.all
36
+ end
37
+ end
38
+ end
39
+ end
40
+ ```
41
+ In the default case, this will lead to the query: ```SELECT * FROM posts```. But we need only ```id``` and ```title```.
42
+ For tables with a large number of columns, this has a negative effect on performance.
43
+
44
+ ## Usage
45
+
46
+ Let's use our plugin:
47
+ ```ruby
48
+ module GraphqlAPI
49
+ module Types
50
+ class Query < GraphQL::Schema::Object
51
+ # use plugin
52
+ field_class.prepend(GraphQL::SmartSelect)
53
+
54
+ # activate plugin
55
+ field :posts, Types::Post, null: false, smart_select: true
56
+
57
+ # You can also explicitly specify which fields
58
+ # will be added
59
+ field :posts, Types::Post, null: false, smart_select: [:id]
60
+
61
+ def posts
62
+ Post.all
63
+ end
64
+ end
65
+
66
+ class Post < GraphQL::Schema::Object
67
+ field_class.prepend(GraphQL::SmartSelect)
68
+
69
+ field :id, ID
70
+ field :title, String
71
+ field :raw_content, String
72
+ field :another_content, String
73
+
74
+ # We'll tell the plugin which fields are needed
75
+ # for resolve this field
76
+ field :contents, db_columns: [:raw_content, :another_content]
77
+
78
+ # For one_to_one AR assosiation we include foreign_key
79
+ field :user, Types::User
80
+
81
+ # For has_many AR assosiation we include primary_key
82
+ field :comments, [Types::Comment]
83
+
84
+ def contents
85
+ [object.id, object.title].join
86
+ end
87
+ end
88
+ end
89
+ end
90
+ ```
91
+
92
+ For this example query:
93
+ ```
94
+ query {
95
+ posts {
96
+ title
97
+ contents
98
+ user { name }
99
+ comments { id }
100
+ }
101
+ }
102
+ ```
103
+ It perform following request:
104
+ ```SELECT id, title, raw_content, another_content, user_id FROM posts```
105
+
106
+ ## License
107
+
108
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql/smart_select/version'
4
+ require 'graphql/smart_select/resolver'
5
+
6
+ module GraphQL
7
+ #
8
+ # Apply additional scope to the AR query
9
+ # which selects only the required fields
10
+ #
11
+ module SmartSelect
12
+ attr_reader :db_columns, :smart_select
13
+
14
+ def initialize(*args, **kwargs, &block)
15
+ @smart_select = kwargs.delete(:smart_select)
16
+ @db_columns = kwargs.delete(:db_columns)
17
+ super
18
+ end
19
+
20
+ private
21
+
22
+ def apply_scope(value, ctx)
23
+ if smart_select && value.is_a?(ActiveRecord::Relation)
24
+ fields_for_select = Resolver.new(value, ctx, smart_select).resolve
25
+
26
+ value = value.select(fields_for_select)
27
+ end
28
+ super
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module SmartSelect
5
+ #
6
+ # Provide methods to expose foreign keys
7
+ # for belongs_to and has_one assosiations
8
+ #
9
+ class Assosiations
10
+ attr_reader :relation, :query_fields
11
+
12
+ def initialize(relation, query_fields)
13
+ @relation = relation
14
+ @query_fields = query_fields
15
+ end
16
+
17
+ def expose
18
+ assosiations_keys
19
+ end
20
+
21
+ private
22
+
23
+ def assosiations_keys
24
+ relation.reflections.map do |assosiation_name, reflection|
25
+ next unless required?(assosiation_name)
26
+
27
+ if one_to_one?(reflection)
28
+ reflection.options[:foreign_key]&.to_s || assosiation_name.foreign_key
29
+ elsif has_many?(reflection)
30
+ relation.primary_key
31
+ else
32
+ next
33
+ end
34
+ end.uniq
35
+ end
36
+
37
+ def required?(assosiation_name)
38
+ query_fields.include? assosiation_name
39
+ end
40
+
41
+ def one_to_one?(reflection)
42
+ reflection.is_a?(ActiveRecord::Reflection::BelongsToReflection) ||
43
+ reflection.is_a?(ActiveRecord::Reflection::HasOneReflection)
44
+ end
45
+
46
+ def has_many?(reflection)
47
+ reflection.is_a?(ActiveRecord::Reflection::HasManyReflection)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module SmartSelect
5
+ #
6
+ # Provide methods to expose keys for available
7
+ # options db_columns and smart_select
8
+ #
9
+ class Options
10
+ attr_reader :list_of_nodes, :smart_select
11
+
12
+ def initialize(list_of_nodes, smart_select)
13
+ @list_of_nodes = list_of_nodes
14
+ @smart_select = smart_select
15
+ end
16
+
17
+ def expose
18
+ db_columns_fields | smart_select_fields
19
+ end
20
+
21
+ private
22
+
23
+ def db_columns_fields
24
+ list_of_nodes.flat_map do |_, node|
25
+ node.definition.metadata[:type_class].db_columns&.map(&:to_s)
26
+ end
27
+ end
28
+
29
+ def smart_select_fields
30
+ smart_select.is_a?(Array) ? smart_select.map(&:to_s) : []
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql/smart_select/assosiations'
4
+ require 'graphql/smart_select/options'
5
+
6
+ module GraphQL
7
+ module SmartSelect
8
+ #
9
+ # Resolve the minimum required fields for the query
10
+ #
11
+ class Resolver
12
+ attr_reader :relation, :ctx, :smart_select
13
+
14
+ def initialize(relation, ctx, smart_select)
15
+ @smart_select = smart_select
16
+ @relation = relation
17
+ @ctx = ctx
18
+ end
19
+
20
+ def resolve
21
+ reject_virtual_fields(
22
+ query_fields |
23
+ Assosiations.new(relation, query_fields).expose |
24
+ Options.new(list_of_nodes, smart_select).expose
25
+ ).map(&:to_sym)
26
+ end
27
+
28
+ private
29
+
30
+ def list_of_nodes
31
+ @list_of_nodes ||= ctx.irep_node.typed_children[ctx.type.unwrap]
32
+ end
33
+
34
+ def query_fields
35
+ @query_fields ||= list_of_nodes.keys.map(&:underscore)
36
+ end
37
+
38
+ def reject_virtual_fields(fields_for_select)
39
+ relation.model.column_names & fields_for_select
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module SmartSelect
5
+ VERSION = '0.1.2'
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: graphql-smart_select
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Abroskin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: graphql
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.3'
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 1.3.13
107
+ type: :development
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - "~>"
112
+ - !ruby/object:Gem::Version
113
+ version: '1.3'
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 1.3.13
117
+ description: Provide logic for select only required fields for query
118
+ email:
119
+ - a.a.abroskin@yandex.ru
120
+ executables: []
121
+ extensions: []
122
+ extra_rdoc_files: []
123
+ files:
124
+ - CHANGELOG.md
125
+ - LICENSE.txt
126
+ - README.md
127
+ - lib/graphql/smart_select.rb
128
+ - lib/graphql/smart_select/assosiations.rb
129
+ - lib/graphql/smart_select/options.rb
130
+ - lib/graphql/smart_select/resolver.rb
131
+ - lib/graphql/smart_select/version.rb
132
+ homepage: https://github.com/Arkweid/graphql-smart_select
133
+ licenses:
134
+ - MIT
135
+ metadata: {}
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 2.2.0
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 2.7.6
153
+ signing_key:
154
+ specification_version: 4
155
+ summary: Plugin for graphql-ruby gem
156
+ test_files: []