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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0ae9c23b2566bfa26c786e07703e4fad357cbd09a29112d3e0c9dd5d3af916c
4
- data.tar.gz: fb5f4534174e5ba9cb7b9d323af26c2a13456c022f8682bcc3ccae5e512a1c96
3
+ metadata.gz: 653ecbcc2215bf5358e34bc83d701ded874a6ee1910ceeca18f0ed205a44798f
4
+ data.tar.gz: 2d1e49f247e84347c7bd86123b54b1b9d31d8978bc2a6a8f8d9538342c3ab67d
5
5
  SHA512:
6
- metadata.gz: dc780e4f155ea89b9977822a7bb62ed9880d3b7e707fd5046229b1c91c843a9c1ec37c39fb5e2039e71c9095dfb7a0df006347a19ce4544f75f2b3fe13a35a5c
7
- data.tar.gz: 3dcc86b06e670408ebc18eaaaad7447d5825d1d580b9640ed8860133ba29908eb42553d52da4a2619eb23f072f4999f5aceb622271fafc8d5431fd57a3106ed3
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.1)
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.2.0)
199
- sorbet (0.6.13485)
200
- sorbet-static (= 0.6.13485)
201
- sorbet-runtime (0.6.13485)
202
- sorbet-static (0.6.13485-aarch64-linux)
203
- sorbet-static (0.6.13485-universal-darwin)
204
- sorbet-static (0.6.13485-x86_64-linux)
205
- sorbet-static-and-runtime (0.6.13485)
206
- sorbet (= 0.6.13485)
207
- sorbet-runtime (= 0.6.13485)
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.1)
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.2.0) sha256=ea6acd05eece5a41990e2a5171c57d15700d329326c7666c85ee8c6a0dd0977e
354
- sorbet (0.6.13485) sha256=b885d6a2fcde57bc46c3cdd597b9014b82619dee0f811a6fdf36f57c8f82c380
355
- sorbet-runtime (0.6.13485) sha256=2982504e662eb424e515b3aa1c8139070451a014b6c1af2302250ed82495b4cc
356
- sorbet-static (0.6.13485-aarch64-linux) sha256=5d802793633363442f189615fdb6c6d1be726b402d78a3d63eab96ca74b98d40
357
- sorbet-static (0.6.13485-universal-darwin) sha256=6c7c4551872d556b37bf1f1a3495509b9fd9479b4a080bd57f9c5db0e8116658
358
- sorbet-static (0.6.13485-x86_64-linux) sha256=e22d88df0bba5a97e664a329a2212ea59e6a2020626597a162c60c5ddfb4f9b4
359
- sorbet-static-and-runtime (0.6.13485) sha256=b893346f9e1a244133071ad3c3d06b8ddf70c1b8246bb594c9aaa5cfc778df5f
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: `Testing.config.router =
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 the committed dump when *that* is. Two graphs may name one
136
- supergraph; two naming different ones is refused rather than picked between.
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 "Reviews::Schema"
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 "PLATFORM"
416
+ client GraphWeaver.new(ENV.fetch("PLATFORM_GRAPHQL_URL"))
417
417
  namespace "Platform"
418
418
  end
419
419
  ```
@@ -38,7 +38,7 @@ module PersonQuery
38
38
  const :person, T.nilable(Person)
39
39
  end
40
40
 
41
- extend GraphWeaver::QueryModule # client / client= (see below)
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
- Resolution is per call (`client:`) per module baked constant
547
- `GraphWeaver.client`; the canonical list is in
548
- [transports](transports.md#client-resolution). Generate *without* a baked
549
- constant when you want modules to follow the app default (`GraphWeaver.client =`
550
- in an initializer). A baked one is no reason a module escapes
551
- [testing's `graphql:` tag](testing.md), which is exactly the instruction to
552
- replace the client generation chose; what the *example* says still wins.
553
-
554
- `client`/`client=` live in the gem (`GraphWeaver::QueryModule`, extended by every
555
- generated module). A baked constant is emitted as a private `DEFAULT_CLIENT`,
556
- resolved on first use so a module can load before the initializer that builds its
557
- client. A module generated from a
558
- [declared graph](getting_started.md#more-than-one-schema) also carries a private
559
- `GRAPH` naming it — so with two graphs, `graphql: :fake` fabricates each module's
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
- boot from a `to_prepare` block, after your initializers and after any
683
- registrations of your own in one. Elsewhere it's explicit, factory_bot-style:
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 generated without a baked
694
- [`client:`](#clients) has none of its own.
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 bakes into a file. It is read off the schema
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
 
@@ -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 without a baked transport resolve to it
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 boot from a `to_prepare` block, so a helper or enum you registered is
103
- already in place when the file that names it loads.
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 constant, or its name what this graph's modules execute against |
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` names a constant, not a url** — its value is spelled into every module
451
- this graph generates and resolved the first time one of them executes, so it has
452
- to be something generated source can write down. Build the client wherever you
453
- like (`GITHUB = GraphWeaver.new(url, auth: …)`) and put the constant holding it
454
- here. A graph with no `client` generates modules that fall back to
455
- `GraphWeaver.client`, the app default. `schema "x"` sets and a bare `schema`
456
- reads back; there is no `schema = "x"` form, since the block is `instance_eval`'d
457
- and that would be a local variable that silently does nothing.
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 generated *with* a baked `client:`, since that
40
- constant is exactly what the tag means to replace. `rspec --tag graphql:router`
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
- `DashboardQuery.client =` on the module itself
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 each
344
- [declared graph](getting_started.md#more-than-one-schema) bakes into its modules
345
- with `client:`, or `GraphWeaver.client` for a graph that bakes none — so a
346
- billing module posts to billing's url and is answered by billing's schema. What
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 baked
356
- client posts nowhere is refused by name too.
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 which for a federated app is usually no config at
546
- all. A graph that is in no supergraph is refused **by name**, rather than
547
- planned against another graph's. A client can't stand in for one: a client's
548
- schema is the API schema the router serves, with the `@join__*` routing table
549
- stripped out. Subgraphs are derived either way.
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 that don't bake a client, make it the app's default:
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. per module: `MyQuery.client = something`
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
- 4. baked constant: `Codegen.generate(..., client: "MyApi::CLIENT")` — the
214
- constant's *name*, not the object, because generated source spells it
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 codegen baked in, not what your example said — 1 and 2
218
- still win. Nothing set anywhere raises, naming the two you'd usually reach for:
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.0](#upgrading-from-070) or from
5
- [0.6.1](#upgrading-from-061). Coming from 0.6.0 or older, the path is that
6
- version's own upgrade notes — read them at the tag they shipped under
7
- (`git show v0.7.1:docs/upgrading.md`), then this page from 0.6.1 down.
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, set `MyQuery.client =`, or tag the example `graphql: :live`.
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.0 — do not edit.
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 / client= — see GraphWeaver::QueryModule
82
+ # client — see GraphWeaver::QueryModule
83
83
  extend GraphWeaver::QueryModule
84
84
 
85
- # the graph this module was generated from — what a test mode builds
86
- # its stand-in client from
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.0 — do not edit.
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 / client= — see GraphWeaver::QueryModule
186
+ # client — see GraphWeaver::QueryModule
187
187
  extend GraphWeaver::QueryModule
188
188
 
189
- # the graph this module was generated from — what a test mode builds
190
- # its stand-in client from
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.0 — do not edit.
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 / client= — see GraphWeaver::QueryModule
106
+ # client — see GraphWeaver::QueryModule
107
107
  extend GraphWeaver::QueryModule
108
108
 
109
- # the graph this module was generated from — what a test mode builds
110
- # its stand-in client from
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
 
@@ -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/client= carry no per-query types, so they live in the gem
460
- out << " # client / client= — see GraphWeaver::QueryModule"
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 — what a test mode builds"
465
- out << " # its stand-in client from"
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 :DEFAULT_CLIENT"
468
+ out << " private_constant :GRAPH"
475
469
  end
476
470
  out << ""
477
471