graphql-active_record_batcher 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 987cfab30dfdc3481d7feff6ffe29273ed8de21c
4
- data.tar.gz: 067a21a5f99cb3f68e6b1084a685e8839a82e442
3
+ metadata.gz: ee2c32fbd0c4746914bd2991fc4f48120c0ebde7
4
+ data.tar.gz: eb39eeef4dcef1422f84aff5771ee7c28b3277a8
5
5
  SHA512:
6
- metadata.gz: 3f68ca34876e1ef67ce416b428fafb11b648388b68e5c36d4f017163ebe5cd82482822014accc07bd77a981e6c873975b7b20e8c6a8f7560b55b85e3007b16f7
7
- data.tar.gz: b536f7dc3d2ccb195ebc70e66fcf4326185236acebcf057c2dfcef4770a464c7fa66b9ffe7d54b1ec7549f62125141f4c5a0007ce9139133ab55f4b5211e8b58
6
+ metadata.gz: 668f040a391588456525f11d27b6dcfe478fd94cef5bc30950e27076bbb369dbd6f5ae611fe5b0ecf956c63d78c873a9b353e71c348d40906a2fea5be31ed00a
7
+ data.tar.gz: 4245d86955ae7d93fe41cc5ff70f434b191e9a7c7b0311173b0a96b12fb0a1de83e103cfaad96f7dcf96e5b558659c51a6b31abccdd6c358d334854cb4b7f5ec
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  /.bundle/
2
+ *.db
2
3
  /.yardoc
3
4
  /Gemfile.lock
4
5
  /_yardoc/
data/README.md CHANGED
@@ -24,6 +24,17 @@ Or install it yourself as:
24
24
 
25
25
  ## Usage
26
26
 
27
+ ### Set up preloading for a Schema
28
+
29
+ ```ruby
30
+ Schema = GraphQL::Schema.define do
31
+ # Enable preloading on a per-schema basis
32
+ use_preloading
33
+ query Query
34
+ mutation Mutation
35
+ end
36
+ ```
37
+
27
38
  ### Preloading Associations
28
39
 
29
40
  Using GraphQL without preloading associations results in under performant API and
@@ -64,8 +75,8 @@ StarWarsMovie = GraphQL::ObjectType.define do
64
75
  # the parent object
65
76
  model Movie
66
77
 
67
- field :characters, !types[!Dog] do
68
- preloads(:characters)
78
+ field :characters, !types[!Character] do
79
+ preloads :characters
69
80
  resolve ->(movie, _, _) { movie.characters }
70
81
  end
71
82
  end
@@ -79,20 +90,15 @@ Associations will now be preloaded and only 3 queries are used this time:
79
90
  3: SELECT "characters".* FROM "characters" WHERE "characters"."movie_d" IN (1, 2)
80
91
  ```
81
92
 
82
- ### Schema config
93
+ #### Preload multiple associations
83
94
 
84
- ```ruby
85
- Schema = GraphQL::Schema.define do
86
- query Query
87
- mutation Mutation
88
-
89
- # GraphQL Batch setup. Handle Promise objects.
90
- lazy_resolve(Promise, :sync)
91
- instrument(:query, GraphQL::Batch::Setup)
95
+ If a certain call loads more than one association, you can use an
96
+ array to express the ones to preload.
92
97
 
93
- # FieldInstrumenter takes care of preloading assocations you've
94
- # marked using the `preloads` attribute
95
- instrument(:field, GraphQL::ActiveRecordBatcher::FieldInstrumenter.new)
98
+ ```ruby
99
+ field :characters, !types[!Character] do
100
+ preloads [:characters, :planets]
101
+ resolve ->(movie, _, _) { movie.characters }
96
102
  end
97
103
  ```
98
104
 
@@ -100,7 +106,7 @@ end
100
106
 
101
107
  - [ ] Expose a way to batch finds
102
108
  - [ ] Expose a way or documentation on how to batch the `node` field
103
- - [ ] Accept an array of preloads
109
+ - [x] Accept an array of preloads
104
110
  - [ ] Accept nested preloads
105
111
 
106
112
  ## License
data/_test_.db CHANGED
Binary file
@@ -7,5 +7,15 @@ module GraphQL
7
7
  end
8
8
  end
9
9
 
10
+ # Accept a preloads attribute on fields
10
11
  GraphQL::Field.accepts_definitions(preloads: GraphQL::Define.assign_metadata_key(:preloads))
12
+
13
+ # For association preloading we need to know which Mode we are dealing with
11
14
  GraphQL::ObjectType.accepts_definitions(model: GraphQL::Define.assign_metadata_key(:model))
15
+
16
+ # A definition on schema lets us avoid documenting how to setup instrumenters
17
+ GraphQL::Schema.accepts_definitions(use_preloading: ->(schema) {
18
+ schema.lazy_methods.set(Promise, :sync)
19
+ schema.instrument(:query, GraphQL::Batch::Setup)
20
+ schema.instrument(:field, GraphQL::ActiveRecordBatcher::FieldInstrumenter.new)
21
+ })
@@ -34,7 +34,9 @@ module GraphQL
34
34
  attr_reader :model, :association
35
35
 
36
36
  def association_loaded?(record)
37
- record.association(@association).loaded?
37
+ puts record
38
+ puts @association
39
+ record.association(@association).loaded?
38
40
  end
39
41
  end
40
42
  end
@@ -2,9 +2,9 @@ module GraphQL
2
2
  module ActiveRecordBatcher
3
3
  class FieldInstrumenter
4
4
  def instrument(type, field)
5
- association_to_preload = field.metadata[:preloads]
5
+ associations = field.metadata[:preloads]
6
6
 
7
- if association_to_preload
7
+ if associations
8
8
  # Model is needed to preload an association
9
9
  unless model = type.metadata[:model]
10
10
  message = "No ActiveRecord Model set on type #{type.name}'s metadata."\
@@ -13,17 +13,14 @@ module GraphQL
13
13
  end
14
14
 
15
15
  # Make sure the association exists on the model
16
- validate_preload(model, association_to_preload)
17
-
18
- loader = GraphQL::ActiveRecordBatcher::AssociationLoader.new(
19
- model,
20
- association_to_preload
21
- )
16
+ validate(model, associations)
22
17
 
23
18
  # "Wrap" the resolve proc with our own, which returns a promise
24
19
  old_resolve_proc = field.resolve_proc
25
20
  new_resolve_proc = ->(obj, args, ctx) do
26
- loader.load(obj).then { old_resolve_proc.call(obj, args, ctx) }
21
+ build_preload_promise(obj, model, associations).then do
22
+ old_resolve_proc.call(obj, args, ctx)
23
+ end
27
24
  end
28
25
 
29
26
  field.redefine do
@@ -36,7 +33,36 @@ module GraphQL
36
33
 
37
34
  private
38
35
 
39
- def validate_preload(model, association_to_preload)
36
+ def build_preload_promise(object, model, associations)
37
+ if associations.is_a?(Array)
38
+ Promise.all(associations.map do |association|
39
+ loader_for(model, association).load(object)
40
+ end)
41
+ else
42
+ loader_for(model, associations).load(object)
43
+ end
44
+ end
45
+
46
+ def loader_for(model, association)
47
+ GraphQL::ActiveRecordBatcher::AssociationLoader.for(
48
+ model,
49
+ association
50
+ )
51
+ end
52
+
53
+ def validate(model, associations)
54
+ case associations
55
+ when Symbol
56
+ validate_association(model, associations)
57
+ when Array
58
+ associations.each { |association| validate_association(model, association) }
59
+ else
60
+ raise ArgumentError, "Cannot preload associations #{associations}."\
61
+ "Use a Symbol to preload one association or an Array of Symbols to load many."
62
+ end
63
+ end
64
+
65
+ def validate_association(model, association_to_preload)
40
66
  unless model.reflect_on_association(association_to_preload)
41
67
  raise ArgumentError, "No association `#{association_to_preload}` on model `#{model}`"
42
68
  end
@@ -1,5 +1,5 @@
1
1
  module GraphQL
2
2
  module ActiveRecordBatcher
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-active_record_batcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc-Andre Giroux
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-15 00:00:00.000000000 Z
11
+ date: 2017-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler