dagger_ruby 0.7.0 → 0.10.0

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.
data/dagger_ruby.gemspec CHANGED
@@ -5,24 +5,25 @@ require_relative "lib/dagger_ruby/version"
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "dagger_ruby"
7
7
  spec.version = DaggerRuby::VERSION
8
- spec.authors = ["Gaurav Tiwari", "Claude Sonnet 4 + GPT-4"]
9
- spec.email = ["gaurav@gauravtiwari.co.uk"]
10
-
11
- spec.summary = "A Ruby SDK for Dagger - build powerful CI/CD pipelines using Ruby"
12
- # rubocop:disable Layout/LineLength
13
- spec.description = "DaggerRuby provides a fluent, idiomatic Ruby interface to Dagger's container-based CI/CD engine. " \
14
- "Define build pipelines programmatically with Ruby instead of YAML. " \
15
- "Features lazy execution, caching, secrets, and service orchestration."
16
- # rubocop:enable Layout/LineLength
8
+ spec.authors = ["BoringCache"]
9
+ spec.email = ["oss@boringcache.com"]
10
+
11
+ spec.summary = "A Ruby client for Dagger's GraphQL API"
12
+ spec.description = "DaggerRuby provides a small, chainable Ruby interface for running container builds, " \
13
+ "services, caches, secrets, and filesystem operations with the Dagger engine."
17
14
  spec.homepage = "https://github.com/boringcache/dagger_ruby"
18
15
  spec.license = "MIT"
19
- spec.required_ruby_version = ">= 3.1.0"
16
+ spec.required_ruby_version = ">= 3.2.0"
20
17
 
21
18
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
22
19
 
23
20
  spec.metadata["homepage_uri"] = spec.homepage
24
- spec.metadata["source_code_uri"] = "https://github.com/boringcache/dagger_ruby"
25
- spec.metadata["changelog_uri"] = "https://github.com/boringcache/dagger_ruby/blob/main/CHANGELOG.md"
21
+ spec.metadata["source_code_uri"] = "#{spec.homepage}/tree/v#{spec.version}"
22
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
23
+ spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
24
+ spec.metadata["documentation_uri"] = "#{spec.homepage}#readme"
25
+ spec.metadata["security_policy_uri"] = "#{spec.homepage}/security/policy"
26
+ spec.metadata["rubygems_mfa_required"] = "true"
26
27
 
27
28
  # Specify which files should be added to the gem when it is released.
28
29
  spec.files = Dir.glob(%w[
@@ -31,18 +32,14 @@ Gem::Specification.new do |spec|
31
32
  LICENSE*
32
33
  CHANGELOG*
33
34
  README*
34
- .yardopts
35
+ SECURITY*
35
36
  ]).reject { |f| File.directory?(f) }
36
37
 
37
- spec.bindir = "exe"
38
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
39
38
  spec.require_paths = ["lib"]
40
39
 
41
- # Core dependencies - using only Ruby stdlib
42
- spec.add_dependency "base64", "~> 0.1"
43
- spec.add_dependency "json", "~> 2.6"
44
- spec.add_dependency "logger", "~> 1.4"
40
+ spec.add_dependency "base64", "~> 0.3"
41
+ spec.add_dependency "json", "~> 2.21"
42
+ spec.add_dependency "logger", "~> 1.7"
45
43
 
46
44
  # Development dependencies are managed in Gemfile
47
- spec.metadata["rubygems_mfa_required"] = "true"
48
45
  end
@@ -4,20 +4,10 @@ require_relative "dagger_object"
4
4
 
5
5
  module DaggerRuby
6
6
  class CacheVolume < DaggerObject
7
- def self.from_id(id, client)
8
- query = QueryBuilder.new("cacheVolume")
9
- query.load_from_id(id)
10
- new(query, client)
11
- end
12
-
13
7
  def self.root_field_name
14
8
  "cacheVolume"
15
9
  end
16
10
 
17
- def key
18
- get_scalar("key")
19
- end
20
-
21
11
  def sync
22
12
  get_scalar("id") # Force execution by getting ID
23
13
  self
@@ -61,17 +61,24 @@ module DaggerRuby
61
61
  Directory.new(QueryBuilder.new("directory"), self)
62
62
  end
63
63
 
64
- def file
65
- File.new(QueryBuilder.new("file"), self)
64
+ def file(name, contents, permissions: nil)
65
+ args = { "name" => name, "contents" => contents }
66
+ args["permissions"] = permissions if permissions
67
+ File.new(QueryBuilder.new.chain_operation("file", args), self)
66
68
  end
67
69
 
68
- def secret
69
- Secret.new(QueryBuilder.new("secret"), self)
70
+ def secret(uri, cache_key: nil)
71
+ args = { "uri" => uri }
72
+ args["cacheKey"] = cache_key if cache_key
73
+ Secret.new(QueryBuilder.new.chain_operation("secret", args), self)
70
74
  end
71
75
 
72
- def cache_volume(name)
73
- query = QueryBuilder.new
74
- query = query.chain_operation("cacheVolume", { "key" => name })
76
+ def cache_volume(name, opts = {})
77
+ args = { "key" => name }
78
+ args["source"] = graphql_id(opts[:source]) if opts[:source]
79
+ args["sharing"] = QueryBuilder.enum_value(opts[:sharing]) if opts[:sharing]
80
+ args["owner"] = opts[:owner] if opts[:owner]
81
+ query = QueryBuilder.new.chain_operation("cacheVolume", args)
75
82
  CacheVolume.new(query, self)
76
83
  end
77
84
 
@@ -81,21 +88,12 @@ module DaggerRuby
81
88
 
82
89
  def git(url, opts = {})
83
90
  args = { "url" => url }
84
- args["keepGitDir"] = opts[:keep_git_dir] if opts.key?(:keep_git_dir)
85
91
  args["sshKnownHosts"] = opts[:ssh_known_hosts] if opts[:ssh_known_hosts]
86
- if opts[:ssh_auth_socket]
87
- args["sshAuthSocket"] =
88
- opts[:ssh_auth_socket].is_a?(DaggerObject) ? opts[:ssh_auth_socket].id : opts[:ssh_auth_socket]
89
- end
92
+ args["sshAuthSocket"] = graphql_id(opts[:ssh_auth_socket]) if opts[:ssh_auth_socket]
90
93
  args["httpAuthUsername"] = opts[:http_auth_username] if opts[:http_auth_username]
91
- if opts[:http_auth_token]
92
- args["httpAuthToken"] =
93
- opts[:http_auth_token].is_a?(DaggerObject) ? opts[:http_auth_token].id : opts[:http_auth_token]
94
- end
95
- if opts[:http_auth_header]
96
- args["httpAuthHeader"] =
97
- opts[:http_auth_header].is_a?(DaggerObject) ? opts[:http_auth_header].id : opts[:http_auth_header]
98
- end
94
+ args["httpAuthToken"] = graphql_id(opts[:http_auth_token]) if opts[:http_auth_token]
95
+ args["httpAuthHeader"] = graphql_id(opts[:http_auth_header]) if opts[:http_auth_header]
96
+ args["experimentalServiceHost"] = graphql_id(opts[:service_host]) if opts[:service_host]
99
97
 
100
98
  query = QueryBuilder.new
101
99
  query = query.chain_operation("git", args)
@@ -106,10 +104,9 @@ module DaggerRuby
106
104
  args = { "url" => url }
107
105
  args["name"] = opts[:name] if opts[:name]
108
106
  args["permissions"] = opts[:permissions] if opts[:permissions]
109
- if opts[:auth_header]
110
- args["authHeader"] =
111
- opts[:auth_header].is_a?(DaggerObject) ? opts[:auth_header].id : opts[:auth_header]
112
- end
107
+ args["checksum"] = opts[:checksum] if opts[:checksum]
108
+ args["authHeader"] = graphql_id(opts[:auth_header]) if opts[:auth_header]
109
+ args["experimentalServiceHost"] = graphql_id(opts[:service_host]) if opts[:service_host]
113
110
 
114
111
  query = QueryBuilder.new
115
112
  query = query.chain_operation("http", args)
@@ -143,6 +140,10 @@ module DaggerRuby
143
140
 
144
141
  private
145
142
 
143
+ def graphql_id(value)
144
+ value.is_a?(DaggerObject) ? value.id : value
145
+ end
146
+
146
147
  def handle_response(response)
147
148
  case response.code.to_i
148
149
  when 200
@@ -1,8 +1,13 @@
1
1
  require "logger"
2
+ require_relative "version"
2
3
 
3
4
  module DaggerRuby
4
5
  class Config
5
- attr_reader :log_output, :workdir, :timeout, :quiet, :silent, :progress
6
+ ENGINE_IMAGE = "registry.dagger.io/engine".freeze
7
+ RUNTIMES = %i[auto apple docker].freeze
8
+
9
+ attr_reader :log_output, :workdir, :timeout, :quiet, :silent, :progress,
10
+ :runtime, :runner_host, :dagger_version, :verify_version
6
11
 
7
12
  def initialize(options = {})
8
13
  @log_output = options[:log_output]
@@ -11,6 +16,38 @@ module DaggerRuby
11
16
  @quiet = options[:quiet] || ENV["DAGGER_QUIET"]&.to_i
12
17
  @silent = options[:silent] || ENV["DAGGER_SILENT"] == "true"
13
18
  @progress = options[:progress] || ENV.fetch("DAGGER_PROGRESS", nil)
19
+ @runtime = normalize_runtime(options.fetch(:runtime, ENV.fetch("DAGGER_RUBY_RUNTIME", "auto")))
20
+ @runner_host = options[:runner_host]
21
+ @dagger_version = options.fetch(:dagger_version, DAGGER_VERSION).to_s.delete_prefix("v")
22
+ @verify_version = options.fetch(:verify_version, true)
23
+
24
+ raise ArgumentError, "runner_host and runtime cannot both be configured" if @runner_host && @runtime != :auto
25
+ end
26
+
27
+ def environment
28
+ environment = {}
29
+ environment["_EXPERIMENTAL_DAGGER_RUNNER_HOST"] = resolved_runner_host if resolved_runner_host
30
+ environment
31
+ end
32
+
33
+ def expected_engine_version
34
+ "v#{dagger_version}"
35
+ end
36
+
37
+ private
38
+
39
+ def normalize_runtime(value)
40
+ runtime = value.to_s.downcase.to_sym
41
+ return runtime if RUNTIMES.include?(runtime)
42
+
43
+ raise ArgumentError, "Unknown Dagger runtime '#{value}'. Use auto, apple, or docker."
44
+ end
45
+
46
+ def resolved_runner_host
47
+ return runner_host if runner_host
48
+ return if runtime == :auto
49
+
50
+ "image+#{runtime}://#{ENGINE_IMAGE}:#{expected_engine_version}"
14
51
  end
15
52
  end
16
53
  end
@@ -4,12 +4,6 @@ require_relative "dagger_object"
4
4
 
5
5
  module DaggerRuby
6
6
  class Container < DaggerObject
7
- def self.from_id(id, client)
8
- query = QueryBuilder.new("container")
9
- query.load_from_id(id)
10
- new(query, client)
11
- end
12
-
13
7
  def self.root_field_name
14
8
  "container"
15
9
  end
@@ -22,23 +16,28 @@ module DaggerRuby
22
16
  args = { "path" => path, "source" => directory.is_a?(DaggerObject) ? directory.id : directory }
23
17
  args["exclude"] = opts[:exclude] if opts[:exclude]
24
18
  args["include"] = opts[:include] if opts[:include]
19
+ args["gitignore"] = opts[:gitignore] if opts[:gitignore]
25
20
  args["owner"] = opts[:owner] if opts[:owner]
26
21
  args["expand"] = opts[:expand] if opts.key?(:expand)
22
+ args["permissions"] = opts[:permissions] if opts[:permissions]
27
23
 
28
24
  chain_operation("withDirectory", args)
29
25
  end
30
26
 
31
- def with_workdir(path)
32
- chain_operation("withWorkdir", { "path" => path })
27
+ def with_workdir(path, expand: nil)
28
+ args = { "path" => path }
29
+ args["expand"] = expand unless expand.nil?
30
+ chain_operation("withWorkdir", args)
33
31
  end
34
32
 
35
33
  def with_exec(args, opts = {})
36
34
  exec_args = { "args" => args }
37
35
  exec_args["useEntrypoint"] = opts[:use_entrypoint] if opts.key?(:use_entrypoint)
38
36
  exec_args["stdin"] = opts[:stdin] if opts[:stdin]
37
+ exec_args["redirectStdin"] = opts[:redirect_stdin] if opts[:redirect_stdin]
39
38
  exec_args["redirectStdout"] = opts[:redirect_stdout] if opts[:redirect_stdout]
40
39
  exec_args["redirectStderr"] = opts[:redirect_stderr] if opts[:redirect_stderr]
41
- exec_args["expect"] = opts[:expect] if opts[:expect]
40
+ exec_args["expect"] = QueryBuilder.enum_value(opts[:expect]) if opts[:expect]
42
41
  if opts.key?(:experimental_privileged_nesting)
43
42
  exec_args["experimentalPrivilegedNesting"] = opts[:experimental_privileged_nesting]
44
43
  end
@@ -54,7 +53,7 @@ module DaggerRuby
54
53
  def with_mounted_cache(path, cache, opts = {})
55
54
  args = { "path" => path, "cache" => cache.is_a?(DaggerObject) ? cache.id : cache }
56
55
  args["source"] = opts[:source] if opts[:source]
57
- args["sharing"] = opts[:sharing] if opts[:sharing]
56
+ args["sharing"] = QueryBuilder.enum_value(opts[:sharing]) if opts[:sharing]
58
57
  args["owner"] = opts[:owner] if opts[:owner]
59
58
  args["expand"] = opts[:expand] if opts.key?(:expand)
60
59
 
@@ -91,10 +90,7 @@ module DaggerRuby
91
90
  chain_operation("withSecretVariable", args)
92
91
  end
93
92
 
94
- def with_secret_env(name, secret)
95
- args = { "name" => name, "secret" => secret.is_a?(DaggerObject) ? secret.id : secret }
96
- chain_operation("withSecretEnv", args)
97
- end
93
+ alias with_secret_env with_secret_variable
98
94
 
99
95
  def with_entrypoint(args, opts = {})
100
96
  entrypoint_args = { "args" => args }
@@ -102,13 +98,37 @@ module DaggerRuby
102
98
  chain_operation("withEntrypoint", entrypoint_args)
103
99
  end
104
100
 
101
+ def with_default_args(args)
102
+ chain_operation("withDefaultArgs", { "args" => args })
103
+ end
104
+
105
+ def with_docker_healthcheck(args, opts = {})
106
+ healthcheck_args = { "args" => args }
107
+ healthcheck_args["shell"] = opts[:shell] if opts.key?(:shell)
108
+ healthcheck_args["interval"] = opts[:interval] if opts[:interval]
109
+ healthcheck_args["timeout"] = opts[:timeout] if opts[:timeout]
110
+ healthcheck_args["startPeriod"] = opts[:start_period] if opts[:start_period]
111
+ healthcheck_args["startInterval"] = opts[:start_interval] if opts[:start_interval]
112
+ healthcheck_args["retries"] = opts[:retries] if opts[:retries]
113
+
114
+ chain_operation("withDockerHealthcheck", healthcheck_args)
115
+ end
116
+
117
+ def without_docker_healthcheck
118
+ chain_operation("withoutDockerHealthcheck")
119
+ end
120
+
105
121
  def with_user(name)
106
122
  chain_operation("withUser", { "name" => name })
107
123
  end
108
124
 
109
- def with_registry_auth(_address, _username, _secret)
110
- puts "⚠️ Registry auth temporarily disabled due to GraphQL formatting issues"
111
- self
125
+ def with_registry_auth(address, username, secret)
126
+ args = {
127
+ "address" => address,
128
+ "username" => username,
129
+ "secret" => secret.is_a?(DaggerObject) ? secret.id : secret,
130
+ }
131
+ chain_operation("withRegistryAuth", args)
112
132
  end
113
133
 
114
134
  def without_registry_auth(address)
@@ -139,21 +159,6 @@ module DaggerRuby
139
159
  get_object("asService", Service, args)
140
160
  end
141
161
 
142
- def build(context, opts = {})
143
- args = { "context" => context.is_a?(DaggerObject) ? context.id : context }
144
- args["dockerfile"] = opts[:dockerfile] if opts[:dockerfile]
145
- args["target"] = opts[:target] if opts[:target]
146
- args["buildArgs"] = opts[:build_args] if opts[:build_args]
147
-
148
- if opts[:secrets]
149
- raise NotImplementedError, "Build secrets are not yet supported. Use with_mounted_secret instead."
150
- end
151
-
152
- args["noInit"] = opts[:no_init] if opts.key?(:no_init)
153
-
154
- chain_operation("build", args)
155
- end
156
-
157
162
  def import(source, opts = {})
158
163
  args = { "source" => source.is_a?(DaggerObject) ? source.id : source }
159
164
  args["tag"] = opts[:tag] if opts[:tag]
@@ -179,7 +184,7 @@ module DaggerRuby
179
184
 
180
185
  def with_exposed_port(port, opts = {})
181
186
  args = { "port" => port }
182
- args["protocol"] = opts[:protocol] if opts[:protocol]
187
+ args["protocol"] = QueryBuilder.enum_value(opts[:protocol]) if opts[:protocol]
183
188
  args["description"] = opts[:description] if opts[:description]
184
189
  if opts.key?(:experimental_skip_healthcheck)
185
190
  args["experimentalSkipHealthcheck"] = opts[:experimental_skip_healthcheck]
@@ -196,6 +201,7 @@ module DaggerRuby
196
201
  def with_mounted_directory(path, source, opts = {})
197
202
  args = { "path" => path, "source" => source.is_a?(DaggerObject) ? source.id : source }
198
203
  args["owner"] = opts[:owner] if opts[:owner]
204
+ args["readOnly"] = opts[:read_only] if opts.key?(:read_only)
199
205
  args["expand"] = opts[:expand] if opts.key?(:expand)
200
206
 
201
207
  chain_operation("withMountedDirectory", args)
@@ -232,7 +238,7 @@ module DaggerRuby
232
238
 
233
239
  def without_exposed_port(port, opts = {})
234
240
  args = { "port" => port }
235
- args["protocol"] = opts[:protocol] if opts[:protocol]
241
+ args["protocol"] = QueryBuilder.enum_value(opts[:protocol]) if opts[:protocol]
236
242
 
237
243
  chain_operation("withoutExposedPort", args)
238
244
  end
@@ -273,24 +279,31 @@ module DaggerRuby
273
279
  get_scalar("entrypoint")
274
280
  end
275
281
 
282
+ def default_args
283
+ get_scalar("defaultArgs")
284
+ end
285
+
286
+ def docker_healthcheck
287
+ get_selection(
288
+ "dockerHealthcheck",
289
+ "args shell interval timeout startPeriod startInterval retries",
290
+ )
291
+ end
292
+
276
293
  def env_variables
277
- get_scalar("envVariables")
294
+ get_selection("envVariables", "name value")
278
295
  end
279
296
 
280
297
  def env_variable(name)
281
- query = @query_builder.build_query_with_selection("envVariable(name: \"#{name}\")")
282
- result = @client.execute(query)
283
- extract_value_from_result(result, "envVariable")
298
+ get_scalar("envVariable", { "name" => name })
284
299
  end
285
300
 
286
301
  def labels
287
- get_scalar("labels")
302
+ get_selection("labels", "name value")
288
303
  end
289
304
 
290
305
  def label(name)
291
- query = @query_builder.build_query_with_selection("label(name: \"#{name}\")")
292
- result = @client.execute(query)
293
- extract_value_from_result(result, "label")
306
+ get_scalar("label", { "name" => name })
294
307
  end
295
308
 
296
309
  def mounts
@@ -298,7 +311,7 @@ module DaggerRuby
298
311
  end
299
312
 
300
313
  def exposed_ports
301
- get_scalar("exposedPorts")
314
+ get_selection("exposedPorts", "port protocol description experimentalSkipHealthcheck")
302
315
  end
303
316
 
304
317
  def platform
@@ -311,48 +324,51 @@ module DaggerRuby
311
324
 
312
325
  def export(path, opts = {})
313
326
  args = { "path" => path }
314
- args["platformVariants"] = opts[:platform_variants] if opts[:platform_variants]
315
- args["forcedCompression"] = opts[:forced_compression] if opts[:forced_compression]
316
- args["mediaTypes"] = opts[:media_types] if opts[:media_types]
327
+ args["platformVariants"] = graphql_ids(opts[:platform_variants]) if opts[:platform_variants]
328
+ args["forcedCompression"] = QueryBuilder.enum_value(opts[:forced_compression]) if opts[:forced_compression]
329
+ args["mediaTypes"] = QueryBuilder.enum_value(opts[:media_types]) if opts[:media_types]
317
330
  args["expand"] = opts[:expand] if opts.key?(:expand)
318
331
 
319
- query = @query_builder.build_query_with_selection("export(#{format_arguments(args)})")
320
- result = @client.execute(query)
321
- extract_value_from_result(result, "export")
332
+ get_scalar("export", args)
322
333
  end
323
334
 
324
335
  def export_to_file(path, opts = {})
325
- args = { "path" => path }
326
- args["platformVariants"] = opts[:platform_variants] if opts[:platform_variants]
327
- args["forcedCompression"] = opts[:forced_compression] if opts[:forced_compression]
328
- args["mediaTypes"] = opts[:media_types] if opts[:media_types]
329
- args["expand"] = opts[:expand] if opts.key?(:expand)
336
+ export(path, opts)
337
+ end
338
+
339
+ def export_image(name, opts = {})
340
+ args = { "name" => name }
341
+ args["platformVariants"] = graphql_ids(opts[:platform_variants]) if opts[:platform_variants]
342
+ args["forcedCompression"] = QueryBuilder.enum_value(opts[:forced_compression]) if opts[:forced_compression]
343
+ args["mediaTypes"] = QueryBuilder.enum_value(opts[:media_types]) if opts[:media_types]
330
344
 
331
- query = @query_builder.build_query_with_selection("exportToFile(#{format_arguments(args)})")
332
- result = @client.execute(query)
333
- extract_value_from_result(result, "exportToFile")
345
+ get_scalar("exportImage", args)
346
+ name
334
347
  end
335
348
 
336
349
  def publish(address, opts = {})
337
350
  args = { "address" => address }
338
- args["platformVariants"] = opts[:platform_variants] if opts[:platform_variants]
339
- args["forcedCompression"] = opts[:forced_compression] if opts[:forced_compression]
340
- args["mediaTypes"] = opts[:media_types] if opts[:media_types]
341
-
342
- query = @query_builder.build_query_with_selection("publish(#{format_arguments(args)})")
343
- result = @client.execute(query)
344
- extract_value_from_result(result, "publish")
351
+ args["platformVariants"] = graphql_ids(opts[:platform_variants]) if opts[:platform_variants]
352
+ args["forcedCompression"] = QueryBuilder.enum_value(opts[:forced_compression]) if opts[:forced_compression]
353
+ args["mediaTypes"] = QueryBuilder.enum_value(opts[:media_types]) if opts[:media_types]
354
+
355
+ if opts[:registry_service]
356
+ args["registryService"] = if opts[:registry_service].is_a?(DaggerObject)
357
+ opts[:registry_service].id
358
+ else
359
+ opts[:registry_service]
360
+ end
361
+ end
362
+ get_scalar("publish", args)
345
363
  end
346
364
 
347
365
  def as_tarball(opts = {})
348
366
  args = {}
349
- args["platformVariants"] = opts[:platform_variants] if opts[:platform_variants]
350
- args["forcedCompression"] = opts[:forced_compression] if opts[:forced_compression]
351
- args["mediaTypes"] = opts[:media_types] if opts[:media_types]
367
+ args["platformVariants"] = graphql_ids(opts[:platform_variants]) if opts[:platform_variants]
368
+ args["forcedCompression"] = QueryBuilder.enum_value(opts[:forced_compression]) if opts[:forced_compression]
369
+ args["mediaTypes"] = QueryBuilder.enum_value(opts[:media_types]) if opts[:media_types]
352
370
 
353
- query = @query_builder.build_query_with_selection("asTarball(#{format_arguments(args)})")
354
- result = @client.execute(query)
355
- extract_value_from_result(result, "asTarball")
371
+ get_object("asTarball", File, args)
356
372
  end
357
373
 
358
374
  def sync
@@ -362,32 +378,8 @@ module DaggerRuby
362
378
 
363
379
  private
364
380
 
365
- def format_arguments(args)
366
- return "" if args.empty?
367
-
368
- args.map { |key, value| "#{key}: #{format_value(value)}" }.join(", ")
369
- end
370
-
371
- def format_value(value)
372
- case value
373
- when String
374
- "\"#{value}\""
375
- when Integer, Float
376
- value.to_s
377
- when TrueClass, FalseClass
378
- value.to_s
379
- when NilClass
380
- "null"
381
- when Array
382
- "[#{value.map { |v| format_value(v) }.join(", ")}]"
383
- when Hash
384
- formatted_pairs = value.map { |k, v| "#{k}: #{format_value(v)}" }
385
- "{ #{formatted_pairs.join(", ")} }"
386
- when DaggerObject
387
- value.id
388
- else
389
- "\"#{value}\""
390
- end
381
+ def graphql_ids(values)
382
+ values.map { |value| value.is_a?(DaggerObject) ? value.id : value }
391
383
  end
392
384
  end
393
385
  end
@@ -23,8 +23,15 @@ module DaggerRuby
23
23
 
24
24
  protected
25
25
 
26
- def get_scalar(field)
27
- query = @query_builder.build_query_with_selection(field)
26
+ def get_scalar(field, args = {})
27
+ query = @query_builder.build_query_with_selection(field, args)
28
+ result = @client.execute_query(query)
29
+ extract_value_from_result(result, field)
30
+ end
31
+
32
+ def get_selection(field, selection, args = {})
33
+ selected_field = "#{QueryBuilder.new.field_selection(field, args)} { #{selection} }"
34
+ query = @query_builder.build_query_with_selection(selected_field)
28
35
  result = @client.execute_query(query)
29
36
  extract_value_from_result(result, field)
30
37
  end
@@ -52,42 +59,25 @@ module DaggerRuby
52
59
  klass.new(new_query, @client)
53
60
  end
54
61
 
55
- def get_object_array(field, klass, _args = {})
56
- query = @query_builder.build_query_with_selection(field)
57
-
58
- array_field = query.selections.find { |s| s.field == field }
59
- array_field&.select("id")
60
-
61
- result = @client.execute(query)
62
- ids = extract_array_from_result(result, field)
63
-
64
- ids.map { |id_data| klass.from_id(id_data["id"], @client) }
65
- end
66
-
67
- private
68
-
69
- def extract_array_from_result(result, field)
70
- current = result["data"]
71
-
72
- if @query_builder.root_field
73
- current = current[@query_builder.root_field]
74
- @query_builder.operation_chain.each do |operation|
75
- current = current[operation[:field]] if current
76
- end
77
- end
78
- current&.[](field) || []
62
+ def get_object_array(field, klass, args = {})
63
+ get_selection(field, "id", args).to_a.map { |data| klass.from_id(data.fetch("id"), @client) }
79
64
  end
80
65
 
81
66
  class << self
82
67
  def from_id(id, client)
83
- query = QueryBuilder.new(root_field_name)
84
- query.load_from_id(id)
68
+ query = QueryBuilder.new.chain_operation("load#{graphql_type_name}FromID", { "id" => id })
85
69
  new(query, client)
86
70
  end
87
71
 
88
72
  def root_field_name
89
73
  name.split("::").last.downcase
90
74
  end
75
+
76
+ private
77
+
78
+ def graphql_type_name
79
+ name.split("::").last
80
+ end
91
81
  end
92
82
  end
93
83
  end