graphql-sources 0.3.0 → 0.4.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f88238e75afcee4b41463d85c77e4ec70a89afffe18baf5bdaa5a780e153335f
4
- data.tar.gz: eb3a39814d97bf3c06c6ea996cd50dcff262a170b5700edd4019f98c2ff80cad
3
+ metadata.gz: c950f4402666974cd24dd441f3b51caac7d337429518753e6886cecc9d9a46dd
4
+ data.tar.gz: 88194279dc3f9ea1f3a1e47349cc5620b7cf550badbe6c0720fa35fcbf20a340
5
5
  SHA512:
6
- metadata.gz: 968c6e5955b5f936c040d862219b890137fed330047670ffda3c7b79ecab1531f976696729e24fb50257acacfff6141296071d84d395e27bedfe757cde5f6f5f
7
- data.tar.gz: 6ec3329d4de24ca2fe71f7c339fa4e6e9d569e4ef6e940f4b1174b2707e8641a72857c4ae1cb30ad53b436a53875616d6a4d254586619d2ebf76bf8a9dc26707
6
+ metadata.gz: 4f63d94f097e6c72665be2086ee3736ba11c87ceb41935afcfcefb1fbb4b64d9b0fe71f93eea66bdc0ddb8f4846e637b320e6f1117631d2a6522638869fc2df2
7
+ data.tar.gz: 620fe9b524a7a0af4a67dbdfcc1f558f419977c25116830b3c46c42ed32f1fc86b1eba92c6a857c5ffc4d8814781cc989dca5b78519eefe6e04ef0b08f0c6b6a
data/README.md CHANGED
@@ -78,6 +78,46 @@ WHERE "comments"."user_id" IN (...)
78
78
  ORDER BY "comments"."id"
79
79
  ```
80
80
 
81
+ ### Loading `has_one_attached` Associations
82
+
83
+ ```ruby
84
+ class User
85
+ has_one_attached :avatar
86
+ end
87
+ ```
88
+
89
+ ```ruby
90
+ class UserType < GraphQL::Schema::Object
91
+ field :avatar, AttachedType, null: false
92
+
93
+ def avatar
94
+ dataloader
95
+ .with(GraphQL::Sources::ActiveStorageHasOneAttached, :avatar)
96
+ .load(object)
97
+ end
98
+ end
99
+ ```
100
+
101
+ ### Loading `has_many_attached` Associations
102
+
103
+ ```ruby
104
+ class User
105
+ has_many_attached :photos
106
+ end
107
+ ```
108
+
109
+ ```ruby
110
+ class UserType < GraphQL::Schema::Object
111
+ field :photos, [AttachedType], null: false
112
+
113
+ def photos
114
+ dataloader
115
+ .with(GraphQL::Sources::ActiveStorageHasOneAttached, :photos)
116
+ .load(object)
117
+ end
118
+ end
119
+ ```
120
+
81
121
  ### Loading Counts
82
122
 
83
123
  ```ruby
@@ -111,6 +151,12 @@ WHERE "likes"."post_id" IN (1, 2, 3, ...)
111
151
  GROUP BY "likes"."post_id"
112
152
  ```
113
153
 
154
+ ## Status
155
+
156
+ [![CircleCI](https://circleci.com/gh/ksylvest/graphql-sources.svg?style=svg)](https://circleci.com/gh/ksylvest/rhino)
157
+ [![Maintainability](https://api.codeclimate.com/v1/badges/bc301cb72712637e67dd/maintainability)](https://codeclimate.com/github/ksylvest/graphql-sources/maintainability)
158
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/bc301cb72712637e67dd/test_coverage)](https://codeclimate.com/github/ksylvest/graphql-sources/test_coverage)
159
+
114
160
  ## License
115
161
 
116
162
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Sources
5
+ # An abstract class for interacting with active storage.
6
+ class ActiveStorageBase < GraphQL::Dataloader::Source
7
+ # @param name [String] the association name
8
+ def initialize(name)
9
+ super()
10
+ @name = name
11
+ end
12
+
13
+ protected
14
+
15
+ # @param records [Array<ActiveRecord::Base>] a collection of records to load attachments for
16
+ # @return [Array<ActiveStorage::Attachment>] the associated attachments with preloaded blobs
17
+ def attachments(records:)
18
+ ActiveStorage::Attachment
19
+ .preload(:blob)
20
+ .where(record: records)
21
+ .where(name: @name)
22
+ .order(:id)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './active_storage_base'
4
+
5
+ module GraphQL
6
+ module Sources
7
+ # A class for loading `has_many_attached` style associations.
8
+ #
9
+ # class User
10
+ # has_many_attached :photos
11
+ # end
12
+ #
13
+ # class UserType < GraphQL::Schema::Object
14
+ # field :photos, [AttachedType], null: false
15
+ #
16
+ # def photos
17
+ # dataloader
18
+ # .with(GraphQL::Sources::ActiveStorageHasManyAttached, :photos)
19
+ # .load(object)
20
+ # end
21
+ # end
22
+ #
23
+ # The resulting SQL query is:
24
+ #
25
+ # SELECT "active_storage_attachments".*
26
+ # FROM "active_storage_attachments"
27
+ # WHERE "active_storage_attachments"."name" = 'photos'
28
+ # AND "active_storage_attachments"."record_type" = 'User'
29
+ # AND "active_storage_attachments"."record_id" IN (...)
30
+ class ActiveStorageHasManyAttached < ActiveStorageBase
31
+ def fetch(records)
32
+ attachments = attachments(records: records).load_async
33
+ dataloader.yield
34
+
35
+ map = attachments.group_by { |attachment| [attachment.record_type, attachment.record_id] }
36
+ records.map { |record| map[[record.class.name, record.id]] || [] }
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './active_storage_base'
4
+
5
+ module GraphQL
6
+ module Sources
7
+ # A class for loading `has_one_attached` style associations.
8
+ #
9
+ # class User
10
+ # has_one_attached :photo
11
+ # end
12
+ #
13
+ # class UserType < GraphQL::Schema::Object
14
+ # field :avatar, AttachedType, null: false
15
+ #
16
+ # def avatar
17
+ # dataloader
18
+ # .with(GraphQL::Sources::ActiveStorageHasOneAttached, :avatar)
19
+ # .load(object)
20
+ # end
21
+ # end
22
+ #
23
+ # The resulting SQL query is:
24
+ #
25
+ # SELECT "active_storage_attachments".*
26
+ # FROM "active_storage_attachments"
27
+ # WHERE "active_storage_attachments"."name" = 'avatar'
28
+ # AND "active_storage_attachments"."record_type" = 'User'
29
+ # AND "active_storage_attachments"."record_id" IN (...)
30
+ class ActiveStorageHasOneAttached < ActiveStorageBase
31
+ def fetch(records)
32
+ attachments = attachments(records: records).load_async
33
+ dataloader.yield
34
+
35
+ map = attachments.index_by { |attachment| [attachment.record_type, attachment.record_id] }
36
+ records.map { |record| map[[record.class.name, record.id]] }
37
+ end
38
+ end
39
+ end
40
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GraphQL
4
4
  module Sources
5
- VERSION = '0.3.0'
5
+ VERSION = '0.4.0'
6
6
  end
7
7
  end
@@ -5,6 +5,8 @@ require 'graphql'
5
5
  require_relative './sources/active_record_count'
6
6
  require_relative './sources/active_record_collection'
7
7
  require_relative './sources/active_record_object'
8
+ require_relative './sources/active_storage_has_many_attached'
9
+ require_relative './sources/active_storage_has_one_attached'
8
10
 
9
11
  module GraphQL
10
12
  # A collection of common GraphQL dataloader classes.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-sources
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Sylvestre
@@ -150,6 +150,20 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: simplecov
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
153
167
  description: Common loaders for various database or cache operations.
154
168
  email:
155
169
  - kevin@ksylvest.com
@@ -165,6 +179,9 @@ files:
165
179
  - lib/graphql/sources/active_record_collection.rb
166
180
  - lib/graphql/sources/active_record_count.rb
167
181
  - lib/graphql/sources/active_record_object.rb
182
+ - lib/graphql/sources/active_storage_base.rb
183
+ - lib/graphql/sources/active_storage_has_many_attached.rb
184
+ - lib/graphql/sources/active_storage_has_one_attached.rb
168
185
  - lib/graphql/sources/version.rb
169
186
  homepage: https://github.com/ksylvest/graphql-sources
170
187
  licenses: