graph_weaver 0.7.1 → 0.7.3
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/Gemfile.lock +19 -19
- data/docs/federation.md +8 -8
- data/docs/generated_modules.md +28 -21
- data/docs/getting_started.md +14 -13
- data/docs/testing.md +17 -14
- data/docs/transports.md +16 -9
- data/docs/upgrading.md +28 -5
- data/examples/github/generated/star_mutation.rb +4 -4
- data/examples/github/generated/stargazers_query.rb +4 -4
- data/examples/github/generated/starred_query.rb +4 -4
- data/lib/graph_weaver/client.rb +8 -0
- data/lib/graph_weaver/codegen/emit.rb +5 -11
- data/lib/graph_weaver/codegen.rb +18 -54
- data/lib/graph_weaver/graph.rb +39 -29
- data/lib/graph_weaver/internal/test_clients.rb +7 -11
- data/lib/graph_weaver/internal.rb +15 -0
- data/lib/graph_weaver/query_module.rb +36 -23
- data/lib/graph_weaver/railtie.rb +202 -147
- data/lib/graph_weaver/rspec.rb +13 -24
- data/lib/graph_weaver/tasks.rb +10 -2
- data/lib/graph_weaver/testing.rb +12 -4
- data/lib/graph_weaver/version.rb +1 -1
- data/lib/graph_weaver.rb +26 -9
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 653ecbcc2215bf5358e34bc83d701ded874a6ee1910ceeca18f0ed205a44798f
|
|
4
|
+
data.tar.gz: 2d1e49f247e84347c7bd86123b54b1b9d31d8978bc2a6a8f8d9538342c3ab67d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 220c5d9ab87c671a602b226b2789fee65307e3b8a85407fa5c979eb272cde0e27d551e0a6d5ef32ad2714a6eec211fcf0657d1a2b7eb7a53c33d063756d8e82c
|
|
7
|
+
data.tar.gz: 650c62d1ca107aaaccfa03ddd4686475c15ad68c0cf421be67379a7b88212af8366681da61208dee39ee2a68a468ca792f8cc9fee54c8982087924f927c2a2d1
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
graph_weaver (0.7.
|
|
4
|
+
graph_weaver (0.7.3)
|
|
5
5
|
graphql (>= 2.6.7)
|
|
6
6
|
sorbet-runtime
|
|
7
7
|
|
|
@@ -195,16 +195,16 @@ GEM
|
|
|
195
195
|
rubydex (0.2.7-x86_64-darwin)
|
|
196
196
|
rubydex (0.2.7-x86_64-linux)
|
|
197
197
|
securerandom (0.4.1)
|
|
198
|
-
simplecov (1.
|
|
199
|
-
sorbet (0.6.
|
|
200
|
-
sorbet-static (= 0.6.
|
|
201
|
-
sorbet-runtime (0.6.
|
|
202
|
-
sorbet-static (0.6.
|
|
203
|
-
sorbet-static (0.6.
|
|
204
|
-
sorbet-static (0.6.
|
|
205
|
-
sorbet-static-and-runtime (0.6.
|
|
206
|
-
sorbet (= 0.6.
|
|
207
|
-
sorbet-runtime (= 0.6.
|
|
198
|
+
simplecov (1.3.0)
|
|
199
|
+
sorbet (0.6.13498)
|
|
200
|
+
sorbet-static (= 0.6.13498)
|
|
201
|
+
sorbet-runtime (0.6.13498)
|
|
202
|
+
sorbet-static (0.6.13498-aarch64-linux)
|
|
203
|
+
sorbet-static (0.6.13498-universal-darwin)
|
|
204
|
+
sorbet-static (0.6.13498-x86_64-linux)
|
|
205
|
+
sorbet-static-and-runtime (0.6.13498)
|
|
206
|
+
sorbet (= 0.6.13498)
|
|
207
|
+
sorbet-runtime (= 0.6.13498)
|
|
208
208
|
spoom (1.8.3)
|
|
209
209
|
erubi (>= 1.10.0)
|
|
210
210
|
prism (>= 0.28.0)
|
|
@@ -299,7 +299,7 @@ CHECKSUMS
|
|
|
299
299
|
google-protobuf (4.35.1-arm64-darwin) sha256=d9c957df04fa89c749fa9a72a7b383eb4296efc9b2303dc6fd6fbe39c698ad6b
|
|
300
300
|
google-protobuf (4.35.1-x86_64-darwin) sha256=66b62b4df00931018a692806df66393efa960d6d2b7da69735187249f950d3ee
|
|
301
301
|
google-protobuf (4.35.1-x86_64-linux-gnu) sha256=c786439087512a3fbd199e9897d265b855f951d4027e218ea55e858d45969edd
|
|
302
|
-
graph_weaver (0.7.
|
|
302
|
+
graph_weaver (0.7.3)
|
|
303
303
|
graphql (2.6.10) sha256=9b7c8633767f516ff9d48a8d6305b2a00a2101c82aa871b92e69086944f9f83e
|
|
304
304
|
hashdiff (1.2.1) sha256=9c079dbc513dfc8833ab59c0c2d8f230fa28499cc5efb4b8dd276cf931457cd1
|
|
305
305
|
i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5
|
|
@@ -350,13 +350,13 @@ CHECKSUMS
|
|
|
350
350
|
rubydex (0.2.7-x86_64-darwin) sha256=b002b259d118ac69de44470eff1597143318402c45630c47371f9542631447dc
|
|
351
351
|
rubydex (0.2.7-x86_64-linux) sha256=dacfade9fa42ce4469618da6dac07e69d5f3ac6a313b4caced5234c8f052419a
|
|
352
352
|
securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
|
|
353
|
-
simplecov (1.
|
|
354
|
-
sorbet (0.6.
|
|
355
|
-
sorbet-runtime (0.6.
|
|
356
|
-
sorbet-static (0.6.
|
|
357
|
-
sorbet-static (0.6.
|
|
358
|
-
sorbet-static (0.6.
|
|
359
|
-
sorbet-static-and-runtime (0.6.
|
|
353
|
+
simplecov (1.3.0) sha256=d9886307863c1ead47657dcbed869bfffd82318808b09014d8f0ff77dcfe7492
|
|
354
|
+
sorbet (0.6.13498) sha256=cb5279f6a9dbfc8d526bc9fb71d05020afb8043c40708e4aff2244ba329ce224
|
|
355
|
+
sorbet-runtime (0.6.13498) sha256=2da4627f9341a1fc6e4148cc891989b7b108106c206c46ca69940e10a21e9133
|
|
356
|
+
sorbet-static (0.6.13498-aarch64-linux) sha256=cbee732c49379d38029f295b45edaeb5757ab180d308d8383dc79f03fd4991be
|
|
357
|
+
sorbet-static (0.6.13498-universal-darwin) sha256=4cc97aa0da3dd175b8278e1617954d6dd9ba1f5aeb62981f21616b9ec791fb75
|
|
358
|
+
sorbet-static (0.6.13498-x86_64-linux) sha256=75d02e8af7d6c1081d4693e2ebefe679760327f1304377519970784faf9f913d
|
|
359
|
+
sorbet-static-and-runtime (0.6.13498) sha256=5f5686869dceae893b4171b05e3db159fe12f1aadf04aa8c2bf9dfa3edc0d902
|
|
360
360
|
spoom (1.8.3) sha256=32871fa189bbfa49cf557a50f819f23cc9a6ceefd0346caa7a6adc193becd5dd
|
|
361
361
|
tapioca (0.19.2) sha256=938731b07811aee8d23871b1aee8861d464fbaf2cfffbf79a62b0c869a5120ec
|
|
362
362
|
thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73
|
data/docs/federation.md
CHANGED
|
@@ -129,11 +129,13 @@ your resolvers run, which is the whole point.
|
|
|
129
129
|
|
|
130
130
|
In rspec that's the [`graphql: :router`](testing.md#a-federated-graph--graphql-router)
|
|
131
131
|
tag and there is nothing to pass — the tag builds it, once for the suite. It finds
|
|
132
|
-
the supergraph where you have already said it is:
|
|
133
|
-
{ supergraph: … }` if you named one there, else the schema a
|
|
132
|
+
the supergraph where you have already said it is: the schema a
|
|
134
133
|
[graph](getting_started.md#more-than-one-schema) declares when that schema is
|
|
135
|
-
composed, else
|
|
136
|
-
|
|
134
|
+
composed, else `Testing.config.router = { supergraph: … }` if you named one
|
|
135
|
+
there, else the committed dump when *that* is, else the dump your own client was
|
|
136
|
+
built from (`GraphWeaver.new("supergraph.graphql")` keeps its path). Two graphs
|
|
137
|
+
may name one supergraph; two naming different ones is refused rather than picked
|
|
138
|
+
between.
|
|
137
139
|
Outside rspec, build it yourself:
|
|
138
140
|
|
|
139
141
|
```ruby
|
|
@@ -406,14 +408,12 @@ client distinct from the one the app uses to reach the gateway from outside:
|
|
|
406
408
|
|
|
407
409
|
```ruby
|
|
408
410
|
# config/initializers/graph_weaver.rb — beside GraphWeaver.graph :reviews,
|
|
409
|
-
# whose client is
|
|
410
|
-
PLATFORM = GraphWeaver.new(ENV.fetch("PLATFORM_GRAPHQL_URL"))
|
|
411
|
-
|
|
411
|
+
# whose client is Reviews::Schema
|
|
412
412
|
GraphWeaver.graph :platform do
|
|
413
413
|
schema "app/graphql/supergraph.graphql"
|
|
414
414
|
queries "app/graphql/platform/queries"
|
|
415
415
|
output "app/graphql/platform/generated"
|
|
416
|
-
client "
|
|
416
|
+
client GraphWeaver.new(ENV.fetch("PLATFORM_GRAPHQL_URL"))
|
|
417
417
|
namespace "Platform"
|
|
418
418
|
end
|
|
419
419
|
```
|
data/docs/generated_modules.md
CHANGED
|
@@ -38,7 +38,7 @@ module PersonQuery
|
|
|
38
38
|
const :person, T.nilable(Person)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
extend GraphWeaver::QueryModule # client
|
|
41
|
+
extend GraphWeaver::QueryModule # client (see below)
|
|
42
42
|
def self.execute(id:, client: nil) # -> GraphWeaver::Response[Result]
|
|
43
43
|
def self.execute!(id:, client: nil) # -> Result, or raises QueryError
|
|
44
44
|
|
|
@@ -543,21 +543,20 @@ bodies. Every form above, and every error it raises, is a named example in
|
|
|
543
543
|
|
|
544
544
|
A client is anything satisfying the [execute contract](transports.md) — a
|
|
545
545
|
`GraphWeaver::Client`, a transport, a `Retry`, a live schema class, a fake.
|
|
546
|
-
|
|
547
|
-
`
|
|
548
|
-
[
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
own schema instead of having to be told which one you meant, and it is the
|
|
546
|
+
A module knows which graph it belongs to, and the graph knows how to reach it:
|
|
547
|
+
resolution is per call (`client:`) → a test mode's stand-in → the client its
|
|
548
|
+
[graph](getting_started.md#more-than-one-schema) names → `GraphWeaver.client`;
|
|
549
|
+
the canonical list is in [transports](transports.md#client-resolution). There is
|
|
550
|
+
no setter — `MyQuery.client` reads back what the module would execute through,
|
|
551
|
+
and a [parsed](#dynamic-mode) module, which has no graph, runs
|
|
552
|
+
against whatever parsed it. A graph naming its own client is no reason a module
|
|
553
|
+
escapes [testing's `graphql:` tag](testing.md), which is exactly the instruction
|
|
554
|
+
to replace it; what the *example* says still wins.
|
|
555
|
+
|
|
556
|
+
`client` lives in the gem (`GraphWeaver::QueryModule`, extended by every
|
|
557
|
+
generated module). A generated file says nothing about transport — only a private
|
|
558
|
+
`GRAPH` naming its graph, which is also how `graphql: :fake` fabricates each
|
|
559
|
+
module's own schema with two graphs in play, and the
|
|
561
560
|
`:graph` on every [instrumentation event](logging.md#the-payload) the module's
|
|
562
561
|
`execute` produces.
|
|
563
562
|
|
|
@@ -679,8 +678,9 @@ spot a *schema* change for you — `schema:diff`, `schema:refresh`, `queries:che
|
|
|
679
678
|
### Loading what it wrote
|
|
680
679
|
|
|
681
680
|
In Rails, loading is automatic — the Railtie requires every generated file at
|
|
682
|
-
|
|
683
|
-
|
|
681
|
+
the end of boot, after your initializers and after any registrations of your own
|
|
682
|
+
in a `to_prepare` block, and again after each development reload. Elsewhere it's
|
|
683
|
+
explicit, factory_bot-style:
|
|
684
684
|
`GraphWeaver.load_generated!` requires every file under `generated_paths`.
|
|
685
685
|
|
|
686
686
|
**Outside Rails, four things have to agree**, and nothing wires them together for
|
|
@@ -690,8 +690,8 @@ you — a script that generates its own modules sets all four:
|
|
|
690
690
|
2. `generated_paths` — where it writes, and where `load_generated!` reads. Point
|
|
691
691
|
them at the same directory or generation is invisible.
|
|
692
692
|
3. the call above, before the first `execute` — nothing else requires the files.
|
|
693
|
-
4. `GraphWeaver.client =` — a module
|
|
694
|
-
[
|
|
693
|
+
4. `GraphWeaver.client =` — a module belonging to no declared graph has no
|
|
694
|
+
other [client](#clients) to reach for.
|
|
695
695
|
|
|
696
696
|
Miss (3) and the script gets a `NameError` for its own module; miss (4) and it
|
|
697
697
|
gets `PersonQuery: client must respond to #execute(query, variables:), got
|
|
@@ -723,9 +723,16 @@ form: parse and execute in one call, no module kept. In development
|
|
|
723
723
|
`client.load_queries!` parses every query file into modules with the same names
|
|
724
724
|
generation would use.
|
|
725
725
|
|
|
726
|
+
A parsed module **runs against whatever parsed it** — `client.parse(query)` and
|
|
727
|
+
`load_queries!` bind the client they came from, and `GraphWeaver.parse(client:)`
|
|
728
|
+
says it outright. That is a property of parsing, not a slot you can set later:
|
|
729
|
+
it generates no file, so it has no graph to read a client off, and a per-call
|
|
730
|
+
`client:` still wins over it.
|
|
731
|
+
|
|
726
732
|
In an app with [more than one graph](getting_started.md#more-than-one-schema), a
|
|
727
733
|
parsed module belongs to one of them — that is what a `graphql:` tag runs it
|
|
728
|
-
against, the same thing generation
|
|
734
|
+
against and whose `client` it reaches for, the same thing generation writes into
|
|
735
|
+
a file. It is read off the schema
|
|
729
736
|
you parsed against when a graph runs that class in-process; say it outright
|
|
730
737
|
otherwise:
|
|
731
738
|
|
data/docs/getting_started.md
CHANGED
|
@@ -52,8 +52,8 @@ would drop the source url it records; delete it and re-run to re-introspect.
|
|
|
52
52
|
What it wrote:
|
|
53
53
|
|
|
54
54
|
- **`config/initializers/graph_weaver.rb`.** `GraphWeaver.client =` is the
|
|
55
|
-
load-bearing line: generated modules
|
|
56
|
-
at execute time (the full
|
|
55
|
+
load-bearing line: generated modules belonging to no declared graph resolve to
|
|
56
|
+
it at execute time (the full
|
|
57
57
|
[resolution order](transports.md#client-resolution)). Custom
|
|
58
58
|
scalars/enums/type helpers register here too — the rake tasks bake them into
|
|
59
59
|
generated source, so they have to run first ([scalars](scalars.md)):
|
|
@@ -99,8 +99,9 @@ What it wrote:
|
|
|
99
99
|
|
|
100
100
|
Rake needs no wiring: in Rails the `graph_weaver:*` tasks register themselves and
|
|
101
101
|
depend on `:environment`, so your initializer runs first. The generated modules
|
|
102
|
-
load at
|
|
103
|
-
already in place when the
|
|
102
|
+
load at the end of boot, after your initializers and after any `to_prepare`
|
|
103
|
+
block of yours, so a helper or enum you registered is already in place when the
|
|
104
|
+
file that names it loads.
|
|
104
105
|
|
|
105
106
|
All of that describes **one** schema, which is the usual case; an app with a
|
|
106
107
|
second one declares each as a graph ([more than one
|
|
@@ -428,7 +429,7 @@ plus `register_scalar`, `register_enum` and `extend_type`).
|
|
|
428
429
|
| `schema` | a graphql-ruby schema class, a [`Client`](transports.md), a path to a dump, SDL, or a lambda returning one |
|
|
429
430
|
| `queries` | a directory, or a list of them — the `.graphql` files this graph generates from |
|
|
430
431
|
| `output` | one directory — where this graph's generated Ruby is written |
|
|
431
|
-
| `client` | a
|
|
432
|
+
| `client` | what this graph's modules execute against — a client, or the name of the constant holding one |
|
|
432
433
|
| `namespace` | a constant, or its name — what every constant this graph generates nests under |
|
|
433
434
|
| `types_module` | a constant name for the shared types module (default: `GraphQLTypes`, under `namespace`) |
|
|
434
435
|
|
|
@@ -447,14 +448,14 @@ GraphWeaver.graph :app do
|
|
|
447
448
|
end
|
|
448
449
|
```
|
|
449
450
|
|
|
450
|
-
**`client`
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
451
|
+
**`client` is where this graph's endpoint lives** — its modules say which graph
|
|
452
|
+
they belong to and nothing about transport, so they read it when they execute.
|
|
453
|
+
A graph with no `client` falls back to `GraphWeaver.client`, the app default.
|
|
454
|
+
Name the object (`client GraphWeaver.new(url, auth: …)`) or, when the constant
|
|
455
|
+
holding it is defined later than the graph block, its name (`client "GITHUB"`),
|
|
456
|
+
which is resolved on first use. `schema "x"` sets and a bare `schema` reads
|
|
457
|
+
back; there is no `schema = "x"` form, since the block is `instance_eval`'d and
|
|
458
|
+
that would be a local variable that silently does nothing.
|
|
458
459
|
|
|
459
460
|
**`namespace` nests everything that graph generates** — `person.graphql` becomes
|
|
460
461
|
`Billing::PersonQuery` ([naming](generated_modules.md#naming)). Constants are
|
data/docs/testing.md
CHANGED
|
@@ -36,8 +36,8 @@ it "sends the caller tag", graphql: :wire do … end
|
|
|
36
36
|
There is nothing else to set up: each mode works out what to run against per
|
|
37
37
|
graph, and [refuses rather than guessing](#nothing-to-configure). The tag
|
|
38
38
|
installs a stand-in per graph, and every generated module of that graph runs
|
|
39
|
-
against it — including one
|
|
40
|
-
|
|
39
|
+
against it — including one whose graph names a `client` of its own, since that
|
|
40
|
+
is exactly what the tag means to replace. `rspec --tag graphql:router`
|
|
41
41
|
runs one mode's examples.
|
|
42
42
|
|
|
43
43
|
**Every example has exactly one mode.** An untagged one takes
|
|
@@ -50,7 +50,8 @@ whatever the example did to it, so building your own client is a plain
|
|
|
50
50
|
assignment: `before { GraphWeaver.client = GraphWeaver::Testing::Failure.throttled }`.
|
|
51
51
|
Do both at once and **the tag wins**: the assignment reads back while the modules
|
|
52
52
|
keep using the mode. Two things do step out of a tag — a per-call `client:`, and
|
|
53
|
-
|
|
53
|
+
a module [parsed](generated_modules.md#dynamic-mode) from a client of its own,
|
|
54
|
+
which runs against that client
|
|
54
55
|
([client resolution](transports.md#client-resolution) has the full order).
|
|
55
56
|
|
|
56
57
|
**The half `:fake` can't reach** is refusal. It fabricates a shape-correct
|
|
@@ -340,10 +341,10 @@ suite. The tag adds one stub per endpoint and takes each back after the example
|
|
|
340
341
|
it never disables net connections on your behalf, and never resets stubs it
|
|
341
342
|
didn't make.
|
|
342
343
|
|
|
343
|
-
**Every endpoint an example can reach is served**, one per graph: the client
|
|
344
|
-
[declared graph](getting_started.md#more-than-one-schema)
|
|
345
|
-
|
|
346
|
-
billing
|
|
344
|
+
**Every endpoint an example can reach is served**, one per graph: the `client`
|
|
345
|
+
each [declared graph](getting_started.md#more-than-one-schema) names, or
|
|
346
|
+
`GraphWeaver.client` for a graph naming none — so a billing module posts to
|
|
347
|
+
billing's url and is answered by billing's schema. What
|
|
347
348
|
sits behind each is **what that graph is**, in descending faithfulness: that
|
|
348
349
|
graph's [router](#a-federated-graph--graphql-router) when it is in a composed
|
|
349
350
|
supergraph, its [live schema class](#real-resolvers--graphql-in_process) when it
|
|
@@ -352,8 +353,8 @@ that is a pure *client* of someone else's API gets a schema-correct server
|
|
|
352
353
|
without writing one. A graph with no schema at all is refused, **by `:wire`'s own
|
|
353
354
|
name** — the one fallback the other tags have and this one can't use is your
|
|
354
355
|
client's own schema, since reading it means introspecting the endpoint `:wire`
|
|
355
|
-
has just stubbed. Commit a dump, or set `config.schema`. A graph whose
|
|
356
|
-
|
|
356
|
+
has just stubbed. Commit a dump, or set `config.schema`. A graph whose `client`
|
|
357
|
+
posts nowhere is refused by name too.
|
|
357
358
|
|
|
358
359
|
**It says which, on the logger** — the choice is the one thing this tag makes for
|
|
359
360
|
you, and it is invisible from inside the example. One line per endpoint, at
|
|
@@ -542,11 +543,13 @@ rather than guessing**:
|
|
|
542
543
|
[maps subgraphs](federation.md#which-schema-serves-which-subgraph).
|
|
543
544
|
- **`:router`** plans against the composed supergraph **that graph** names, else
|
|
544
545
|
`config.router = { supergraph: … }`, else the committed dump when *that*
|
|
545
|
-
carries `@join__*` markers
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
546
|
+
carries `@join__*` markers, else the dump your own client was built from
|
|
547
|
+
(`GraphWeaver.new("supergraph.graphql")`) — which for a federated app is
|
|
548
|
+
usually no config at all. A graph that is in no supergraph is refused **by
|
|
549
|
+
name**, rather than planned against another graph's. A client's *schema* can't
|
|
550
|
+
stand in for one — it is the API schema the router serves, with the `@join__*`
|
|
551
|
+
routing table stripped out — but the file it was read from carries the table.
|
|
552
|
+
Subgraphs are derived either way.
|
|
550
553
|
|
|
551
554
|
So configure only to override a derivation, or to tune fabricated values — in the
|
|
552
555
|
same file as the require, since support files load in sorted order and one naming
|
data/docs/transports.md
CHANGED
|
@@ -37,8 +37,8 @@ applied (exposed as `client.transport`), the schema introspected lazily, and
|
|
|
37
37
|
|
|
38
38
|
They combine, so the whole thing is still one call —
|
|
39
39
|
`GraphWeaver.new(url, transport: :faraday, retries: 2) { |conn| conn.response :logger }`.
|
|
40
|
-
To wire generated modules
|
|
41
|
-
`GraphWeaver.client = github`.
|
|
40
|
+
To wire generated modules belonging to no declared graph, make it the app's
|
|
41
|
+
default: `GraphWeaver.client = github`.
|
|
42
42
|
|
|
43
43
|
## What fills the client slot
|
|
44
44
|
|
|
@@ -202,22 +202,29 @@ APM payload gets ([errors](errors.md)).
|
|
|
202
202
|
|
|
203
203
|
## Client resolution
|
|
204
204
|
|
|
205
|
+
A module knows which graph it belongs to, and the graph knows how to reach it.
|
|
205
206
|
The canonical order — how a generated module finds its client (each slot takes a
|
|
206
207
|
`Client` or any bare transport/fake):
|
|
207
208
|
|
|
208
209
|
1. per call: `execute(client: some_client, ...)` — a kwarg like the variables, and
|
|
209
210
|
a name no GraphQL variable is allowed to take
|
|
210
|
-
2.
|
|
211
|
-
3. a test mode's stand-in: under `graphql: :fake` / `:in_process` / `:router`,
|
|
211
|
+
2. a test mode's stand-in: under `graphql: :fake` / `:in_process` / `:router`,
|
|
212
212
|
built from the graph this module was generated from
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
5. the app default: `GraphWeaver.client=`
|
|
213
|
+
3. the client its [graph](getting_started.md#more-than-one-schema) names
|
|
214
|
+
4. the app default: `GraphWeaver.client=`
|
|
216
215
|
|
|
217
|
-
The mode replaces what
|
|
218
|
-
|
|
216
|
+
The mode replaces what the graph says, not what your example said — 1 still
|
|
217
|
+
wins. Nothing set anywhere raises, naming the two you'd usually reach for:
|
|
219
218
|
`no client configured — set GraphWeaver.client= or pass a client`.
|
|
220
219
|
|
|
220
|
+
**A [parsed](generated_modules.md#dynamic-mode) module isn't in that list**: it generates no
|
|
221
|
+
file, so it has no graph, and it runs against whatever parsed it —
|
|
222
|
+
`client.parse(query)`, `load_queries!`, or `GraphWeaver.parse(client:)`. That
|
|
223
|
+
binding sits directly under the per-call `client:`, above even a test mode's
|
|
224
|
+
stand-in, and is the only one there is: `MyQuery.client` reads back what a
|
|
225
|
+
module would execute through, but there is no setter for it. A module's client
|
|
226
|
+
comes from its graph, its parser, or the call.
|
|
227
|
+
|
|
221
228
|
## Retries
|
|
222
229
|
|
|
223
230
|
A url client retries when you give it a count; the rest of the options sit beside
|
data/docs/upgrading.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# Upgrading
|
|
2
2
|
|
|
3
3
|
[Regenerate](#regenerate-on-every-upgrade) whichever version you're on, then read
|
|
4
|
-
the one section that is yours: from [0.7.
|
|
5
|
-
[0.
|
|
6
|
-
version's own upgrade notes — read them at the
|
|
7
|
-
(`git show v0.7.1:docs/upgrading.md`), then this page from
|
|
4
|
+
the one section that is yours: from [0.7.1](#upgrading-from-071), from
|
|
5
|
+
[0.7.0](#upgrading-from-070) or from [0.6.1](#upgrading-from-061). Coming from
|
|
6
|
+
0.6.0 or older, the path is that version's own upgrade notes — read them at the
|
|
7
|
+
tag they shipped under (`git show v0.7.1:docs/upgrading.md`), then this page from
|
|
8
|
+
0.6.1 down.
|
|
8
9
|
|
|
9
10
|
## Regenerate on every upgrade
|
|
10
11
|
|
|
@@ -22,6 +23,28 @@ That's the reminder working, not a false alarm. Generation is deterministic, so
|
|
|
22
23
|
the diff is exactly what the new version emits differently and nothing else —
|
|
23
24
|
worth reading rather than rubber-stamping.
|
|
24
25
|
|
|
26
|
+
## Upgrading from 0.7.1
|
|
27
|
+
|
|
28
|
+
A patch release, and one change with a shape: a generated module no longer
|
|
29
|
+
carries a client of its own — the graph it belongs to resolves one. Read the
|
|
30
|
+
left column and skip what isn't yours; the [changelog](../CHANGELOG.md) says why
|
|
31
|
+
each one moved.
|
|
32
|
+
|
|
33
|
+
| applies if you… | what changed |
|
|
34
|
+
|---|---|
|
|
35
|
+
| call `generate!`, `verify_generated!`, `Codegen.new` or `Codegen.generate` yourself — `grep -rn "client:" config lib Rakefile` | the `client:` kwarg is gone, and the call raises `unknown keyword: :client`. Say it once on the graph (`client` in a `GraphWeaver.graph` block), or as the app default (`GraphWeaver.client =`) for modules in no declared graph. `Graph#client` answers that object now, not the name of the constant holding it |
|
|
36
|
+
| assign a generated module's client — `grep -rn "\.client *=" app config lib` (a hit on `GraphWeaver.client =` is the app default, and still fine) | the writer is private, and `MyQuery.client = …` raises `NoMethodError`. A module's client comes from its graph, from `client:` on the call, or — for a module you parsed — from `GraphWeaver.parse(client:)`, which `client.parse` and `load_queries!` already pass |
|
|
37
|
+
|
|
38
|
+
Then regenerate, and the gate:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
# generated files no longer carry a DEFAULT_CLIENT
|
|
42
|
+
rake graph_weaver:generate
|
|
43
|
+
|
|
44
|
+
# red while any checked-in file is still what 0.7.1 wrote
|
|
45
|
+
rake graph_weaver:verify
|
|
46
|
+
```
|
|
47
|
+
|
|
25
48
|
## Upgrading from 0.7.0
|
|
26
49
|
|
|
27
50
|
A patch release of fixes, and a typical app ticks none of these. Read the left
|
|
@@ -167,7 +190,7 @@ only one here that shows up in production rather than in your code.
|
|
|
167
190
|
- **A `graphql:` tag reaches a module generated with `client:`.** The baked client
|
|
168
191
|
used to sit above the slot a tag swaps, so a bound module ran against its real
|
|
169
192
|
endpoint under `graphql: :fake`. **If a spec relied on that**, pass `client:` on
|
|
170
|
-
the call,
|
|
193
|
+
the call, or tag the example `graphql: :live`.
|
|
171
194
|
- **`config.context`, `config.schema` and `config.router` are suite setup.**
|
|
172
195
|
Setting any of the three once an example is running refuses, naming the
|
|
173
196
|
per-example helper (`graphql_context`, `graphql_fake(schema:)`,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
# Generated by GraphWeaver 0.7.
|
|
4
|
+
# Generated by GraphWeaver 0.7.3 — do not edit.
|
|
5
5
|
|
|
6
6
|
module StarMutation
|
|
7
7
|
extend T::Sig
|
|
@@ -79,11 +79,11 @@ module StarMutation
|
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
-
# client
|
|
82
|
+
# client — see GraphWeaver::QueryModule
|
|
83
83
|
extend GraphWeaver::QueryModule
|
|
84
84
|
|
|
85
|
-
# the graph this module was generated from —
|
|
86
|
-
# its stand-in
|
|
85
|
+
# the graph this module was generated from — whose client it runs
|
|
86
|
+
# against, and what a test mode builds its stand-in from
|
|
87
87
|
GRAPH = T.let(:github, Symbol)
|
|
88
88
|
private_constant :GRAPH
|
|
89
89
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
# Generated by GraphWeaver 0.7.
|
|
4
|
+
# Generated by GraphWeaver 0.7.3 — do not edit.
|
|
5
5
|
|
|
6
6
|
require "time"
|
|
7
7
|
|
|
@@ -183,11 +183,11 @@ module StargazersQuery
|
|
|
183
183
|
end
|
|
184
184
|
end
|
|
185
185
|
|
|
186
|
-
# client
|
|
186
|
+
# client — see GraphWeaver::QueryModule
|
|
187
187
|
extend GraphWeaver::QueryModule
|
|
188
188
|
|
|
189
|
-
# the graph this module was generated from —
|
|
190
|
-
# its stand-in
|
|
189
|
+
# the graph this module was generated from — whose client it runs
|
|
190
|
+
# against, and what a test mode builds its stand-in from
|
|
191
191
|
GRAPH = T.let(:github, Symbol)
|
|
192
192
|
private_constant :GRAPH
|
|
193
193
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
# Generated by GraphWeaver 0.7.
|
|
4
|
+
# Generated by GraphWeaver 0.7.3 — do not edit.
|
|
5
5
|
|
|
6
6
|
module StarredQuery
|
|
7
7
|
extend T::Sig
|
|
@@ -103,11 +103,11 @@ module StarredQuery
|
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
# client
|
|
106
|
+
# client — see GraphWeaver::QueryModule
|
|
107
107
|
extend GraphWeaver::QueryModule
|
|
108
108
|
|
|
109
|
-
# the graph this module was generated from —
|
|
110
|
-
# its stand-in
|
|
109
|
+
# the graph this module was generated from — whose client it runs
|
|
110
|
+
# against, and what a test mode builds its stand-in from
|
|
111
111
|
GRAPH = T.let(:github, Symbol)
|
|
112
112
|
private_constant :GRAPH
|
|
113
113
|
|
data/lib/graph_weaver/client.rb
CHANGED
|
@@ -77,6 +77,10 @@ class GraphWeaver::Client
|
|
|
77
77
|
# a live schema class doubles as an in-process transport; a loaded
|
|
78
78
|
# dump has no resolvers, so it is type information only
|
|
79
79
|
@schema = source.is_a?(Module) ? source : GraphWeaver::SchemaLoader.load(source)
|
|
80
|
+
# A supergraph's routing table lives in the file, not in the loaded
|
|
81
|
+
# schema, so the path is the only thing that can name one later. Told
|
|
82
|
+
# from SDL by its extension, as SchemaLoader tells it.
|
|
83
|
+
@schema_source = source if !source.is_a?(Module) && GraphWeaver::SchemaLoader.dump_path?(source)
|
|
80
84
|
|
|
81
85
|
if context && !(source.is_a?(Module) && transport.nil?)
|
|
82
86
|
# nothing would ever read it — a dump has no resolvers, and an
|
|
@@ -122,6 +126,10 @@ class GraphWeaver::Client
|
|
|
122
126
|
# schema-dump clients (type information only).
|
|
123
127
|
attr_reader :transport
|
|
124
128
|
|
|
129
|
+
# The dump this client's schema was read from, or nil for a url, a schema
|
|
130
|
+
# class, or inline SDL. What a graph named by this client is named by.
|
|
131
|
+
attr_reader :schema_source
|
|
132
|
+
|
|
125
133
|
# transport, when this client must be able to execute
|
|
126
134
|
private def transport!
|
|
127
135
|
transport or raise GraphWeaver::Error,
|
|
@@ -456,22 +456,16 @@ class GraphWeaver::Codegen
|
|
|
456
456
|
end
|
|
457
457
|
|
|
458
458
|
def emit_execute(out, variables)
|
|
459
|
-
# client
|
|
460
|
-
out << " # client
|
|
459
|
+
# client carries no per-query types, so it lives in the gem
|
|
460
|
+
out << " # client — see GraphWeaver::QueryModule"
|
|
461
461
|
out << " extend GraphWeaver::QueryModule"
|
|
462
462
|
if @graph_name
|
|
463
463
|
out << ""
|
|
464
|
-
out << " # the graph this module was generated from —
|
|
465
|
-
out << " # its stand-in
|
|
464
|
+
out << " # the graph this module was generated from — whose client it runs"
|
|
465
|
+
out << " # against, and what a test mode builds its stand-in from"
|
|
466
466
|
out << " GRAPH = T.let(#{@graph_name.inspect}, Symbol)"
|
|
467
|
-
out << " private_constant :GRAPH"
|
|
468
|
-
end
|
|
469
|
-
if @client_const
|
|
470
|
-
out << ""
|
|
471
|
-
out << " # the baked default client, resolved on first use"
|
|
472
|
-
out << " DEFAULT_CLIENT = T.let(-> { #{@client_const} }, T.proc.returns(T.untyped))"
|
|
473
467
|
# QueryModule reads it with const_get, which privacy doesn't block
|
|
474
|
-
out << " private_constant :
|
|
468
|
+
out << " private_constant :GRAPH"
|
|
475
469
|
end
|
|
476
470
|
out << ""
|
|
477
471
|
|