graphql-batch 0.3.4 → 0.3.5
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 +4 -4
- data/README.md +6 -0
- data/examples/association_loader.rb +48 -0
- data/examples/record_loader.rb +28 -0
- data/lib/graphql/batch.rb +7 -2
- data/lib/graphql/batch/loader.rb +0 -1
- data/lib/graphql/batch/mutation_execution_strategy.rb +2 -0
- data/lib/graphql/batch/setup.rb +45 -5
- data/lib/graphql/batch/setup_multiplex.rb +10 -5
- data/lib/graphql/batch/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b725a9f32a436a6e9ee155242dbcff2b576c6b8
|
4
|
+
data.tar.gz: d2e42e370abdd6c28014ca0e10e10ae958854e28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aee2377e4fa101ddeec55f33a679af48776262a80087c0b9e033e280c49d7a02cd2ae225b15b3f466c242c359d429ec60e03291e5d6ab0f74dcd4044eb7ecac9
|
7
|
+
data.tar.gz: 200b341c757155b9fb23aa87e22cd228dc22bfca8d90c05102ddc54ef806034228472a9fc7d45f329cdc6be3ce1361096e9fa9f4985271ce2f51afc74d3042d1
|
data/README.md
CHANGED
@@ -72,6 +72,12 @@ The loader class can be used from the resolve proc for a graphql field by callin
|
|
72
72
|
resolve -> (obj, args, context) { RecordLoader.for(Product).load(args["id"]) }
|
73
73
|
```
|
74
74
|
|
75
|
+
Although this library doesn't have a dependency on active record,
|
76
|
+
the [examples directory](examples) has record and association loaders
|
77
|
+
for active record which handles edge cases like type casting ids
|
78
|
+
and overriding GraphQL::Batch::Loader#cache_key to load associations
|
79
|
+
on records with the same id.
|
80
|
+
|
75
81
|
### Promises
|
76
82
|
|
77
83
|
GraphQL::Batch::Loader#load returns a Promise using the [promise.rb gem](https://rubygems.org/gems/promise.rb) to provide a promise based API, so you can transform the query results using `.then`
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class AssociationLoader < GraphQL::Batch::Loader
|
2
|
+
def self.validate(model, association_name)
|
3
|
+
new(model, association_name)
|
4
|
+
nil
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(model, association_name)
|
8
|
+
@model = model
|
9
|
+
@association_name = association_name
|
10
|
+
validate
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(record)
|
14
|
+
raise TypeError, "#{@model} loader can't load association for #{record.class}" unless record.is_a?(@model)
|
15
|
+
return Promise.resolve(read_association(record)) if association_loaded?(record)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
# We want to load the associations on all records, even if they have the same id
|
20
|
+
def cache_key(record)
|
21
|
+
record.object_id
|
22
|
+
end
|
23
|
+
|
24
|
+
def perform(records)
|
25
|
+
preload_association(records)
|
26
|
+
records.each { |record| fulfill(record, read_association(record)) }
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate
|
32
|
+
unless @model.reflect_on_association(@association_name)
|
33
|
+
raise ArgumentError, "No association #{@association_name} on #{@model}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def preload_association(records)
|
38
|
+
::ActiveRecord::Associations::Preloader.new.preload(records, @association_name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def read_association(record)
|
42
|
+
record.public_send(@association_name)
|
43
|
+
end
|
44
|
+
|
45
|
+
def association_loaded?(record)
|
46
|
+
record.association(@association_name).loaded?
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class RecordLoader < GraphQL::Batch::Loader
|
2
|
+
def initialize(model, column: model.primary_key, where: nil)
|
3
|
+
@model = model
|
4
|
+
@column = column.to_s
|
5
|
+
@column_type = model.type_for_attribute(@column)
|
6
|
+
@where = where
|
7
|
+
end
|
8
|
+
|
9
|
+
def load(key)
|
10
|
+
super(@column_type.cast(key))
|
11
|
+
end
|
12
|
+
|
13
|
+
def perform(keys)
|
14
|
+
query(keys).each do |record|
|
15
|
+
value = @column_type.cast(record.public_send(@column))
|
16
|
+
fulfill(value, record)
|
17
|
+
end
|
18
|
+
keys.each { |key| fulfill(key, nil) unless fulfilled?(key) }
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def query(keys)
|
24
|
+
scope = @model
|
25
|
+
scope = scope.where(@where) if @where
|
26
|
+
scope.where(@column => keys)
|
27
|
+
end
|
28
|
+
end
|
data/lib/graphql/batch.rb
CHANGED
@@ -20,10 +20,15 @@ module GraphQL
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.use(schema_defn)
|
23
|
+
schema = schema_defn.target
|
23
24
|
if GraphQL::VERSION >= "1.6.0"
|
24
|
-
|
25
|
+
instrumentation = GraphQL::Batch::SetupMultiplex.new(schema)
|
26
|
+
schema_defn.instrument(:multiplex, instrumentation)
|
27
|
+
schema_defn.instrument(:field, instrumentation)
|
25
28
|
else
|
26
|
-
|
29
|
+
instrumentation = GraphQL::Batch::Setup.new(schema)
|
30
|
+
schema_defn.instrument(:query, instrumentation)
|
31
|
+
schema_defn.instrument(:field, instrumentation)
|
27
32
|
end
|
28
33
|
schema_defn.lazy_resolve(::Promise, :sync)
|
29
34
|
end
|
data/lib/graphql/batch/loader.rb
CHANGED
@@ -9,11 +9,13 @@ module GraphQL::Batch
|
|
9
9
|
strategy = execution_context.strategy
|
10
10
|
return super if strategy.enable_batching
|
11
11
|
|
12
|
+
GraphQL::Batch::Executor.current.clear
|
12
13
|
begin
|
13
14
|
strategy.enable_batching = true
|
14
15
|
strategy.deep_sync(Promise.sync(super))
|
15
16
|
ensure
|
16
17
|
strategy.enable_batching = false
|
18
|
+
GraphQL::Batch::Executor.current.clear
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
data/lib/graphql/batch/setup.rb
CHANGED
@@ -1,14 +1,54 @@
|
|
1
1
|
module GraphQL::Batch
|
2
|
-
|
3
|
-
|
2
|
+
class Setup
|
3
|
+
class << self
|
4
|
+
def start_batching
|
5
|
+
raise NestedError if GraphQL::Batch::Executor.current
|
6
|
+
GraphQL::Batch::Executor.current = GraphQL::Batch::Executor.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def end_batching
|
10
|
+
GraphQL::Batch::Executor.current = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def instrument_field(schema, type, field)
|
14
|
+
return field unless type == schema.mutation
|
15
|
+
old_resolve_proc = field.resolve_proc
|
16
|
+
field.redefine do
|
17
|
+
resolve ->(obj, args, ctx) {
|
18
|
+
GraphQL::Batch::Executor.current.clear
|
19
|
+
begin
|
20
|
+
Promise.sync(old_resolve_proc.call(obj, args, ctx))
|
21
|
+
ensure
|
22
|
+
GraphQL::Batch::Executor.current.clear
|
23
|
+
end
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def before_query(query)
|
29
|
+
warn "Deprecated graphql-batch setup `instrument(:query, GraphQL::Batch::Setup)`, replace with `use GraphQL::Batch`"
|
30
|
+
start_batching
|
31
|
+
end
|
32
|
+
|
33
|
+
def after_query(query)
|
34
|
+
end_batching
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(schema)
|
39
|
+
@schema = schema
|
40
|
+
end
|
4
41
|
|
5
42
|
def before_query(query)
|
6
|
-
|
7
|
-
GraphQL::Batch::Executor.current = GraphQL::Batch::Executor.new
|
43
|
+
Setup.start_batching
|
8
44
|
end
|
9
45
|
|
10
46
|
def after_query(query)
|
11
|
-
|
47
|
+
Setup.end_batching
|
48
|
+
end
|
49
|
+
|
50
|
+
def instrument(type, field)
|
51
|
+
Setup.instrument_field(@schema, type, field)
|
12
52
|
end
|
13
53
|
end
|
14
54
|
end
|
@@ -1,14 +1,19 @@
|
|
1
1
|
module GraphQL::Batch
|
2
|
-
|
3
|
-
|
2
|
+
class SetupMultiplex
|
3
|
+
def initialize(schema)
|
4
|
+
@schema = schema
|
5
|
+
end
|
4
6
|
|
5
7
|
def before_multiplex(multiplex)
|
6
|
-
|
7
|
-
GraphQL::Batch::Executor.current = GraphQL::Batch::Executor.new
|
8
|
+
Setup.start_batching
|
8
9
|
end
|
9
10
|
|
10
11
|
def after_multiplex(multiplex)
|
11
|
-
|
12
|
+
Setup.end_batching
|
13
|
+
end
|
14
|
+
|
15
|
+
def instrument(type, field)
|
16
|
+
Setup.instrument_field(@schema, type, field)
|
12
17
|
end
|
13
18
|
end
|
14
19
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-batch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dylan Thacker-Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -116,6 +116,8 @@ files:
|
|
116
116
|
- Rakefile
|
117
117
|
- bin/console
|
118
118
|
- bin/setup
|
119
|
+
- examples/association_loader.rb
|
120
|
+
- examples/record_loader.rb
|
119
121
|
- graphql-batch.gemspec
|
120
122
|
- lib/graphql/batch.rb
|
121
123
|
- lib/graphql/batch/execution_strategy.rb
|