File: schema.rb

package info (click to toggle)
ruby-graphql 2.2.17-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,584 kB
  • sloc: ruby: 67,505; ansic: 1,753; yacc: 831; javascript: 331; makefile: 6
file content (373 lines) | stat: -rw-r--r-- 10,198 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# frozen_string_literal: true
module StarTrek
  # Adapted from graphql-relay-js
  # https://github.com/graphql/graphql-relay-js/blob/master/src/__tests__/StarTrekSchema.js

  class Ship < GraphQL::Schema::Object
    implements GraphQL::Types::Relay::Node
    global_id_field :id
    field :name, String
    # Test cyclical connection types:
    field :ships, Ship.connection_type, null: false
  end

  class ResidentType < GraphQL::Schema::Object
    global_id_field :id
    field :name, String
  end

  class BaseType < GraphQL::Schema::Object
    graphql_name "Base"
    implements GraphQL::Types::Relay::Node
    global_id_field :id
    field :name, String, null: false

    def name
      LazyWrapper.new {
        if object.id.nil?
          raise GraphQL::ExecutionError, "Boom!"
        else
          object.name
        end
      }
    end

    field :sector, String
    field :residents, ResidentType.connection_type
  end

  class BaseConnectionWithTotalCountType < GraphQL::Types::Relay::BaseConnection
    graphql_name "BasesConnectionWithTotalCount"
    edge_type(BaseType.edge_type)
    field :total_count, Integer

    def total_count
      object.items.count
    end
  end

  class CustomBaseEdge < GraphQL::Pagination::Connection::Edge
    def upcased_name
      node.name.upcase
    end

    def upcased_parent_name
      parent.name.upcase
    end
  end

  class CustomBaseEdgeType < GraphQL::Types::Relay::BaseEdge
    node_type(BaseType)
    field :upcased_name, String
    field :upcased_parent_name, String
    field :edge_class_name, String

    def edge_class_name
      object.class.name
    end
  end

  class CustomEdgeBaseConnectionType < GraphQL::Types::Relay::BaseConnection
    edge_type(CustomBaseEdgeType, edge_class: CustomBaseEdge)

    field :total_count_times_100, Integer
    def total_count_times_100
      obj.items.to_a.count * 100
    end

    field :field_name, String
    def field_name
      object.field.name
    end
  end

  class ShipsWithMaxPageSize < GraphQL::Schema::Resolver
    argument :name_includes, String, required: false
    type Ship.connection_type, null: true

    def resolve(name_includes: nil)
      all_ships = object.ships.map { |ship_id| StarTrek::DATA["Ship"][ship_id] }
      if name_includes
        all_ships = all_ships.select { |ship| ship.name.include?(name_includes)}
      end
      all_ships
    end
  end

  class ShipConnectionWithParentType < GraphQL::Types::Relay::BaseConnection
    edge_type(Ship.edge_type)
    graphql_name "ShipConnectionWithParent"
    field :parent_class_name, String, null: false
    def parent_class_name
      object.parent.class.name
    end
  end

  class Faction < GraphQL::Schema::Object
    implements GraphQL::Types::Relay::Node
    field :name, String
    field :ships, ShipConnectionWithParentType, connection: true, max_page_size: 1000, null: true do
      argument :name_includes, String, required: false
    end

    def ships(name_includes: nil)
      all_ships = object.ships.map {|ship_id| StarTrek::DATA["Ship"][ship_id] }
      if name_includes
        case name_includes
        when "error"
          all_ships = GraphQL::ExecutionError.new("error from within connection")
        when "raisedError"
          raise GraphQL::ExecutionError.new("error raised from within connection")
        when "lazyError"
          all_ships = LazyWrapper.new { GraphQL::ExecutionError.new("lazy error from within connection") }
        when "lazyRaisedError"
          all_ships = LazyWrapper.new { raise GraphQL::ExecutionError.new("lazy raised error from within connection") }
        when "null"
          all_ships = nil
        when "lazyObject"
          prev_all_ships = all_ships
          all_ships = LazyWrapper.new { prev_all_ships }
        else
          all_ships = all_ships.select { |ship| ship.name.include?(name_includes)}
        end
      end
      all_ships
    end

    field :shipsWithMaxPageSize, "Ships with max page size", max_page_size: 2, resolver: ShipsWithMaxPageSize

    field :bases, BaseConnectionWithTotalCountType, connection: true do
      argument :name_includes, String, required: false
    end

    def bases(name_includes: nil)
      all_bases = object.bases
      if name_includes
        all_bases = all_bases.where(name: Regexp.new(name_includes))
      end
      all_bases
    end

    field :bases_clone, BaseType.connection_type
    field :bases_by_name, BaseType.connection_type do
      argument :order, String, default_value: "name", required: false
    end
    def bases_by_name(order: nil)
      if order.present?
        @object.bases.order_by(name: order)
      else
        @object.bases
      end
    end

    def all_bases
      Base.all
    end

    def all_bases_array
      all_bases.to_a
    end

    field :basesWithMaxLimitRelation, BaseType.connection_type, max_page_size: 2, resolver_method: :all_bases
    field :basesWithMaxLimitArray, BaseType.connection_type, max_page_size: 2, resolver_method: :all_bases_array
    field :basesWithDefaultMaxLimitRelation, BaseType.connection_type, resolver_method: :all_bases
    field :basesWithDefaultMaxLimitArray, BaseType.connection_type, resolver_method: :all_bases_array
    field :basesWithLargeMaxLimitRelation, BaseType.connection_type, max_page_size: 1000, resolver_method: :all_bases

    field :bases_with_custom_edge, CustomEdgeBaseConnectionType, connection: true
    def bases_with_custom_edge
      LazyNodesWrapper.new(object.bases)
    end
  end

  class IntroduceShipMutation < GraphQL::Schema::RelayClassicMutation
    description "Add a ship to this faction"

    # Nested under `input` in the query:
    argument :ship_name, String, required: false
    argument :faction_id, ID

    # Result may have access to these fields:
    field :ship_edge, Ship.edge_type
    field :faction, Faction
    field :aliased_faction, Faction, hash_key: :aliased_faction, null: true

    def resolve(ship_name: nil, faction_id:)
      if ship_name == 'USS Voyager'
        GraphQL::ExecutionError.new("Sorry, USS Voyager ship is reserved")
      elsif ship_name == 'IKS Korinar'
        raise GraphQL::ExecutionError.new("🔥")
      elsif ship_name == 'Scimitar'
        LazyWrapper.new { raise GraphQL::ExecutionError.new("💥")}
      end
    end
  end

  # GraphQL-Batch knockoff
  class LazyLoader
    def self.defer(ctx, model, id)
      ids = ctx.namespace(:loading)[model] ||= []
      ids << id
      self.new(model: model, id: id, context: ctx)
    end

    def initialize(model:, id:, context:)
      @model = model
      @id = id
      @context = context
    end

    def value
      loaded = @context.namespace(:loaded)[@model] ||= {}
      if loaded.empty?
        ids = @context.namespace(:loading)[@model]
        # Example custom tracing
        @context.trace("lazy_loader", { ids: ids, model: @model}) do
          records = @model.where(id: ids)
          records.each do |record|
            loaded[record.id.to_s] = record
          end
        end
      end

      loaded[@id]
    end
  end

  class LazyWrapper
    def initialize(value = nil, &block)
      if block_given?
        @lazy_value = block
      else
        @value = value
      end
    end

    def value
      @resolved_value = @value || @lazy_value.call
    end
  end

  LazyNodesWrapper = Struct.new(:relation)
  class LazyNodesRelationConnection < GraphQL::Pagination::MongoidRelationConnection
    def initialize(wrapper, *args)
      super(wrapper.relation, *args)
    end

    def edge_nodes
      LazyWrapper.new { super }
    end
  end

  class QueryType < GraphQL::Schema::Object
    graphql_name "Query"

    field :federation, Faction

    def federation
      StarTrek::DATA["Faction"]["1"]
    end

    field :klingons, Faction
    def klingons
      StarTrek::DATA["Faction"]["2"]
    end

    field :romulans, Faction

    def romulans
      StarTrek::DATA["Faction"]["3"]
    end

    field :largest_base, BaseType

    def largest_base
      Base.find(3)
    end

    field :newest_bases_grouped_by_faction, BaseType.connection_type

    def newest_bases_grouped_by_faction
      agg = Base.collection.aggregate([{
        "$group" => {
          "_id" => "$faction_id",
          "baseId" => { "$max" => "$_id" }
        }
      }])
      Base.
        in(id: agg.map { |doc| doc['baseId'] }).
        order_by(faction_id: -1)
    end

    field :bases_with_null_name, BaseType.connection_type, null: false

    def bases_with_null_name
      [OpenStruct.new(id: nil)]
    end

    include GraphQL::Types::Relay::HasNodeField

    field :node_with_custom_resolver, GraphQL::Types::Relay::Node do
      argument :id, ID
    end
    def node_with_custom_resolver(id:)
      StarTrek::DATA["Faction"]["1"]
    end

    include GraphQL::Types::Relay::HasNodesField

    field :nodes_with_custom_resolver, [GraphQL::Types::Relay::Node, null: true] do
      argument :ids, [ID]
    end
    def nodes_with_custom_resolver(ids:)
      [StarTrek::DATA["Faction"]["1"], StarTrek::DATA["Faction"]["2"]]
    end

    field :batched_base, BaseType do
      argument :id, ID
    end

    def batched_base(id:)
      LazyLoader.defer(@context, Base, id)
    end
  end

  class MutationType < GraphQL::Schema::Object
    graphql_name "Mutation"
    field :introduceShip, mutation: IntroduceShipMutation
  end

  class Schema < GraphQL::Schema
    query(QueryType)
    mutation(MutationType)
    default_max_page_size 3

    def self.resolve_type(type, object, ctx)
      if object == :test_error
        :not_a_type
      elsif object.is_a?(Base)
        BaseType
      elsif DATA["Faction"].values.include?(object)
        Faction
      elsif DATA["Ship"].values.include?(object)
        Ship
      else
        nil
      end
    end

    connections.add(LazyNodesWrapper, LazyNodesRelationConnection)

    def self.object_from_id(node_id, ctx)
      type_name, id = GraphQL::Schema::UniqueWithinType.decode(node_id)
      StarTrek::DATA[type_name][id]
    end

    def self.id_from_object(object, type, ctx)
      GraphQL::Schema::UniqueWithinType.encode(type.graphql_name, object.id)
    end

    lazy_resolve(LazyWrapper, :value)
    lazy_resolve(LazyLoader, :value)
  end
end