carddb 0.2.0 → 0.2.2

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: f38ee7d9b3b04bbbc3cfa0c3b4954cb0a65ee7f61f64f87a7bc07c228cdec60d
4
- data.tar.gz: 80759ca9be30df5ef9c3b122caccde5c669d7828d3fbd097d5ad431b2c2885b3
3
+ metadata.gz: 95339c7a41f87063b7543aff563ae04f955d59de9f3e5f5ee5f4be020f3897f1
4
+ data.tar.gz: 370d681dea20285ea2f4429d027733a7dd175c241a773feb6fccaa0e52ccdf37
5
5
  SHA512:
6
- metadata.gz: 8d1f7de2a44deaa670f63f3de0879edb50b271e154d31d788464f457537a91c99e56a8db7a1717ff047456eee7f1f02d1745305f92e3fa9488945386941af6c6
7
- data.tar.gz: db96a54832d649c3bb683a01ec1c19a287062ba4ec82b08c201c628e15b407a788d587562f124447d943652d299ccd1b4b8287fd8bedd70e2c2675257022c2ef
6
+ metadata.gz: e40e127c9afcd40e408f6417c56f64d99f7841b97ee5580702cb6d77f4c632a4a28c037b4164f87c37f281f9dbe36b1eb5ecf3fc11c8dc185742f17941937648
7
+ data.tar.gz: ba3d0d3b825e0d8eef8b2ba48767375d78fcee011e6572026557ef3a588335f7beb9b762b8632d390d0762f0c7ba76b9687ba80ac55c1a89ccfea8bf86ed7aad
data/.rspec_status CHANGED
@@ -1,94 +1,114 @@
1
1
  example_id | status | run_time |
2
2
  ------------------------------------------------- | ------ | --------------- |
3
- ./spec/carddb/client_spec.rb[1:1:1] | passed | 0.00029 seconds |
4
- ./spec/carddb/client_spec.rb[1:1:2] | passed | 0.00004 seconds |
3
+ ./spec/carddb/client_spec.rb[1:1:1] | passed | 0.0002 seconds |
4
+ ./spec/carddb/client_spec.rb[1:1:2] | passed | 0.00005 seconds |
5
5
  ./spec/carddb/client_spec.rb[1:1:3] | passed | 0.00003 seconds |
6
- ./spec/carddb/client_spec.rb[1:2:1] | passed | 0.00016 seconds |
7
- ./spec/carddb/client_spec.rb[1:2:2] | passed | 0.00019 seconds |
8
- ./spec/carddb/client_spec.rb[1:3:1] | passed | 0.00003 seconds |
6
+ ./spec/carddb/client_spec.rb[1:2:1] | passed | 0.00013 seconds |
7
+ ./spec/carddb/client_spec.rb[1:2:2] | passed | 0.00016 seconds |
8
+ ./spec/carddb/client_spec.rb[1:3:1] | passed | 0.00004 seconds |
9
9
  ./spec/carddb/client_spec.rb[1:4:1] | passed | 0.00003 seconds |
10
10
  ./spec/carddb/client_spec.rb[1:5:1] | passed | 0.00004 seconds |
11
11
  ./spec/carddb/client_spec.rb[1:6:1] | passed | 0.00003 seconds |
12
- ./spec/carddb/client_spec.rb[1:7:1] | passed | 0.00032 seconds |
13
- ./spec/carddb/client_spec.rb[1:7:2] | passed | 0.01201 seconds |
14
- ./spec/carddb/collection_spec.rb[1:1:1] | passed | 0.00006 seconds |
15
- ./spec/carddb/collection_spec.rb[2:1:1] | passed | 0.00245 seconds |
16
- ./spec/carddb/collection_spec.rb[2:1:2] | passed | 0.00015 seconds |
17
- ./spec/carddb/collection_spec.rb[2:1:3] | passed | 0.0004 seconds |
18
- ./spec/carddb/collection_spec.rb[2:1:4] | passed | 0.00038 seconds |
19
- ./spec/carddb/collection_spec.rb[2:1:5] | passed | 0.00005 seconds |
20
- ./spec/carddb/collection_spec.rb[3:1:1] | passed | 0.00018 seconds |
21
- ./spec/carddb/collection_spec.rb[3:1:2] | passed | 0.0003 seconds |
22
- ./spec/carddb/collection_spec.rb[3:1:3] | passed | 0.00015 seconds |
23
- ./spec/carddb/collection_spec.rb[3:1:4] | passed | 0.00004 seconds |
24
- ./spec/carddb/configuration_spec.rb[1:1:1] | passed | 0.00004 seconds |
25
- ./spec/carddb/configuration_spec.rb[1:1:2] | passed | 0.0001 seconds |
26
- ./spec/carddb/configuration_spec.rb[1:1:3] | passed | 0.00004 seconds |
12
+ ./spec/carddb/client_spec.rb[1:7:1] | passed | 0.00023 seconds |
13
+ ./spec/carddb/client_spec.rb[1:7:2] | passed | 0.01089 seconds |
14
+ ./spec/carddb/collection_spec.rb[1:1:1] | passed | 0.00005 seconds |
15
+ ./spec/carddb/collection_spec.rb[2:1:1] | passed | 0.00003 seconds |
16
+ ./spec/carddb/collection_spec.rb[3:1:1] | passed | 0.00191 seconds |
17
+ ./spec/carddb/collection_spec.rb[3:1:2] | passed | 0.00012 seconds |
18
+ ./spec/carddb/collection_spec.rb[3:1:3] | passed | 0.00032 seconds |
19
+ ./spec/carddb/collection_spec.rb[3:1:4] | passed | 0.00031 seconds |
20
+ ./spec/carddb/collection_spec.rb[3:1:5] | passed | 0.00012 seconds |
21
+ ./spec/carddb/collection_spec.rb[4:1:1] | passed | 0.00012 seconds |
22
+ ./spec/carddb/collection_spec.rb[4:1:2] | passed | 0.00013 seconds |
23
+ ./spec/carddb/collection_spec.rb[4:1:3] | passed | 0.00013 seconds |
24
+ ./spec/carddb/collection_spec.rb[4:1:4] | passed | 0.00004 seconds |
25
+ ./spec/carddb/configuration_spec.rb[1:1:1] | passed | 0.00003 seconds |
26
+ ./spec/carddb/configuration_spec.rb[1:1:2] | passed | 0.00003 seconds |
27
+ ./spec/carddb/configuration_spec.rb[1:1:3] | passed | 0.00003 seconds |
27
28
  ./spec/carddb/configuration_spec.rb[1:1:4] | passed | 0.00003 seconds |
28
- ./spec/carddb/configuration_spec.rb[1:1:5] | passed | 0.00003 seconds |
29
+ ./spec/carddb/configuration_spec.rb[1:1:5] | passed | 0.00008 seconds |
29
30
  ./spec/carddb/configuration_spec.rb[1:1:6] | passed | 0.00003 seconds |
30
- ./spec/carddb/configuration_spec.rb[1:2:1:1] | passed | 0.00004 seconds |
31
+ ./spec/carddb/configuration_spec.rb[1:2:1:1] | passed | 0.00003 seconds |
31
32
  ./spec/carddb/configuration_spec.rb[1:2:2:1] | passed | 0.00003 seconds |
32
- ./spec/carddb/configuration_spec.rb[1:2:2:2] | passed | 0.0001 seconds |
33
+ ./spec/carddb/configuration_spec.rb[1:2:2:2] | passed | 0.00004 seconds |
33
34
  ./spec/carddb/configuration_spec.rb[1:3:1:1] | passed | 0.00003 seconds |
34
35
  ./spec/carddb/configuration_spec.rb[1:3:2:1] | passed | 0.00003 seconds |
35
- ./spec/carddb/configuration_spec.rb[1:3:2:2] | passed | 0.00003 seconds |
36
- ./spec/carddb/configuration_spec.rb[1:3:2:3] | passed | 0.00002 seconds |
37
- ./spec/carddb/configuration_spec.rb[1:4:1] | passed | 0.00004 seconds |
36
+ ./spec/carddb/configuration_spec.rb[1:3:2:2] | passed | 0.00004 seconds |
37
+ ./spec/carddb/configuration_spec.rb[1:3:2:3] | passed | 0.00003 seconds |
38
+ ./spec/carddb/configuration_spec.rb[1:4:1] | passed | 0.00003 seconds |
38
39
  ./spec/carddb/configuration_spec.rb[1:4:2] | passed | 0.00003 seconds |
39
- ./spec/carddb/configuration_spec.rb[1:5:1] | passed | 0.00003 seconds |
40
- ./spec/carddb/filter_builder_spec.rb[1:1:1] | passed | 0.00004 seconds |
40
+ ./spec/carddb/configuration_spec.rb[1:5:1] | passed | 0.00004 seconds |
41
+ ./spec/carddb/filter_builder_spec.rb[1:1:1] | passed | 0.00003 seconds |
41
42
  ./spec/carddb/filter_builder_spec.rb[1:1:2] | passed | 0.00003 seconds |
42
- ./spec/carddb/filter_builder_spec.rb[1:1:3] | passed | 0.00003 seconds |
43
- ./spec/carddb/filter_builder_spec.rb[1:1:4] | passed | 0.00002 seconds |
44
- ./spec/carddb/filter_builder_spec.rb[1:1:5] | passed | 0.00002 seconds |
43
+ ./spec/carddb/filter_builder_spec.rb[1:1:3] | passed | 0.00004 seconds |
44
+ ./spec/carddb/filter_builder_spec.rb[1:1:4] | passed | 0.00008 seconds |
45
+ ./spec/carddb/filter_builder_spec.rb[1:1:5] | passed | 0.00003 seconds |
45
46
  ./spec/carddb/filter_builder_spec.rb[1:1:6] | passed | 0.00003 seconds |
46
47
  ./spec/carddb/filter_builder_spec.rb[1:1:7] | passed | 0.00003 seconds |
47
- ./spec/carddb/filter_builder_spec.rb[1:1:8] | passed | 0.00002 seconds |
48
+ ./spec/carddb/filter_builder_spec.rb[1:1:8] | passed | 0.00003 seconds |
48
49
  ./spec/carddb/filter_builder_spec.rb[1:2:1] | passed | 0.00003 seconds |
49
- ./spec/carddb/filter_builder_spec.rb[1:2:2] | passed | 0.00002 seconds |
50
- ./spec/carddb/filter_builder_spec.rb[1:2:3] | passed | 0.00002 seconds |
51
- ./spec/carddb/filter_builder_spec.rb[1:2:4] | passed | 0.00002 seconds |
52
- ./spec/carddb/filter_builder_spec.rb[1:2:5] | passed | 0.00002 seconds |
50
+ ./spec/carddb/filter_builder_spec.rb[1:2:2] | passed | 0.00003 seconds |
51
+ ./spec/carddb/filter_builder_spec.rb[1:2:3] | passed | 0.00003 seconds |
52
+ ./spec/carddb/filter_builder_spec.rb[1:2:4] | passed | 0.00003 seconds |
53
+ ./spec/carddb/filter_builder_spec.rb[1:2:5] | passed | 0.00003 seconds |
53
54
  ./spec/carddb/filter_builder_spec.rb[1:2:6] | passed | 0.00002 seconds |
54
- ./spec/carddb/filter_builder_spec.rb[1:2:7] | passed | 0.00002 seconds |
55
- ./spec/carddb/filter_builder_spec.rb[1:2:8] | passed | 0.00002 seconds |
56
- ./spec/carddb/filter_builder_spec.rb[1:2:9] | passed | 0.00002 seconds |
57
- ./spec/carddb/filter_builder_spec.rb[1:2:10] | passed | 0.00002 seconds |
58
- ./spec/carddb/filter_builder_spec.rb[1:2:11] | passed | 0.00002 seconds |
59
- ./spec/carddb/filter_builder_spec.rb[1:2:12] | passed | 0.00002 seconds |
60
- ./spec/carddb/filter_builder_spec.rb[1:2:13] | passed | 0.00003 seconds |
61
- ./spec/carddb/resources/datasets_spec.rb[1:1:1] | passed | 0.00387 seconds |
62
- ./spec/carddb/resources/datasets_spec.rb[1:1:2] | passed | 0.00363 seconds |
63
- ./spec/carddb/resources/datasets_spec.rb[1:2:1] | passed | 0.00444 seconds |
64
- ./spec/carddb/resources/decks_spec.rb[1:1:1] | passed | 0.00427 seconds |
65
- ./spec/carddb/resources/decks_spec.rb[1:2:1] | passed | 0.00438 seconds |
66
- ./spec/carddb/resources/decks_spec.rb[1:3:1] | passed | 0.00442 seconds |
67
- ./spec/carddb/resources/decks_spec.rb[1:4:1] | passed | 0.0043 seconds |
68
- ./spec/carddb/resources/decks_spec.rb[1:5:1] | passed | 0.00403 seconds |
69
- ./spec/carddb/resources/decks_spec.rb[1:6:1] | passed | 0.00384 seconds |
70
- ./spec/carddb/resources/decks_spec.rb[1:7:1] | passed | 0.00416 seconds |
71
- ./spec/carddb/resources/games_spec.rb[1:1:1] | passed | 0.00463 seconds |
72
- ./spec/carddb/resources/games_spec.rb[1:1:2] | passed | 0.00008 seconds |
73
- ./spec/carddb/resources/games_spec.rb[1:2:1] | passed | 0.00426 seconds |
74
- ./spec/carddb/resources/games_spec.rb[1:2:2] | passed | 0.00444 seconds |
75
- ./spec/carddb/resources/publishers_spec.rb[1:1:1] | passed | 0.00383 seconds |
76
- ./spec/carddb/resources/publishers_spec.rb[1:2:1] | passed | 0.00447 seconds |
77
- ./spec/carddb/resources/records_spec.rb[1:1:1] | passed | 0.00428 seconds |
78
- ./spec/carddb/resources/records_spec.rb[1:1:2] | passed | 0.00416 seconds |
79
- ./spec/carddb/resources/records_spec.rb[1:1:3] | passed | 0.00012 seconds |
55
+ ./spec/carddb/filter_builder_spec.rb[1:2:7] | passed | 0.00007 seconds |
56
+ ./spec/carddb/filter_builder_spec.rb[1:2:8] | passed | 0.00004 seconds |
57
+ ./spec/carddb/filter_builder_spec.rb[1:2:9] | passed | 0.00003 seconds |
58
+ ./spec/carddb/filter_builder_spec.rb[1:2:10] | passed | 0.00003 seconds |
59
+ ./spec/carddb/filter_builder_spec.rb[1:2:11] | passed | 0.00003 seconds |
60
+ ./spec/carddb/filter_builder_spec.rb[1:2:12] | passed | 0.00005 seconds |
61
+ ./spec/carddb/filter_builder_spec.rb[1:2:13] | passed | 0.00004 seconds |
62
+ ./spec/carddb/query_builder_spec.rb[1:1:1] | passed | 0.00004 seconds |
63
+ ./spec/carddb/query_builder_spec.rb[1:1:2] | passed | 0.00004 seconds |
64
+ ./spec/carddb/query_builder_spec.rb[1:1:3] | passed | 0.00062 seconds |
65
+ ./spec/carddb/query_builder_spec.rb[1:2:1:1] | passed | 0.00005 seconds |
66
+ ./spec/carddb/query_builder_spec.rb[1:2:2:1] | passed | 0.00004 seconds |
67
+ ./spec/carddb/resources/datasets_spec.rb[1:1:1] | passed | 0.00385 seconds |
68
+ ./spec/carddb/resources/datasets_spec.rb[1:1:2] | passed | 0.0037 seconds |
69
+ ./spec/carddb/resources/datasets_spec.rb[1:2:1] | passed | 0.00376 seconds |
70
+ ./spec/carddb/resources/decks_spec.rb[1:1:1] | passed | 0.00386 seconds |
71
+ ./spec/carddb/resources/decks_spec.rb[1:1:2] | passed | 0.00381 seconds |
72
+ ./spec/carddb/resources/decks_spec.rb[1:2:1] | passed | 0.00403 seconds |
73
+ ./spec/carddb/resources/decks_spec.rb[1:3:1] | passed | 0.00388 seconds |
74
+ ./spec/carddb/resources/decks_spec.rb[1:4:1] | passed | 0.00365 seconds |
75
+ ./spec/carddb/resources/decks_spec.rb[1:5:1] | passed | 0.00386 seconds |
76
+ ./spec/carddb/resources/decks_spec.rb[1:6:1] | passed | 0.00367 seconds |
77
+ ./spec/carddb/resources/decks_spec.rb[1:7:1] | passed | 0.00401 seconds |
78
+ ./spec/carddb/resources/decks_spec.rb[1:8:1] | passed | 0.00386 seconds |
79
+ ./spec/carddb/resources/decks_spec.rb[1:9:1] | passed | 0.00363 seconds |
80
+ ./spec/carddb/resources/decks_spec.rb[1:10:1] | passed | 0.00398 seconds |
81
+ ./spec/carddb/resources/decks_spec.rb[1:11:1] | passed | 0.00382 seconds |
82
+ ./spec/carddb/resources/decks_spec.rb[1:12:1] | passed | 0.00371 seconds |
83
+ ./spec/carddb/resources/decks_spec.rb[1:13:1] | passed | 0.00387 seconds |
84
+ ./spec/carddb/resources/decks_spec.rb[1:14:1] | passed | 0.00376 seconds |
85
+ ./spec/carddb/resources/decks_spec.rb[1:15:1] | passed | 0.00398 seconds |
86
+ ./spec/carddb/resources/decks_spec.rb[1:16:1] | passed | 0.00383 seconds |
87
+ ./spec/carddb/resources/decks_spec.rb[1:17:1] | passed | 0.00383 seconds |
88
+ ./spec/carddb/resources/decks_spec.rb[1:18:1] | passed | 0.00412 seconds |
89
+ ./spec/carddb/resources/decks_spec.rb[1:19:1] | passed | 0.00398 seconds |
90
+ ./spec/carddb/resources/games_spec.rb[1:1:1] | passed | 0.00368 seconds |
91
+ ./spec/carddb/resources/games_spec.rb[1:1:2] | passed | 0.00006 seconds |
92
+ ./spec/carddb/resources/games_spec.rb[1:2:1] | passed | 0.00407 seconds |
93
+ ./spec/carddb/resources/games_spec.rb[1:2:2] | passed | 0.0039 seconds |
94
+ ./spec/carddb/resources/publishers_spec.rb[1:1:1] | passed | 0.00375 seconds |
95
+ ./spec/carddb/resources/publishers_spec.rb[1:2:1] | passed | 0.00382 seconds |
96
+ ./spec/carddb/resources/records_spec.rb[1:1:1] | passed | 0.00366 seconds |
97
+ ./spec/carddb/resources/records_spec.rb[1:1:2] | passed | 0.00402 seconds |
98
+ ./spec/carddb/resources/records_spec.rb[1:1:3] | passed | 0.00013 seconds |
80
99
  ./spec/carddb/resources/records_spec.rb[1:1:4] | passed | 0.00004 seconds |
81
- ./spec/carddb/resources/records_spec.rb[1:2:1] | passed | 0.00412 seconds |
82
- ./spec/carddb/resources/records_spec.rb[1:2:2] | passed | 0.00414 seconds |
83
- ./spec/carddb/resources/records_spec.rb[1:3:1] | passed | 0.00444 seconds |
100
+ ./spec/carddb/resources/records_spec.rb[1:2:1] | passed | 0.00392 seconds |
101
+ ./spec/carddb/resources/records_spec.rb[1:2:2] | passed | 0.00366 seconds |
102
+ ./spec/carddb/resources/records_spec.rb[1:2:3] | passed | 0.00403 seconds |
103
+ ./spec/carddb/resources/records_spec.rb[1:3:1] | passed | 0.00388 seconds |
84
104
  ./spec/carddb/resources/records_spec.rb[1:3:2] | passed | 0.00011 seconds |
85
- ./spec/carddb/resources/records_spec.rb[1:4:1] | passed | 0.00365 seconds |
86
- ./spec/carddb/resources/records_spec.rb[1:4:2] | passed | 0.00004 seconds |
105
+ ./spec/carddb/resources/records_spec.rb[1:4:1] | passed | 0.00367 seconds |
106
+ ./spec/carddb/resources/records_spec.rb[1:4:2] | passed | 0.00005 seconds |
87
107
  ./spec/carddb/resources/records_spec.rb[1:4:3] | passed | 0.00009 seconds |
88
- ./spec/carddb/resources/rules_spec.rb[1:1:1] | passed | 0.00403 seconds |
89
- ./spec/carddb/resources/rules_spec.rb[1:2:1] | passed | 0.00419 seconds |
90
- ./spec/carddb_spec.rb[1:1] | passed | 0.00004 seconds |
91
- ./spec/carddb_spec.rb[1:2:1] | passed | 0.00003 seconds |
108
+ ./spec/carddb/resources/rules_spec.rb[1:1:1] | passed | 0.00391 seconds |
109
+ ./spec/carddb/resources/rules_spec.rb[1:2:1] | passed | 0.00372 seconds |
110
+ ./spec/carddb_spec.rb[1:1] | passed | 0.00008 seconds |
111
+ ./spec/carddb_spec.rb[1:2:1] | passed | 0.00005 seconds |
92
112
  ./spec/carddb_spec.rb[1:3:1] | passed | 0.00003 seconds |
93
113
  ./spec/carddb_spec.rb[1:4:1] | passed | 0.00004 seconds |
94
114
  ./spec/carddb_spec.rb[1:5:1] | passed | 0.00003 seconds |
data/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.1] - 2026-05-01
11
+
12
+ ### Fixed
13
+
14
+ - Fetch dataset schemas with recursive `nestedFields` selections to preserve deeper nested field definitions.
15
+
10
16
  ## [0.2.0] - 2026-04-29
11
17
 
12
18
  ### Added
data/carddb.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/carddb/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'carddb'
7
+ spec.version = CardDB::VERSION
8
+ spec.authors = ['CardDB Team']
9
+ spec.email = ['support@carddb.xtda.org']
10
+
11
+ spec.summary = 'Ruby client for the CardDB API'
12
+ spec.description = 'A Ruby client library for interacting with the CardDB GraphQL API. ' \
13
+ 'Search and fetch card game data with an expressive filter DSL.'
14
+ spec.homepage = 'https://github.com/xtda/carddb-ruby'
15
+ spec.license = 'MIT'
16
+ spec.required_ruby_version = '>= 3.0.0'
17
+
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = 'https://github.com/xtda/carddb-ruby'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/xtda/carddb-ruby/blob/main/CHANGELOG.md'
21
+ spec.metadata['rubygems_mfa_required'] = 'true'
22
+
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (File.expand_path(f) == __FILE__) ||
26
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
27
+ end
28
+ end
29
+ spec.bindir = 'exe'
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ['lib']
32
+
33
+ spec.add_dependency 'faraday', '~> 2.0'
34
+ spec.add_dependency 'faraday-retry', '~> 2.0'
35
+ end
@@ -436,6 +436,10 @@ module CardDB
436
436
  data['purpose']
437
437
  end
438
438
 
439
+ def tcgplayer_product_id_field_key
440
+ data['tcgplayerProductIdFieldKey']
441
+ end
442
+
439
443
  def visibility
440
444
  data['visibility']
441
445
  end
@@ -531,10 +535,11 @@ module CardDB
531
535
  #
532
536
  # @param first [Integer, nil] Maximum number of results
533
537
  # @param filter [Hash, nil] Filter conditions (alternative to block)
538
+ # @param include_pricing [Boolean] Include live TCGPlayer pricing when configured
534
539
  # @yield [FilterBuilder] Optional block for filter DSL
535
540
  # @return [Collection<Record>] Collection of records
536
541
  # @raise [CardDB::Error] If no client is available
537
- def records(first: nil, filter: nil, &block)
542
+ def records(first: nil, filter: nil, include_pricing: false, &block)
538
543
  raise Error, 'No client available to fetch records' unless client
539
544
 
540
545
  publisher_slug = publisher&.[]('slug')
@@ -549,6 +554,7 @@ module CardDB
549
554
  dataset_key: key,
550
555
  first: first,
551
556
  filter: filter,
557
+ include_pricing: include_pricing,
552
558
  &block
553
559
  )
554
560
  end
@@ -707,6 +713,10 @@ module CardDB
707
713
  @resolved_links ||= parse_resolved_links
708
714
  end
709
715
 
716
+ def pricing
717
+ data['pricing']
718
+ end
719
+
710
720
  def created_at
711
721
  parse_time(data['createdAt'])
712
722
  end
@@ -786,6 +796,99 @@ module CardDB
786
796
  @game ||= data['game'] ? Game.new(data['game'], client: client) : nil
787
797
  end
788
798
 
799
+ def slug
800
+ data['slug']
801
+ end
802
+
803
+ def identifier
804
+ data['identifier']
805
+ end
806
+
807
+ def title
808
+ data['title']
809
+ end
810
+
811
+ def description
812
+ data['description']
813
+ end
814
+
815
+ def format_key
816
+ data['formatKey']
817
+ end
818
+
819
+ def visibility
820
+ data['visibility']
821
+ end
822
+
823
+ def external_ref
824
+ data['externalRef']
825
+ end
826
+
827
+ def source_url
828
+ data['sourceUrl']
829
+ end
830
+
831
+ def metadata
832
+ data['metadata'] || {}
833
+ end
834
+
835
+ def entries
836
+ @entries ||= (data['entries'] || []).map { |entry| DeckEntry.new(entry, client: client) }
837
+ end
838
+
839
+ def latest_published_version
840
+ @latest_published_version ||= data['latestPublishedVersion'] ? DeckVersion.new(data['latestPublishedVersion'], client: client) : nil
841
+ end
842
+
843
+ def published_at
844
+ parse_time(data['publishedAt'])
845
+ end
846
+
847
+ def has_unpublished_changes?
848
+ !!data['hasUnpublishedChanges']
849
+ end
850
+
851
+ def created_at
852
+ parse_time(data['createdAt'])
853
+ end
854
+
855
+ def updated_at
856
+ parse_time(data['updatedAt'])
857
+ end
858
+
859
+ private
860
+
861
+ def parse_time(value)
862
+ return nil unless value
863
+
864
+ Time.parse(value)
865
+ rescue ArgumentError
866
+ value
867
+ end
868
+ end
869
+
870
+ # Wrapper for immutable published DeckVersion objects
871
+ class DeckVersion < Resource
872
+ def id
873
+ data['id']
874
+ end
875
+
876
+ def deck_id
877
+ data['deckId']
878
+ end
879
+
880
+ def version_number
881
+ data['versionNumber']
882
+ end
883
+
884
+ def slug
885
+ data['slug']
886
+ end
887
+
888
+ def identifier
889
+ data['identifier']
890
+ end
891
+
789
892
  def title
790
893
  data['title']
791
894
  end
@@ -818,6 +921,59 @@ module CardDB
818
921
  @entries ||= (data['entries'] || []).map { |entry| DeckEntry.new(entry, client: client) }
819
922
  end
820
923
 
924
+ def publish_note
925
+ data['publishNote']
926
+ end
927
+
928
+ def computed_diff
929
+ data['computedDiff'] || {}
930
+ end
931
+
932
+ def published_by_account_id
933
+ data['publishedByAccountId']
934
+ end
935
+
936
+ def published_by_api_application_id
937
+ data['publishedByApiApplicationId']
938
+ end
939
+
940
+ def created_at
941
+ parse_time(data['createdAt'])
942
+ end
943
+
944
+ private
945
+
946
+ def parse_time(value)
947
+ return nil unless value
948
+
949
+ Time.parse(value)
950
+ rescue ArgumentError
951
+ value
952
+ end
953
+ end
954
+
955
+ # Wrapper for deck collaborator objects
956
+ class DeckCollaborator < Resource
957
+ def id
958
+ data['id']
959
+ end
960
+
961
+ def deck_id
962
+ data['deckId']
963
+ end
964
+
965
+ def account_id
966
+ data['accountId']
967
+ end
968
+
969
+ def role
970
+ data['role']
971
+ end
972
+
973
+ def created_by_account_id
974
+ data['createdByAccountId']
975
+ end
976
+
821
977
  def created_at
822
978
  parse_time(data['createdAt'])
823
979
  end
@@ -837,6 +993,62 @@ module CardDB
837
993
  end
838
994
  end
839
995
 
996
+ # Wrapper for deck preview token metadata
997
+ class DeckPreviewToken < Resource
998
+ def id
999
+ data['id']
1000
+ end
1001
+
1002
+ def deck_id
1003
+ data['deckId']
1004
+ end
1005
+
1006
+ def label
1007
+ data['label']
1008
+ end
1009
+
1010
+ def expires_at
1011
+ parse_time(data['expiresAt'])
1012
+ end
1013
+
1014
+ def revoked_at
1015
+ parse_time(data['revokedAt'])
1016
+ end
1017
+
1018
+ def last_used_at
1019
+ parse_time(data['lastUsedAt'])
1020
+ end
1021
+
1022
+ def created_at
1023
+ parse_time(data['createdAt'])
1024
+ end
1025
+
1026
+ def updated_at
1027
+ parse_time(data['updatedAt'])
1028
+ end
1029
+
1030
+ private
1031
+
1032
+ def parse_time(value)
1033
+ return nil unless value
1034
+
1035
+ Time.parse(value)
1036
+ rescue ArgumentError
1037
+ value
1038
+ end
1039
+ end
1040
+
1041
+ # Wrapper for deck preview token creation payloads
1042
+ class DeckPreviewTokenCreatePayload < Resource
1043
+ def token
1044
+ data['token']
1045
+ end
1046
+
1047
+ def preview_token
1048
+ @preview_token ||= data['previewToken'] ? DeckPreviewToken.new(data['previewToken'], client: client) : nil
1049
+ end
1050
+ end
1051
+
840
1052
  # Wrapper for hosted DeckEntry objects
841
1053
  class DeckEntry < Resource
842
1054
  def id
@@ -4,6 +4,8 @@ module CardDB
4
4
  # Builds GraphQL queries for the CardDB API.
5
5
  # rubocop:disable Metrics/ModuleLength
6
6
  module QueryBuilder
7
+ SCHEMA_NESTED_FIELDS_DEPTH = 4
8
+
7
9
  # rubocop:disable Metrics/ClassLength
8
10
  class << self
9
11
  # Builds a searchPublishers query
@@ -163,6 +165,7 @@ module CardDB
163
165
  end
164
166
 
165
167
  # Builds a searchRecords query
168
+ # rubocop:disable Metrics/ParameterLists
166
169
  def search_records(
167
170
  publisher_slug:,
168
171
  game_key:,
@@ -173,7 +176,8 @@ module CardDB
173
176
  resolve_links: nil,
174
177
  first: nil,
175
178
  after: nil,
176
- validate_schema: nil
179
+ validate_schema: nil,
180
+ include_pricing: false
177
181
  )
178
182
  args = build_args(
179
183
  {
@@ -194,51 +198,55 @@ module CardDB
194
198
  <<~GRAPHQL
195
199
  query SearchRecords#{args[:definition]} {
196
200
  searchRecords#{args[:call]} {
197
- #{record_connection_fields(include_resolved_links: resolve_links&.any?)}
201
+ #{record_connection_fields(
202
+ include_resolved_links: resolve_links&.any?,
203
+ include_pricing: include_pricing
204
+ )}
198
205
  }
199
206
  }
200
207
  GRAPHQL
201
208
  end
209
+ # rubocop:enable Metrics/ParameterLists
202
210
 
203
211
  # Builds a fetchRecordByIdentifier query
204
- def fetch_record_by_identifier
212
+ def fetch_record_by_identifier(include_pricing: false)
205
213
  <<~GRAPHQL
206
214
  query FetchRecordByIdentifier($publisherSlug: String!, $gameKey: String!, $datasetKey: String!, $identifier: String!) {
207
215
  fetchRecordByIdentifier(publisherSlug: $publisherSlug, gameKey: $gameKey, datasetKey: $datasetKey, identifier: $identifier) {
208
- #{record_fields}
216
+ #{record_fields(include_pricing: include_pricing)}
209
217
  }
210
218
  }
211
219
  GRAPHQL
212
220
  end
213
221
 
214
222
  # Builds a fetchRecordsByIdentifier query
215
- def fetch_records_by_identifier
223
+ def fetch_records_by_identifier(include_pricing: false)
216
224
  <<~GRAPHQL
217
225
  query FetchRecordsByIdentifier($publisherSlug: String!, $gameKey: String!, $datasetKey: String!, $identifiers: [String!]!) {
218
226
  fetchRecordsByIdentifier(publisherSlug: $publisherSlug, gameKey: $gameKey, datasetKey: $datasetKey, identifiers: $identifiers) {
219
- #{record_fields}
227
+ #{record_fields(include_pricing: include_pricing)}
220
228
  }
221
229
  }
222
230
  GRAPHQL
223
231
  end
224
232
 
225
233
  # Builds a fetchRecord query
226
- def fetch_record
234
+ def fetch_record(include_pricing: false)
227
235
  <<~GRAPHQL
228
236
  query FetchRecord($id: UUID!) {
229
237
  fetchRecord(id: $id) {
230
- #{record_fields}
238
+ #{record_fields(include_pricing: include_pricing)}
231
239
  }
232
240
  }
233
241
  GRAPHQL
234
242
  end
235
243
 
236
244
  # Builds a fetchRecords query
237
- def fetch_records
245
+ def fetch_records(include_pricing: false)
238
246
  <<~GRAPHQL
239
247
  query FetchRecords($ids: [UUID!]!) {
240
248
  fetchRecords(ids: $ids) {
241
- #{record_fields}
249
+ #{record_fields(include_pricing: include_pricing)}
242
250
  }
243
251
  }
244
252
  GRAPHQL
@@ -268,6 +276,28 @@ module CardDB
268
276
  GRAPHQL
269
277
  end
270
278
 
279
+ # Builds a myDeck query
280
+ def my_deck
281
+ <<~GRAPHQL
282
+ query MyDeck($id: UUID!) {
283
+ myDeck(id: $id) {
284
+ #{deck_fields}
285
+ }
286
+ }
287
+ GRAPHQL
288
+ end
289
+
290
+ # Builds a fetchDeckBySlug query
291
+ def fetch_deck_by_slug
292
+ <<~GRAPHQL
293
+ query FetchDeckBySlug($publisherSlug: String!, $gameKey: String!, $slug: String!) {
294
+ fetchDeckBySlug(publisherSlug: $publisherSlug, gameKey: $gameKey, slug: $slug) {
295
+ #{deck_fields}
296
+ }
297
+ }
298
+ GRAPHQL
299
+ end
300
+
271
301
  # Builds a fetchDeckByExternalRef query
272
302
  def fetch_deck_by_external_ref
273
303
  <<~GRAPHQL
@@ -279,6 +309,63 @@ module CardDB
279
309
  GRAPHQL
280
310
  end
281
311
 
312
+ # Builds a deckVersion query
313
+ def deck_version
314
+ <<~GRAPHQL
315
+ query DeckVersion($id: UUID!) {
316
+ deckVersion(id: $id) {
317
+ #{deck_version_fields}
318
+ }
319
+ }
320
+ GRAPHQL
321
+ end
322
+
323
+ # Builds a deckVersions query
324
+ def deck_versions(first: nil, after: nil)
325
+ args = build_args({ deckId: true, first: first, after: after }, required: [:deckId])
326
+
327
+ <<~GRAPHQL
328
+ query DeckVersions#{args[:definition]} {
329
+ deckVersions#{args[:call]} {
330
+ #{deck_version_connection_fields}
331
+ }
332
+ }
333
+ GRAPHQL
334
+ end
335
+
336
+ # Builds a deckPreview query
337
+ def deck_preview
338
+ <<~GRAPHQL
339
+ query DeckPreview($token: String!) {
340
+ deckPreview(token: $token) {
341
+ #{deck_fields}
342
+ }
343
+ }
344
+ GRAPHQL
345
+ end
346
+
347
+ # Builds a deckCollaborators query
348
+ def deck_collaborators
349
+ <<~GRAPHQL
350
+ query DeckCollaborators($deckId: UUID!) {
351
+ deckCollaborators(deckId: $deckId) {
352
+ #{deck_collaborator_fields}
353
+ }
354
+ }
355
+ GRAPHQL
356
+ end
357
+
358
+ # Builds a deckPreviewTokens query
359
+ def deck_preview_tokens
360
+ <<~GRAPHQL
361
+ query DeckPreviewTokens($deckId: UUID!) {
362
+ deckPreviewTokens(deckId: $deckId) {
363
+ #{deck_preview_token_fields}
364
+ }
365
+ }
366
+ GRAPHQL
367
+ end
368
+
282
369
  # Builds a deckCreate mutation
283
370
  def create_deck
284
371
  <<~GRAPHQL
@@ -301,6 +388,60 @@ module CardDB
301
388
  GRAPHQL
302
389
  end
303
390
 
391
+ # Builds a deckPublish mutation
392
+ def publish_deck
393
+ <<~GRAPHQL
394
+ mutation DeckPublish($id: UUID!, $input: DeckPublishInput!) {
395
+ deckPublish(id: $id, input: $input) {
396
+ #{deck_version_fields}
397
+ }
398
+ }
399
+ GRAPHQL
400
+ end
401
+
402
+ # Builds a deckCollaboratorUpsert mutation
403
+ def upsert_deck_collaborator
404
+ <<~GRAPHQL
405
+ mutation DeckCollaboratorUpsert($deckId: UUID!, $accountId: UUID!, $role: DeckCollaboratorRole!) {
406
+ deckCollaboratorUpsert(deckId: $deckId, accountId: $accountId, role: $role) {
407
+ #{deck_collaborator_fields}
408
+ }
409
+ }
410
+ GRAPHQL
411
+ end
412
+
413
+ # Builds a deckCollaboratorRemove mutation
414
+ def remove_deck_collaborator
415
+ <<~GRAPHQL
416
+ mutation DeckCollaboratorRemove($deckId: UUID!, $accountId: UUID!) {
417
+ deckCollaboratorRemove(deckId: $deckId, accountId: $accountId)
418
+ }
419
+ GRAPHQL
420
+ end
421
+
422
+ # Builds a deckPreviewTokenCreate mutation
423
+ def create_deck_preview_token
424
+ <<~GRAPHQL
425
+ mutation DeckPreviewTokenCreate($input: DeckPreviewTokenCreateInput!) {
426
+ deckPreviewTokenCreate(input: $input) {
427
+ token
428
+ previewToken {
429
+ #{deck_preview_token_fields}
430
+ }
431
+ }
432
+ }
433
+ GRAPHQL
434
+ end
435
+
436
+ # Builds a deckPreviewTokenRevoke mutation
437
+ def revoke_deck_preview_token
438
+ <<~GRAPHQL
439
+ mutation DeckPreviewTokenRevoke($id: UUID!) {
440
+ deckPreviewTokenRevoke(id: $id)
441
+ }
442
+ GRAPHQL
443
+ end
444
+
304
445
  # Builds a deckDelete mutation
305
446
  def delete_deck
306
447
  <<~GRAPHQL
@@ -357,6 +498,7 @@ module CardDB
357
498
  first: 'Int',
358
499
  after: 'String',
359
500
  externalRef: 'String',
501
+ deckId: 'UUID!',
360
502
  validateSchema: 'Boolean',
361
503
  purpose: 'DatasetPurpose',
362
504
  id: 'UUID!',
@@ -471,6 +613,7 @@ module CardDB
471
613
  name
472
614
  description
473
615
  purpose
616
+ tcgplayerProductIdFieldKey
474
617
  visibility
475
618
  isArchived
476
619
  createdAt
@@ -492,29 +635,7 @@ module CardDB
492
635
  <<~FIELDS
493
636
  schema {
494
637
  fields {
495
- key
496
- label
497
- description
498
- type
499
- isRequired
500
- filterable
501
- searchable
502
- isIdentifier
503
- itemType
504
- displayFormat
505
- semanticType
506
- allowedValues
507
- nestedFields {
508
- key
509
- label
510
- description
511
- type
512
- isRequired
513
- filterable
514
- searchable
515
- itemType
516
- semanticType
517
- }
638
+ #{field_info_fields(depth: SCHEMA_NESTED_FIELDS_DEPTH)}
518
639
  }
519
640
  filterableFields
520
641
  searchableFields
@@ -529,6 +650,32 @@ module CardDB
529
650
  FIELDS
530
651
  end
531
652
 
653
+ def field_info_fields(depth:)
654
+ nested_fields = if depth.positive?
655
+ <<~FIELDS
656
+ nestedFields {
657
+ #{field_info_fields(depth: depth - 1)}
658
+ }
659
+ FIELDS
660
+ end
661
+
662
+ <<~FIELDS
663
+ key
664
+ label
665
+ description
666
+ type
667
+ isRequired
668
+ filterable
669
+ searchable
670
+ isIdentifier
671
+ itemType
672
+ displayFormat
673
+ semanticType
674
+ allowedValues
675
+ #{nested_fields}
676
+ FIELDS
677
+ end
678
+
532
679
  def dataset_connection_fields
533
680
  <<~FIELDS
534
681
  totalCount
@@ -547,11 +694,14 @@ module CardDB
547
694
  FIELDS
548
695
  end
549
696
 
550
- def record_fields
697
+ def record_fields(include_pricing: false)
698
+ pricing_fields = include_pricing ? tcgplayer_pricing_fields : ''
699
+
551
700
  <<~FIELDS
552
701
  id
553
702
  datasetId
554
703
  data
704
+ #{pricing_fields}
555
705
  createdAt
556
706
  updatedAt
557
707
  dataset {
@@ -564,7 +714,23 @@ module CardDB
564
714
  FIELDS
565
715
  end
566
716
 
567
- def record_connection_fields(include_resolved_links: false)
717
+ def tcgplayer_pricing_fields
718
+ <<~FIELDS
719
+ pricing {
720
+ productId
721
+ prices {
722
+ subTypeName
723
+ lowPrice
724
+ midPrice
725
+ highPrice
726
+ marketPrice
727
+ directLowPrice
728
+ }
729
+ }
730
+ FIELDS
731
+ end
732
+
733
+ def record_connection_fields(include_resolved_links: false, include_pricing: false)
568
734
  resolved_links_field = if include_resolved_links
569
735
  <<~FIELDS
570
736
  resolvedLinks {
@@ -593,7 +759,7 @@ module CardDB
593
759
  edges {
594
760
  cursor
595
761
  node {
596
- #{record_fields}
762
+ #{record_fields(include_pricing: include_pricing)}
597
763
  #{resolved_links_field}
598
764
  }
599
765
  }
@@ -606,6 +772,8 @@ module CardDB
606
772
  accountId
607
773
  apiApplicationId
608
774
  gameId
775
+ slug
776
+ identifier
609
777
  title
610
778
  description
611
779
  formatKey
@@ -613,6 +781,11 @@ module CardDB
613
781
  externalRef
614
782
  sourceUrl
615
783
  metadata
784
+ latestPublishedVersion {
785
+ #{deck_version_fields}
786
+ }
787
+ publishedAt
788
+ hasUnpublishedChanges
616
789
  createdAt
617
790
  updatedAt
618
791
  game {
@@ -634,6 +807,84 @@ module CardDB
634
807
  FIELDS
635
808
  end
636
809
 
810
+ def deck_version_fields
811
+ <<~FIELDS
812
+ id
813
+ deckId
814
+ versionNumber
815
+ slug
816
+ identifier
817
+ title
818
+ description
819
+ formatKey
820
+ visibility
821
+ externalRef
822
+ sourceUrl
823
+ metadata
824
+ publishNote
825
+ computedDiff
826
+ publishedByAccountId
827
+ publishedByApiApplicationId
828
+ createdAt
829
+ entries {
830
+ id
831
+ datasetId
832
+ recordId
833
+ identifier
834
+ quantity
835
+ section
836
+ sortOrder
837
+ annotations
838
+ record {
839
+ #{record_fields}
840
+ }
841
+ }
842
+ FIELDS
843
+ end
844
+
845
+ def deck_version_connection_fields
846
+ <<~FIELDS
847
+ totalCount
848
+ pageInfo {
849
+ hasNextPage
850
+ hasPreviousPage
851
+ startCursor
852
+ endCursor
853
+ }
854
+ edges {
855
+ cursor
856
+ node {
857
+ #{deck_version_fields}
858
+ }
859
+ }
860
+ FIELDS
861
+ end
862
+
863
+ def deck_collaborator_fields
864
+ <<~FIELDS
865
+ id
866
+ deckId
867
+ accountId
868
+ role
869
+ createdByAccountId
870
+ createdAt
871
+ updatedAt
872
+ FIELDS
873
+ end
874
+
875
+ def deck_preview_token_fields
876
+ <<~FIELDS
877
+ id
878
+ deckId
879
+ label
880
+ expiresAt
881
+ revokedAt
882
+ lastUsedAt
883
+ createdAt
884
+ updatedAt
885
+ FIELDS
886
+ end
887
+
637
888
  def deck_connection_fields
638
889
  <<~FIELDS
639
890
  totalCount
@@ -31,6 +31,31 @@ module CardDB
31
31
  end
32
32
  end
33
33
 
34
+ # Fetch one deck owned by the current account or API application.
35
+ def fetch_mine(id, cache: nil)
36
+ key = cache_key('decks', 'fetch_mine', id: id)
37
+ with_cache(key, resource: :decks, cache: cache) do
38
+ data = connection.execute(QueryBuilder.my_deck, { id: id })
39
+ data['myDeck'] ? Deck.new(data['myDeck'], client: client) : nil
40
+ end
41
+ end
42
+
43
+ # Fetch a hosted deck by canonical or historical slug.
44
+ def fetch_by_slug(slug:, publisher_slug: nil, game_key: nil, cache: nil)
45
+ resolved_publisher = resolve_publisher(publisher_slug)
46
+ resolved_game = resolve_game(game_key)
47
+ validate_access!(resolved_publisher, resolved_game)
48
+
49
+ key = cache_key('decks', 'fetch_by_slug', publisher_slug: resolved_publisher, game_key: resolved_game, slug: slug)
50
+ with_cache(key, resource: :decks, cache: cache) do
51
+ data = connection.execute(
52
+ QueryBuilder.fetch_deck_by_slug,
53
+ { publisherSlug: resolved_publisher, gameKey: resolved_game, slug: slug }
54
+ )
55
+ data['fetchDeckBySlug'] ? Deck.new(data['fetchDeckBySlug'], client: client) : nil
56
+ end
57
+ end
58
+
34
59
  # Fetch a hosted deck by external reference for the current API application.
35
60
  def fetch_by_external_ref(external_ref:, cache: nil)
36
61
  key = cache_key('decks', 'fetch_by_external_ref', external_ref: external_ref)
@@ -40,6 +65,60 @@ module CardDB
40
65
  end
41
66
  end
42
67
 
68
+ # Fetch one immutable published deck version.
69
+ def fetch_version(id, cache: nil)
70
+ key = cache_key('decks', 'fetch_version', id: id)
71
+ with_cache(key, resource: :decks, cache: cache) do
72
+ data = connection.execute(QueryBuilder.deck_version, { id: id })
73
+ data['deckVersion'] ? DeckVersion.new(data['deckVersion'], client: client) : nil
74
+ end
75
+ end
76
+
77
+ # List immutable published versions for a deck.
78
+ def list_versions(deck_id:, first: nil, after: nil, cache: nil)
79
+ query = QueryBuilder.deck_versions(first: first, after: after)
80
+ variables = build_variables(deckId: deck_id, first: first, after: after)
81
+ key = cache_key('decks', 'list_versions', **variables)
82
+
83
+ data = with_cache(key, resource: :decks, cache: cache) do
84
+ connection.execute(query, variables)
85
+ end
86
+
87
+ Collection.new(
88
+ data['deckVersions'],
89
+ item_class: DeckVersion,
90
+ next_page_loader: ->(cursor) { list_versions(deck_id: deck_id, first: first, after: cursor, cache: cache) },
91
+ client: client
92
+ )
93
+ end
94
+
95
+ # Fetch current draft data using a revocable preview token.
96
+ def preview(token:, cache: nil)
97
+ key = cache_key('decks', 'preview', token: token)
98
+ with_cache(key, resource: :decks, cache: cache) do
99
+ data = connection.execute(QueryBuilder.deck_preview, { token: token })
100
+ data['deckPreview'] ? Deck.new(data['deckPreview'], client: client) : nil
101
+ end
102
+ end
103
+
104
+ # List collaborators for a deck.
105
+ def collaborators(deck_id:, cache: nil)
106
+ key = cache_key('decks', 'collaborators', deck_id: deck_id)
107
+ with_cache(key, resource: :decks, cache: cache) do
108
+ data = connection.execute(QueryBuilder.deck_collaborators, { deckId: deck_id })
109
+ (data['deckCollaborators'] || []).map { |collaborator| DeckCollaborator.new(collaborator, client: client) }
110
+ end
111
+ end
112
+
113
+ # List draft preview tokens for a deck.
114
+ def preview_tokens(deck_id:, cache: nil)
115
+ key = cache_key('decks', 'preview_tokens', deck_id: deck_id)
116
+ with_cache(key, resource: :decks, cache: cache) do
117
+ data = connection.execute(QueryBuilder.deck_preview_tokens, { deckId: deck_id })
118
+ (data['deckPreviewTokens'] || []).map { |token| DeckPreviewToken.new(token, client: client) }
119
+ end
120
+ end
121
+
43
122
  # Create a hosted deck.
44
123
  def create(input:)
45
124
  data = connection.execute(QueryBuilder.create_deck, { input: input })
@@ -52,6 +131,46 @@ module CardDB
52
131
  Deck.new(data['deckUpdate'], client: client)
53
132
  end
54
133
 
134
+ # Publish the current draft as an immutable deck version.
135
+ def publish(id:, input: {})
136
+ data = connection.execute(QueryBuilder.publish_deck, { id: id, input: input })
137
+ DeckVersion.new(data['deckPublish'], client: client)
138
+ end
139
+
140
+ # Create or update a deck collaborator.
141
+ def upsert_collaborator(deck_id:, account_id:, role:)
142
+ data = connection.execute(
143
+ QueryBuilder.upsert_deck_collaborator,
144
+ { deckId: deck_id, accountId: account_id, role: role }
145
+ )
146
+ DeckCollaborator.new(data['deckCollaboratorUpsert'], client: client)
147
+ end
148
+
149
+ # Remove a deck collaborator.
150
+ # rubocop:disable Naming/PredicateMethod
151
+ def remove_collaborator(deck_id:, account_id:)
152
+ data = connection.execute(
153
+ QueryBuilder.remove_deck_collaborator,
154
+ { deckId: deck_id, accountId: account_id }
155
+ )
156
+ !!data['deckCollaboratorRemove']
157
+ end
158
+ # rubocop:enable Naming/PredicateMethod
159
+
160
+ # Create a revocable draft preview token.
161
+ def create_preview_token(input:)
162
+ data = connection.execute(QueryBuilder.create_deck_preview_token, { input: input })
163
+ DeckPreviewTokenCreatePayload.new(data['deckPreviewTokenCreate'], client: client)
164
+ end
165
+
166
+ # Revoke a draft preview token.
167
+ # rubocop:disable Naming/PredicateMethod
168
+ def revoke_preview_token(id:)
169
+ data = connection.execute(QueryBuilder.revoke_deck_preview_token, { id: id })
170
+ !!data['deckPreviewTokenRevoke']
171
+ end
172
+ # rubocop:enable Naming/PredicateMethod
173
+
55
174
  # Delete a hosted deck.
56
175
  # rubocop:disable Naming/PredicateMethod
57
176
  def delete(id:)
@@ -18,6 +18,7 @@ module CardDB
18
18
  # @param first [Integer, nil] Maximum number of results
19
19
  # @param after [String, nil] Cursor for pagination
20
20
  # @param validate_schema [Boolean, nil] Whether to validate against schema
21
+ # @param include_pricing [Boolean] Include live TCGPlayer pricing when configured
21
22
  # @yield [FilterBuilder] Optional block for filter DSL
22
23
  # @return [Collection<Record>] Collection of records
23
24
  #
@@ -35,7 +36,7 @@ module CardDB
35
36
  # dataset_key: "cards",
36
37
  # filter: { "type" => "creature" }
37
38
  # )
38
- # rubocop:disable Metrics/MethodLength
39
+ # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
39
40
  def search(
40
41
  dataset_key:,
41
42
  publisher_slug: nil,
@@ -47,6 +48,7 @@ module CardDB
47
48
  first: nil,
48
49
  after: nil,
49
50
  validate_schema: nil,
51
+ include_pricing: false,
50
52
  &block
51
53
  )
52
54
  resolved_publisher = resolve_publisher(publisher_slug)
@@ -71,7 +73,8 @@ module CardDB
71
73
  resolve_links: resolve_links,
72
74
  first: first,
73
75
  after: after,
74
- validate_schema: validate_schema
76
+ validate_schema: validate_schema,
77
+ include_pricing: include_pricing
75
78
  )
76
79
 
77
80
  variables = build_variables(
@@ -99,7 +102,8 @@ module CardDB
99
102
  order_by: order_by,
100
103
  resolve_links: resolve_links,
101
104
  first: first,
102
- validate_schema: validate_schema
105
+ validate_schema: validate_schema,
106
+ include_pricing: include_pricing
103
107
  }
104
108
 
105
109
  next_page_loader = lambda do |cursor|
@@ -113,17 +117,18 @@ module CardDB
113
117
  client: client
114
118
  )
115
119
  end
116
- # rubocop:enable Metrics/MethodLength
120
+ # rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
117
121
 
118
122
  # Fetch a single record by ID
119
123
  #
120
124
  # @param id [String] The record UUID
121
125
  # @param cache [Boolean, nil] Whether to cache (nil = use config setting)
126
+ # @param include_pricing [Boolean] Include live TCGPlayer pricing when configured
122
127
  # @return [Record, nil] The record or nil if not found
123
- def fetch(id, cache: nil)
124
- key = cache_key('records', 'fetch', id: id)
128
+ def fetch(id, cache: nil, include_pricing: false)
129
+ key = cache_key('records', 'fetch', id: id, include_pricing: include_pricing)
125
130
  with_cache(key, resource: :records, cache: cache) do
126
- query = QueryBuilder.fetch_record
131
+ query = QueryBuilder.fetch_record(include_pricing: include_pricing)
127
132
  data = connection.execute(query, { id: id })
128
133
 
129
134
  return nil unless data['fetchRecord']
@@ -142,20 +147,29 @@ module CardDB
142
147
  # @param publisher_slug [String, nil] Publisher slug (uses default if not provided)
143
148
  # @param game_key [String, nil] Game key (uses default if not provided)
144
149
  # @param cache [Boolean, nil] Whether to cache (nil = use config setting)
150
+ # @param include_pricing [Boolean] Include live TCGPlayer pricing when configured
145
151
  # @return [Record, nil] The record or nil if not found
146
152
  #
147
153
  # @example
148
154
  # record = client.records.get(identifier: "xy1-1", dataset_key: "cards")
149
- def get(identifier:, dataset_key:, publisher_slug: nil, game_key: nil, cache: nil)
155
+ def get(
156
+ identifier:,
157
+ dataset_key:,
158
+ publisher_slug: nil,
159
+ game_key: nil,
160
+ cache: nil,
161
+ include_pricing: false
162
+ )
150
163
  resolved_publisher = resolve_publisher(publisher_slug)
151
164
  resolved_game = resolve_game(game_key)
152
165
 
153
166
  validate_access!(resolved_publisher, resolved_game)
154
167
 
155
168
  key = cache_key('records', 'get', publisher_slug: resolved_publisher, game_key: resolved_game,
156
- dataset_key: dataset_key, identifier: identifier)
169
+ dataset_key: dataset_key, identifier: identifier,
170
+ include_pricing: include_pricing)
157
171
  with_cache(key, resource: :records, cache: cache) do
158
- query = QueryBuilder.fetch_record_by_identifier
172
+ query = QueryBuilder.fetch_record_by_identifier(include_pricing: include_pricing)
159
173
  variables = {
160
174
  publisherSlug: resolved_publisher,
161
175
  gameKey: resolved_game,
@@ -181,6 +195,7 @@ module CardDB
181
195
  # @param publisher_slug [String, nil] Publisher slug (uses default if not provided)
182
196
  # @param game_key [String, nil] Game key (uses default if not provided)
183
197
  # @param cache [Boolean, nil] Whether to cache (nil = use config setting)
198
+ # @param include_pricing [Boolean] Include live TCGPlayer pricing when configured
184
199
  # @return [Array<Record>] Matching records
185
200
  # @raise [ArgumentError] If more than 1000 identifiers are provided
186
201
  #
@@ -189,7 +204,14 @@ module CardDB
189
204
  # identifiers: ["xy1-1", "xy1-2"],
190
205
  # dataset_key: "cards"
191
206
  # )
192
- def get_many(identifiers:, dataset_key:, publisher_slug: nil, game_key: nil, cache: nil)
207
+ def get_many(
208
+ identifiers:,
209
+ dataset_key:,
210
+ publisher_slug: nil,
211
+ game_key: nil,
212
+ cache: nil,
213
+ include_pricing: false
214
+ )
193
215
  raise ArgumentError, 'Maximum 1000 identifiers allowed' if identifiers.length > 1000
194
216
  return [] if identifiers.empty?
195
217
 
@@ -204,10 +226,11 @@ module CardDB
204
226
  publisher_slug: resolved_publisher,
205
227
  game_key: resolved_game,
206
228
  dataset_key: dataset_key,
207
- identifiers: identifiers
229
+ identifiers: identifiers,
230
+ include_pricing: include_pricing
208
231
  )
209
232
  with_cache(key, resource: :records, cache: cache) do
210
- query = QueryBuilder.fetch_records_by_identifier
233
+ query = QueryBuilder.fetch_records_by_identifier(include_pricing: include_pricing)
211
234
  variables = {
212
235
  publisherSlug: resolved_publisher,
213
236
  gameKey: resolved_game,
@@ -224,12 +247,13 @@ module CardDB
224
247
  # Fetch multiple records by IDs
225
248
  #
226
249
  # @param ids [Array<String>] Array of record UUIDs (max 1000)
250
+ # @param include_pricing [Boolean] Include live TCGPlayer pricing when configured
227
251
  # @return [Array<Record>] Array of records
228
252
  # @raise [ArgumentError] If more than 1000 IDs provided
229
- def fetch_many(ids)
253
+ def fetch_many(ids, include_pricing: false)
230
254
  raise ArgumentError, 'Maximum 1000 IDs allowed' if ids.length > 1000
231
255
 
232
- query = QueryBuilder.fetch_records
256
+ query = QueryBuilder.fetch_records(include_pricing: include_pricing)
233
257
  data = connection.execute(query, { ids: ids })
234
258
 
235
259
  (data['fetchRecords'] || []).map { |r| Record.new(r, client: client) }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CardDB
4
- VERSION = '0.2.0'
4
+ VERSION = '0.2.2'
5
5
  end
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+ cd "$ROOT_DIR"
6
+
7
+ GEMSPEC="carddb.gemspec"
8
+
9
+ if ! command -v bundle >/dev/null 2>&1; then
10
+ printf 'bundle is required but was not found in PATH.\n' >&2
11
+ exit 1
12
+ fi
13
+
14
+ if [[ ! -f "$GEMSPEC" ]]; then
15
+ printf 'Expected %s in %s.\n' "$GEMSPEC" "$ROOT_DIR" >&2
16
+ exit 1
17
+ fi
18
+
19
+ version="$(ruby -Ilib -rcarddb/version -e 'print CardDB::VERSION')"
20
+ gem_file="pkg/carddb-${version}.gem"
21
+
22
+ if [[ -n "$(git status --porcelain)" ]]; then
23
+ printf 'Working tree has uncommitted changes. Commit or stash before publishing.\n' >&2
24
+ git status --short >&2
25
+ exit 1
26
+ fi
27
+
28
+ bundle exec rspec
29
+ bundle exec rubocop
30
+
31
+ rm -f "$gem_file"
32
+ gem build "$GEMSPEC" --output "$gem_file"
33
+ gem push "$gem_file"
34
+
35
+ printf 'Published carddb %s from %s.\n' "$version" "$gem_file"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carddb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - CardDB Team
@@ -53,6 +53,7 @@ files:
53
53
  - LICENSE.txt
54
54
  - README.md
55
55
  - Rakefile
56
+ - carddb.gemspec
56
57
  - examples/basic_usage.rb
57
58
  - examples/filtering.rb
58
59
  - examples/pagination.rb
@@ -74,6 +75,7 @@ files:
74
75
  - lib/carddb/resources/records.rb
75
76
  - lib/carddb/resources/rules.rb
76
77
  - lib/carddb/version.rb
78
+ - scripts/publish.sh
77
79
  homepage: https://github.com/xtda/carddb-ruby
78
80
  licenses:
79
81
  - MIT