carddb 0.3.5 → 0.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec_status +118 -114
- data/.rubocop.yml +1 -1
- data/README.md +26 -4
- data/carddb.gemspec +6 -5
- data/lib/carddb/batch.rb +51 -2
- data/lib/carddb/collection.rb +29 -6
- data/lib/carddb/configuration.rb +1 -1
- data/lib/carddb/deck_tokens.rb +197 -0
- data/lib/carddb/filter_builder.rb +4 -4
- data/lib/carddb/query_builder.rb +24 -0
- data/lib/carddb/resources/decks.rb +8 -0
- data/lib/carddb/resources/records.rb +4 -4
- data/lib/carddb/resources/rules.rb +6 -6
- data/lib/carddb/version.rb +1 -1
- data/lib/carddb.rb +3 -2
- metadata +22 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de0907aa6dd9a3634bac2ad6ffdad769417e63f152fd239983dde1a47fb941c4
|
|
4
|
+
data.tar.gz: 0657376eec78c8c10817b0bc7f1305c689878e74660056850433bfd806370c1a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70abf104f20c017127051549239e08175c61ed9d48e6ae2594c00019e8086dbd71603c922e88ff8b617a72b38801c3184b2c161d600b4f79c9e2089d558c9c45
|
|
7
|
+
data.tar.gz: 8a3a0960423e0df0fdee392f67777ea18937aa7d59d3d756345dab17c1a2637e1792d1a1930dafe65bf2e91a164f0f625923e25d2558c0b550b1f2f771437f0a
|
data/.rspec_status
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
example_id | status | run_time |
|
|
2
2
|
---------------------------------------------------------- | ------ | --------------- |
|
|
3
|
-
./spec/carddb/client_spec.rb[1:1:1] | passed | 0.
|
|
3
|
+
./spec/carddb/client_spec.rb[1:1:1] | passed | 0.00048 seconds |
|
|
4
4
|
./spec/carddb/client_spec.rb[1:1:2] | passed | 0.00004 seconds |
|
|
5
|
-
./spec/carddb/client_spec.rb[1:1:3] | passed | 0.
|
|
5
|
+
./spec/carddb/client_spec.rb[1:1:3] | passed | 0.00004 seconds |
|
|
6
6
|
./spec/carddb/client_spec.rb[1:1:4] | passed | 0.00003 seconds |
|
|
7
|
-
./spec/carddb/client_spec.rb[1:2:1] | passed | 0.
|
|
8
|
-
./spec/carddb/client_spec.rb[1:2:2] | passed | 0.
|
|
7
|
+
./spec/carddb/client_spec.rb[1:2:1] | passed | 0.00034 seconds |
|
|
8
|
+
./spec/carddb/client_spec.rb[1:2:2] | passed | 0.00024 seconds |
|
|
9
9
|
./spec/carddb/client_spec.rb[1:3:1] | passed | 0.00005 seconds |
|
|
10
10
|
./spec/carddb/client_spec.rb[1:4:1] | passed | 0.00004 seconds |
|
|
11
|
-
./spec/carddb/client_spec.rb[1:5:1] | passed | 0.
|
|
11
|
+
./spec/carddb/client_spec.rb[1:5:1] | passed | 0.00003 seconds |
|
|
12
12
|
./spec/carddb/client_spec.rb[1:6:1] | passed | 0.00003 seconds |
|
|
13
|
-
./spec/carddb/client_spec.rb[1:7:1] | passed | 0.
|
|
14
|
-
./spec/carddb/client_spec.rb[1:8:1] | passed | 0.
|
|
15
|
-
./spec/carddb/client_spec.rb[1:9:1] | passed | 0.
|
|
13
|
+
./spec/carddb/client_spec.rb[1:7:1] | passed | 0.00003 seconds |
|
|
14
|
+
./spec/carddb/client_spec.rb[1:8:1] | passed | 0.00003 seconds |
|
|
15
|
+
./spec/carddb/client_spec.rb[1:9:1] | passed | 0.00003 seconds |
|
|
16
16
|
./spec/carddb/client_spec.rb[1:10:1] | passed | 0.00003 seconds |
|
|
17
|
-
./spec/carddb/client_spec.rb[1:11:1] | passed | 0.
|
|
18
|
-
./spec/carddb/client_spec.rb[1:11:2] | passed | 0.
|
|
19
|
-
./spec/carddb/collection_spec.rb[1:1:1] | passed | 0.
|
|
20
|
-
./spec/carddb/collection_spec.rb[2:1:1] | passed | 0.
|
|
21
|
-
./spec/carddb/collection_spec.rb[3:1:1] | passed | 0.
|
|
22
|
-
./spec/carddb/collection_spec.rb[3:1:2] | passed | 0.
|
|
23
|
-
./spec/carddb/collection_spec.rb[3:1:3] | passed | 0.
|
|
24
|
-
./spec/carddb/collection_spec.rb[3:1:4] | passed | 0.
|
|
17
|
+
./spec/carddb/client_spec.rb[1:11:1] | passed | 0.00032 seconds |
|
|
18
|
+
./spec/carddb/client_spec.rb[1:11:2] | passed | 0.00978 seconds |
|
|
19
|
+
./spec/carddb/collection_spec.rb[1:1:1] | passed | 0.00006 seconds |
|
|
20
|
+
./spec/carddb/collection_spec.rb[2:1:1] | passed | 0.00004 seconds |
|
|
21
|
+
./spec/carddb/collection_spec.rb[3:1:1] | passed | 0.0026 seconds |
|
|
22
|
+
./spec/carddb/collection_spec.rb[3:1:2] | passed | 0.00014 seconds |
|
|
23
|
+
./spec/carddb/collection_spec.rb[3:1:3] | passed | 0.00039 seconds |
|
|
24
|
+
./spec/carddb/collection_spec.rb[3:1:4] | passed | 0.00056 seconds |
|
|
25
25
|
./spec/carddb/collection_spec.rb[3:1:5] | passed | 0.00005 seconds |
|
|
26
26
|
./spec/carddb/collection_spec.rb[4:1:1] | passed | 0.00016 seconds |
|
|
27
27
|
./spec/carddb/collection_spec.rb[4:1:2] | passed | 0.00014 seconds |
|
|
28
|
-
./spec/carddb/collection_spec.rb[4:1:3] | passed | 0.
|
|
29
|
-
./spec/carddb/collection_spec.rb[4:1:4] | passed | 0.
|
|
28
|
+
./spec/carddb/collection_spec.rb[4:1:3] | passed | 0.00015 seconds |
|
|
29
|
+
./spec/carddb/collection_spec.rb[4:1:4] | passed | 0.00004 seconds |
|
|
30
30
|
./spec/carddb/configuration_spec.rb[1:1:1] | passed | 0.00003 seconds |
|
|
31
31
|
./spec/carddb/configuration_spec.rb[1:1:2] | passed | 0.00003 seconds |
|
|
32
32
|
./spec/carddb/configuration_spec.rb[1:1:3] | passed | 0.00003 seconds |
|
|
@@ -37,135 +37,139 @@ example_id | status | run_time
|
|
|
37
37
|
./spec/carddb/configuration_spec.rb[1:2:2:1] | passed | 0.00003 seconds |
|
|
38
38
|
./spec/carddb/configuration_spec.rb[1:2:2:2] | passed | 0.00004 seconds |
|
|
39
39
|
./spec/carddb/configuration_spec.rb[1:3:1:1] | passed | 0.00003 seconds |
|
|
40
|
-
./spec/carddb/configuration_spec.rb[1:3:2:1] | passed | 0.
|
|
41
|
-
./spec/carddb/configuration_spec.rb[1:3:2:2] | passed | 0.
|
|
42
|
-
./spec/carddb/configuration_spec.rb[1:3:2:3] | passed | 0.
|
|
40
|
+
./spec/carddb/configuration_spec.rb[1:3:2:1] | passed | 0.00003 seconds |
|
|
41
|
+
./spec/carddb/configuration_spec.rb[1:3:2:2] | passed | 0.00004 seconds |
|
|
42
|
+
./spec/carddb/configuration_spec.rb[1:3:2:3] | passed | 0.00004 seconds |
|
|
43
43
|
./spec/carddb/configuration_spec.rb[1:4:1] | passed | 0.00003 seconds |
|
|
44
44
|
./spec/carddb/configuration_spec.rb[1:4:2] | passed | 0.00003 seconds |
|
|
45
|
-
./spec/carddb/configuration_spec.rb[1:5:1] | passed | 0.
|
|
45
|
+
./spec/carddb/configuration_spec.rb[1:5:1] | passed | 0.00004 seconds |
|
|
46
46
|
./spec/carddb/configuration_spec.rb[1:6:1] | passed | 0.00003 seconds |
|
|
47
47
|
./spec/carddb/configuration_spec.rb[1:6:2] | passed | 0.00003 seconds |
|
|
48
|
-
./spec/carddb/configuration_spec.rb[1:6:3] | passed | 0.
|
|
48
|
+
./spec/carddb/configuration_spec.rb[1:6:3] | passed | 0.00004 seconds |
|
|
49
49
|
./spec/carddb/configuration_spec.rb[1:7:1] | passed | 0.00003 seconds |
|
|
50
|
-
./spec/carddb/configuration_spec.rb[1:7:2] | passed | 0.
|
|
50
|
+
./spec/carddb/configuration_spec.rb[1:7:2] | passed | 0.00004 seconds |
|
|
51
51
|
./spec/carddb/configuration_spec.rb[1:7:3] | passed | 0.00004 seconds |
|
|
52
|
-
./spec/carddb/
|
|
52
|
+
./spec/carddb/deck_tokens_spec.rb[1:1:1] | passed | 0.00117 seconds |
|
|
53
|
+
./spec/carddb/deck_tokens_spec.rb[1:2:1] | passed | 0.0008 seconds |
|
|
54
|
+
./spec/carddb/deck_tokens_spec.rb[1:2:2] | passed | 0.00025 seconds |
|
|
55
|
+
./spec/carddb/deck_tokens_spec.rb[1:2:3] | passed | 0.00007 seconds |
|
|
56
|
+
./spec/carddb/filter_builder_spec.rb[1:1:1] | passed | 0.00004 seconds |
|
|
53
57
|
./spec/carddb/filter_builder_spec.rb[1:1:2] | passed | 0.00003 seconds |
|
|
54
|
-
./spec/carddb/filter_builder_spec.rb[1:1:3] | passed | 0.
|
|
55
|
-
./spec/carddb/filter_builder_spec.rb[1:1:4] | passed | 0.
|
|
58
|
+
./spec/carddb/filter_builder_spec.rb[1:1:3] | passed | 0.00004 seconds |
|
|
59
|
+
./spec/carddb/filter_builder_spec.rb[1:1:4] | passed | 0.00004 seconds |
|
|
56
60
|
./spec/carddb/filter_builder_spec.rb[1:1:5] | passed | 0.00003 seconds |
|
|
57
61
|
./spec/carddb/filter_builder_spec.rb[1:1:6] | passed | 0.00003 seconds |
|
|
58
62
|
./spec/carddb/filter_builder_spec.rb[1:1:7] | passed | 0.00003 seconds |
|
|
59
63
|
./spec/carddb/filter_builder_spec.rb[1:1:8] | passed | 0.00003 seconds |
|
|
60
|
-
./spec/carddb/filter_builder_spec.rb[1:2:1] | passed | 0.
|
|
64
|
+
./spec/carddb/filter_builder_spec.rb[1:2:1] | passed | 0.00004 seconds |
|
|
61
65
|
./spec/carddb/filter_builder_spec.rb[1:2:2] | passed | 0.00003 seconds |
|
|
62
66
|
./spec/carddb/filter_builder_spec.rb[1:2:3] | passed | 0.00003 seconds |
|
|
63
67
|
./spec/carddb/filter_builder_spec.rb[1:2:4] | passed | 0.00003 seconds |
|
|
64
|
-
./spec/carddb/filter_builder_spec.rb[1:2:5] | passed | 0.
|
|
65
|
-
./spec/carddb/filter_builder_spec.rb[1:2:6] | passed | 0.
|
|
68
|
+
./spec/carddb/filter_builder_spec.rb[1:2:5] | passed | 0.00004 seconds |
|
|
69
|
+
./spec/carddb/filter_builder_spec.rb[1:2:6] | passed | 0.00003 seconds |
|
|
66
70
|
./spec/carddb/filter_builder_spec.rb[1:2:7] | passed | 0.00003 seconds |
|
|
67
|
-
./spec/carddb/filter_builder_spec.rb[1:2:8] | passed | 0.
|
|
68
|
-
./spec/carddb/filter_builder_spec.rb[1:2:9] | passed | 0.
|
|
69
|
-
./spec/carddb/filter_builder_spec.rb[1:2:10] | passed | 0.
|
|
70
|
-
./spec/carddb/filter_builder_spec.rb[1:2:11] | passed | 0.
|
|
71
|
-
./spec/carddb/filter_builder_spec.rb[1:2:12] | passed | 0.
|
|
72
|
-
./spec/carddb/filter_builder_spec.rb[1:2:13] | passed | 0.
|
|
73
|
-
./spec/carddb/query_builder_spec.rb[1:1:1] | passed | 0.
|
|
71
|
+
./spec/carddb/filter_builder_spec.rb[1:2:8] | passed | 0.00003 seconds |
|
|
72
|
+
./spec/carddb/filter_builder_spec.rb[1:2:9] | passed | 0.00003 seconds |
|
|
73
|
+
./spec/carddb/filter_builder_spec.rb[1:2:10] | passed | 0.00003 seconds |
|
|
74
|
+
./spec/carddb/filter_builder_spec.rb[1:2:11] | passed | 0.00003 seconds |
|
|
75
|
+
./spec/carddb/filter_builder_spec.rb[1:2:12] | passed | 0.00003 seconds |
|
|
76
|
+
./spec/carddb/filter_builder_spec.rb[1:2:13] | passed | 0.00003 seconds |
|
|
77
|
+
./spec/carddb/query_builder_spec.rb[1:1:1] | passed | 0.00005 seconds |
|
|
74
78
|
./spec/carddb/query_builder_spec.rb[1:1:2] | passed | 0.00004 seconds |
|
|
75
|
-
./spec/carddb/query_builder_spec.rb[1:1:3] | passed | 0.
|
|
79
|
+
./spec/carddb/query_builder_spec.rb[1:1:3] | passed | 0.00003 seconds |
|
|
76
80
|
./spec/carddb/query_builder_spec.rb[1:2:1:1] | passed | 0.00005 seconds |
|
|
77
81
|
./spec/carddb/query_builder_spec.rb[1:2:2:1] | passed | 0.00004 seconds |
|
|
78
82
|
./spec/carddb/query_builder_spec.rb[1:3:1] | passed | 0.00004 seconds |
|
|
79
83
|
./spec/carddb/query_builder_spec.rb[1:3:2] | passed | 0.00004 seconds |
|
|
80
|
-
./spec/carddb/query_builder_spec.rb[1:4:1] | passed | 0.
|
|
84
|
+
./spec/carddb/query_builder_spec.rb[1:4:1] | passed | 0.00005 seconds |
|
|
81
85
|
./spec/carddb/query_builder_spec.rb[1:4:2] | passed | 0.00004 seconds |
|
|
82
|
-
./spec/carddb/query_builder_spec.rb[1:5:1] | passed | 0.
|
|
86
|
+
./spec/carddb/query_builder_spec.rb[1:5:1] | passed | 0.00003 seconds |
|
|
83
87
|
./spec/carddb/query_builder_spec.rb[1:5:2] | passed | 0.00004 seconds |
|
|
84
88
|
./spec/carddb/query_builder_spec.rb[1:5:3] | passed | 0.00004 seconds |
|
|
85
89
|
./spec/carddb/query_builder_spec.rb[1:5:4] | passed | 0.00003 seconds |
|
|
86
|
-
./spec/carddb/query_builder_spec.rb[1:5:5] | passed | 0.
|
|
87
|
-
./spec/carddb/query_builder_spec.rb[1:5:6] | passed | 0.
|
|
90
|
+
./spec/carddb/query_builder_spec.rb[1:5:5] | passed | 0.00005 seconds |
|
|
91
|
+
./spec/carddb/query_builder_spec.rb[1:5:6] | passed | 0.00004 seconds |
|
|
88
92
|
./spec/carddb/query_builder_spec.rb[1:5:7] | passed | 0.00004 seconds |
|
|
89
93
|
./spec/carddb/query_builder_spec.rb[1:6:1] | passed | 0.00006 seconds |
|
|
90
94
|
./spec/carddb/query_builder_spec.rb[1:6:2] | passed | 0.00006 seconds |
|
|
91
95
|
./spec/carddb/query_builder_spec.rb[1:6:3] | passed | 0.00005 seconds |
|
|
92
|
-
./spec/carddb/resources/datasets_spec.rb[1:1:1] | passed | 0.
|
|
93
|
-
./spec/carddb/resources/datasets_spec.rb[1:1:2] | passed | 0.
|
|
94
|
-
./spec/carddb/resources/datasets_spec.rb[1:2:1] | passed | 0.
|
|
95
|
-
./spec/carddb/resources/decks_spec.rb[1:1:1] | passed | 0.
|
|
96
|
-
./spec/carddb/resources/decks_spec.rb[1:1:2] | passed | 0.
|
|
97
|
-
./spec/carddb/resources/decks_spec.rb[1:1:3] | passed | 0.
|
|
98
|
-
./spec/carddb/resources/decks_spec.rb[1:1:4] | passed | 0.
|
|
99
|
-
./spec/carddb/resources/decks_spec.rb[1:2:1] | passed | 0.
|
|
100
|
-
./spec/carddb/resources/decks_spec.rb[1:2:2] | passed | 0.
|
|
96
|
+
./spec/carddb/resources/datasets_spec.rb[1:1:1] | passed | 0.00432 seconds |
|
|
97
|
+
./spec/carddb/resources/datasets_spec.rb[1:1:2] | passed | 0.00421 seconds |
|
|
98
|
+
./spec/carddb/resources/datasets_spec.rb[1:2:1] | passed | 0.00394 seconds |
|
|
99
|
+
./spec/carddb/resources/decks_spec.rb[1:1:1] | passed | 0.00406 seconds |
|
|
100
|
+
./spec/carddb/resources/decks_spec.rb[1:1:2] | passed | 0.00474 seconds |
|
|
101
|
+
./spec/carddb/resources/decks_spec.rb[1:1:3] | passed | 0.00426 seconds |
|
|
102
|
+
./spec/carddb/resources/decks_spec.rb[1:1:4] | passed | 0.00418 seconds |
|
|
103
|
+
./spec/carddb/resources/decks_spec.rb[1:2:1] | passed | 0.00451 seconds |
|
|
104
|
+
./spec/carddb/resources/decks_spec.rb[1:2:2] | passed | 0.01223 seconds |
|
|
101
105
|
./spec/carddb/resources/decks_spec.rb[1:2:3] | passed | 0.00007 seconds |
|
|
102
|
-
./spec/carddb/resources/decks_spec.rb[1:3:1] | passed | 0.
|
|
103
|
-
./spec/carddb/resources/decks_spec.rb[1:4:1] | passed | 0.
|
|
104
|
-
./spec/carddb/resources/decks_spec.rb[1:5:1] | passed | 0.
|
|
105
|
-
./spec/carddb/resources/decks_spec.rb[1:6:1] | passed | 0.
|
|
106
|
-
./spec/carddb/resources/decks_spec.rb[1:7:1] | passed | 0.
|
|
107
|
-
./spec/carddb/resources/decks_spec.rb[1:8:1] | passed | 0.
|
|
108
|
-
./spec/carddb/resources/decks_spec.rb[1:9:1] | passed | 0.
|
|
109
|
-
./spec/carddb/resources/decks_spec.rb[1:10:1] | passed | 0.
|
|
110
|
-
./spec/carddb/resources/decks_spec.rb[1:11:1] | passed | 0.
|
|
111
|
-
./spec/carddb/resources/decks_spec.rb[1:11:2] | passed | 0.
|
|
112
|
-
./spec/carddb/resources/decks_spec.rb[1:11:3] | passed | 0.
|
|
113
|
-
./spec/carddb/resources/decks_spec.rb[1:11:4] | passed | 0.
|
|
114
|
-
./spec/carddb/resources/decks_spec.rb[1:12:1] | passed | 0.
|
|
115
|
-
./spec/carddb/resources/decks_spec.rb[1:13:1] | passed | 0.
|
|
116
|
-
./spec/carddb/resources/decks_spec.rb[1:14:1] | passed | 0.
|
|
117
|
-
./spec/carddb/resources/decks_spec.rb[1:14:2] | passed | 0.
|
|
118
|
-
./spec/carddb/resources/decks_spec.rb[1:14:3] | passed | 0.
|
|
119
|
-
./spec/carddb/resources/decks_spec.rb[1:15:1] | passed | 0.
|
|
120
|
-
./spec/carddb/resources/decks_spec.rb[1:16:1] | passed | 0.
|
|
121
|
-
./spec/carddb/resources/decks_spec.rb[1:17:1] | passed | 0.
|
|
122
|
-
./spec/carddb/resources/decks_spec.rb[1:17:2] | passed | 0.
|
|
123
|
-
./spec/carddb/resources/decks_spec.rb[1:17:3] | passed | 0.
|
|
124
|
-
./spec/carddb/resources/decks_spec.rb[1:18:1] | passed | 0.
|
|
125
|
-
./spec/carddb/resources/decks_spec.rb[1:19:1] | passed | 0.
|
|
126
|
-
./spec/carddb/resources/decks_spec.rb[1:20:1] | passed | 0.
|
|
127
|
-
./spec/carddb/resources/decks_spec.rb[1:21:1] | passed | 0.
|
|
128
|
-
./spec/carddb/resources/decks_spec.rb[1:22:1] | passed | 0.
|
|
129
|
-
./spec/carddb/resources/decks_spec.rb[1:23:1] | passed | 0.
|
|
130
|
-
./spec/carddb/resources/decks_spec.rb[1:24:1] | passed | 0.
|
|
131
|
-
./spec/carddb/resources/decks_spec.rb[1:25:1] | passed | 0.
|
|
132
|
-
./spec/carddb/resources/games_spec.rb[1:1:1] | passed | 0.
|
|
106
|
+
./spec/carddb/resources/decks_spec.rb[1:3:1] | passed | 0.0047 seconds |
|
|
107
|
+
./spec/carddb/resources/decks_spec.rb[1:4:1] | passed | 0.00395 seconds |
|
|
108
|
+
./spec/carddb/resources/decks_spec.rb[1:5:1] | passed | 0.00425 seconds |
|
|
109
|
+
./spec/carddb/resources/decks_spec.rb[1:6:1] | passed | 0.00414 seconds |
|
|
110
|
+
./spec/carddb/resources/decks_spec.rb[1:7:1] | passed | 0.00413 seconds |
|
|
111
|
+
./spec/carddb/resources/decks_spec.rb[1:8:1] | passed | 0.00394 seconds |
|
|
112
|
+
./spec/carddb/resources/decks_spec.rb[1:9:1] | passed | 0.00409 seconds |
|
|
113
|
+
./spec/carddb/resources/decks_spec.rb[1:10:1] | passed | 0.00439 seconds |
|
|
114
|
+
./spec/carddb/resources/decks_spec.rb[1:11:1] | passed | 0.00466 seconds |
|
|
115
|
+
./spec/carddb/resources/decks_spec.rb[1:11:2] | passed | 0.00414 seconds |
|
|
116
|
+
./spec/carddb/resources/decks_spec.rb[1:11:3] | passed | 0.00433 seconds |
|
|
117
|
+
./spec/carddb/resources/decks_spec.rb[1:11:4] | passed | 0.00454 seconds |
|
|
118
|
+
./spec/carddb/resources/decks_spec.rb[1:12:1] | passed | 0.00424 seconds |
|
|
119
|
+
./spec/carddb/resources/decks_spec.rb[1:13:1] | passed | 0.00384 seconds |
|
|
120
|
+
./spec/carddb/resources/decks_spec.rb[1:14:1] | passed | 0.00444 seconds |
|
|
121
|
+
./spec/carddb/resources/decks_spec.rb[1:14:2] | passed | 0.00423 seconds |
|
|
122
|
+
./spec/carddb/resources/decks_spec.rb[1:14:3] | passed | 0.00618 seconds |
|
|
123
|
+
./spec/carddb/resources/decks_spec.rb[1:15:1] | passed | 0.00397 seconds |
|
|
124
|
+
./spec/carddb/resources/decks_spec.rb[1:16:1] | passed | 0.0038 seconds |
|
|
125
|
+
./spec/carddb/resources/decks_spec.rb[1:17:1] | passed | 0.00434 seconds |
|
|
126
|
+
./spec/carddb/resources/decks_spec.rb[1:17:2] | passed | 0.00494 seconds |
|
|
127
|
+
./spec/carddb/resources/decks_spec.rb[1:17:3] | passed | 0.00417 seconds |
|
|
128
|
+
./spec/carddb/resources/decks_spec.rb[1:18:1] | passed | 0.00456 seconds |
|
|
129
|
+
./spec/carddb/resources/decks_spec.rb[1:19:1] | passed | 0.00422 seconds |
|
|
130
|
+
./spec/carddb/resources/decks_spec.rb[1:20:1] | passed | 0.0039 seconds |
|
|
131
|
+
./spec/carddb/resources/decks_spec.rb[1:21:1] | passed | 0.00385 seconds |
|
|
132
|
+
./spec/carddb/resources/decks_spec.rb[1:22:1] | passed | 0.00398 seconds |
|
|
133
|
+
./spec/carddb/resources/decks_spec.rb[1:23:1] | passed | 0.00384 seconds |
|
|
134
|
+
./spec/carddb/resources/decks_spec.rb[1:24:1] | passed | 0.00415 seconds |
|
|
135
|
+
./spec/carddb/resources/decks_spec.rb[1:25:1] | passed | 0.00416 seconds |
|
|
136
|
+
./spec/carddb/resources/games_spec.rb[1:1:1] | passed | 0.00383 seconds |
|
|
133
137
|
./spec/carddb/resources/games_spec.rb[1:1:2] | passed | 0.00007 seconds |
|
|
134
|
-
./spec/carddb/resources/games_spec.rb[1:2:1] | passed | 0.
|
|
135
|
-
./spec/carddb/resources/games_spec.rb[1:2:2] | passed | 0.
|
|
136
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:1:1] | passed | 0.
|
|
137
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:1:2] | passed | 0.
|
|
138
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:1:3] | passed | 0.
|
|
139
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:2:1] | passed | 0.
|
|
140
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:2:2] | passed | 0.
|
|
141
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:3:1] | passed | 0.
|
|
142
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:3:2] | passed | 0.
|
|
143
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:3:3] | passed | 0.
|
|
144
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:4:1] | passed | 0.
|
|
145
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:4:2] | passed | 0.
|
|
146
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:4:3] | passed | 0.
|
|
147
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:5:1] | passed | 0.
|
|
148
|
-
./spec/carddb/resources/publisher_workflows_spec.rb[1:5:2] | passed | 0.
|
|
149
|
-
./spec/carddb/resources/publishers_spec.rb[1:1:1] | passed | 0.
|
|
150
|
-
./spec/carddb/resources/publishers_spec.rb[1:2:1] | passed | 0.
|
|
151
|
-
./spec/carddb/resources/records_spec.rb[1:1:1] | passed | 0.
|
|
152
|
-
./spec/carddb/resources/records_spec.rb[1:1:2] | passed | 0.
|
|
153
|
-
./spec/carddb/resources/records_spec.rb[1:1:3] | passed | 0.
|
|
154
|
-
./spec/carddb/resources/records_spec.rb[1:1:4] | passed | 0.
|
|
155
|
-
./spec/carddb/resources/records_spec.rb[1:2:1] | passed | 0.
|
|
156
|
-
./spec/carddb/resources/records_spec.rb[1:2:2] | passed | 0.
|
|
157
|
-
./spec/carddb/resources/records_spec.rb[1:2:3] | passed | 0.
|
|
158
|
-
./spec/carddb/resources/records_spec.rb[1:3:1] | passed | 0.
|
|
138
|
+
./spec/carddb/resources/games_spec.rb[1:2:1] | passed | 0.00378 seconds |
|
|
139
|
+
./spec/carddb/resources/games_spec.rb[1:2:2] | passed | 0.00867 seconds |
|
|
140
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:1:1] | passed | 0.00429 seconds |
|
|
141
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:1:2] | passed | 0.00532 seconds |
|
|
142
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:1:3] | passed | 0.00603 seconds |
|
|
143
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:2:1] | passed | 0.00554 seconds |
|
|
144
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:2:2] | passed | 0.00008 seconds |
|
|
145
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:3:1] | passed | 0.00495 seconds |
|
|
146
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:3:2] | passed | 0.00384 seconds |
|
|
147
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:3:3] | passed | 0.00383 seconds |
|
|
148
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:4:1] | passed | 0.00417 seconds |
|
|
149
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:4:2] | passed | 0.00543 seconds |
|
|
150
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:4:3] | passed | 0.00408 seconds |
|
|
151
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:5:1] | passed | 0.00518 seconds |
|
|
152
|
+
./spec/carddb/resources/publisher_workflows_spec.rb[1:5:2] | passed | 0.0042 seconds |
|
|
153
|
+
./spec/carddb/resources/publishers_spec.rb[1:1:1] | passed | 0.00414 seconds |
|
|
154
|
+
./spec/carddb/resources/publishers_spec.rb[1:2:1] | passed | 0.00415 seconds |
|
|
155
|
+
./spec/carddb/resources/records_spec.rb[1:1:1] | passed | 0.00403 seconds |
|
|
156
|
+
./spec/carddb/resources/records_spec.rb[1:1:2] | passed | 0.00486 seconds |
|
|
157
|
+
./spec/carddb/resources/records_spec.rb[1:1:3] | passed | 0.00014 seconds |
|
|
158
|
+
./spec/carddb/resources/records_spec.rb[1:1:4] | passed | 0.00005 seconds |
|
|
159
|
+
./spec/carddb/resources/records_spec.rb[1:2:1] | passed | 0.00406 seconds |
|
|
160
|
+
./spec/carddb/resources/records_spec.rb[1:2:2] | passed | 0.00564 seconds |
|
|
161
|
+
./spec/carddb/resources/records_spec.rb[1:2:3] | passed | 0.00388 seconds |
|
|
162
|
+
./spec/carddb/resources/records_spec.rb[1:3:1] | passed | 0.00376 seconds |
|
|
159
163
|
./spec/carddb/resources/records_spec.rb[1:3:2] | passed | 0.00011 seconds |
|
|
160
|
-
./spec/carddb/resources/records_spec.rb[1:4:1] | passed | 0.
|
|
161
|
-
./spec/carddb/resources/records_spec.rb[1:4:2] | passed | 0.
|
|
162
|
-
./spec/carddb/resources/records_spec.rb[1:4:3] | passed | 0.
|
|
163
|
-
./spec/carddb/resources/rules_spec.rb[1:1:1] | passed | 0.
|
|
164
|
-
./spec/carddb/resources/rules_spec.rb[1:2:1] | passed | 0.
|
|
164
|
+
./spec/carddb/resources/records_spec.rb[1:4:1] | passed | 0.00421 seconds |
|
|
165
|
+
./spec/carddb/resources/records_spec.rb[1:4:2] | passed | 0.00005 seconds |
|
|
166
|
+
./spec/carddb/resources/records_spec.rb[1:4:3] | passed | 0.0001 seconds |
|
|
167
|
+
./spec/carddb/resources/rules_spec.rb[1:1:1] | passed | 0.00411 seconds |
|
|
168
|
+
./spec/carddb/resources/rules_spec.rb[1:2:1] | passed | 0.00398 seconds |
|
|
165
169
|
./spec/carddb_spec.rb[1:1] | passed | 0.00004 seconds |
|
|
166
170
|
./spec/carddb_spec.rb[1:2:1] | passed | 0.00003 seconds |
|
|
167
171
|
./spec/carddb_spec.rb[1:3:1] | passed | 0.00003 seconds |
|
|
168
172
|
./spec/carddb_spec.rb[1:4:1] | passed | 0.00004 seconds |
|
|
169
|
-
./spec/carddb_spec.rb[1:5:1] | passed | 0.
|
|
170
|
-
./spec/carddb_spec.rb[1:6:1] | passed | 0.
|
|
173
|
+
./spec/carddb_spec.rb[1:5:1] | passed | 0.00005 seconds |
|
|
174
|
+
./spec/carddb_spec.rb[1:6:1] | passed | 0.00004 seconds |
|
|
171
175
|
./spec/carddb_spec.rb[1:7:1] | passed | 0.00003 seconds |
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CardDB Ruby Client
|
|
2
2
|
|
|
3
|
-
A Ruby client library for the [CardDB](https://carddb.
|
|
3
|
+
A Ruby client library for the [CardDB](https://carddb.dev) GraphQL API. Search and fetch card game data with an expressive filter DSL.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ gem 'carddb'
|
|
|
13
13
|
Or install from source:
|
|
14
14
|
|
|
15
15
|
```ruby
|
|
16
|
-
gem 'carddb', git: 'https://github.com/
|
|
16
|
+
gem 'carddb', git: 'https://github.com/carddb/carddb-ruby'
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
## Quick Start
|
|
@@ -56,7 +56,7 @@ CardDB.configure do |config|
|
|
|
56
56
|
config.api_key = "carddb_legacy_key" # Legacy low-level API key
|
|
57
57
|
|
|
58
58
|
# Endpoint (defaults to production)
|
|
59
|
-
config.endpoint = "https://carddb.
|
|
59
|
+
config.endpoint = "https://carddb.dev/query"
|
|
60
60
|
|
|
61
61
|
# Timeouts
|
|
62
62
|
config.timeout = 30 # Request timeout in seconds
|
|
@@ -584,7 +584,18 @@ access = client.decks.exchange_access_token(
|
|
|
584
584
|
|
|
585
585
|
deck = client.decks.access(token: access.token)
|
|
586
586
|
|
|
587
|
+
session = client.decks.exchange_session_token(
|
|
588
|
+
input: {
|
|
589
|
+
publisherSlug: "pokemon-company",
|
|
590
|
+
gameKey: "pokemon-tcg",
|
|
591
|
+
externalSubject: "user_123",
|
|
592
|
+
scopes: %w[DECKS_READ DECKS_WRITE DECKS_PUBLISH]
|
|
593
|
+
}
|
|
594
|
+
)
|
|
595
|
+
|
|
587
596
|
# Account sessions can also create trusted issuers for a selected API app.
|
|
597
|
+
key_pair = CardDB::DeckTokens.generate_direct_access_key_pair
|
|
598
|
+
|
|
588
599
|
client.decks.create_access_token_issuer(
|
|
589
600
|
input: {
|
|
590
601
|
deckId: upsert.deck.id,
|
|
@@ -593,10 +604,21 @@ client.decks.create_access_token_issuer(
|
|
|
593
604
|
directSigningKey: {
|
|
594
605
|
algorithm: "ED25519",
|
|
595
606
|
keyId: "prod-2026-01",
|
|
596
|
-
publicKey:
|
|
607
|
+
publicKey: key_pair[:public_key_base64]
|
|
597
608
|
}
|
|
598
609
|
}
|
|
599
610
|
)
|
|
611
|
+
|
|
612
|
+
token = CardDB::DeckTokens.sign_direct_access_token(
|
|
613
|
+
issuer_id: "issuer_uuid",
|
|
614
|
+
deck_id: upsert.deck.id,
|
|
615
|
+
api_application_id: "app_uuid",
|
|
616
|
+
key_id: "prod-2026-01",
|
|
617
|
+
private_key: key_pair[:private_key_pem],
|
|
618
|
+
read_mode: "FULL",
|
|
619
|
+
subject: "user_123",
|
|
620
|
+
expires_at: Time.now + 900
|
|
621
|
+
)
|
|
600
622
|
```
|
|
601
623
|
|
|
602
624
|
### Records
|
data/carddb.gemspec
CHANGED
|
@@ -6,18 +6,18 @@ Gem::Specification.new do |spec|
|
|
|
6
6
|
spec.name = 'carddb'
|
|
7
7
|
spec.version = CardDB::VERSION
|
|
8
8
|
spec.authors = ['CardDB Team']
|
|
9
|
-
spec.email = ['support@carddb.
|
|
9
|
+
spec.email = ['support@carddb.dev']
|
|
10
10
|
|
|
11
11
|
spec.summary = 'Ruby client for the CardDB API'
|
|
12
12
|
spec.description = 'A Ruby client library for interacting with the CardDB GraphQL API. ' \
|
|
13
13
|
'Search and fetch card game data with an expressive filter DSL.'
|
|
14
|
-
spec.homepage = 'https://
|
|
14
|
+
spec.homepage = 'https://carddb.dev'
|
|
15
15
|
spec.license = 'MIT'
|
|
16
|
-
spec.required_ruby_version = '>= 3.
|
|
16
|
+
spec.required_ruby_version = '>= 3.2.0'
|
|
17
17
|
|
|
18
18
|
spec.metadata['homepage_uri'] = spec.homepage
|
|
19
|
-
spec.metadata['source_code_uri'] = 'https://github.com/
|
|
20
|
-
spec.metadata['changelog_uri'] = 'https://github.com/
|
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/carddb/carddb-ruby'
|
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/carddb/carddb-ruby/blob/main/CHANGELOG.md'
|
|
21
21
|
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
22
22
|
|
|
23
23
|
spec.files = Dir.chdir(__dir__) do
|
|
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
|
30
30
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
31
31
|
spec.require_paths = ['lib']
|
|
32
32
|
|
|
33
|
+
spec.add_dependency 'ed25519', '~> 1.3'
|
|
33
34
|
spec.add_dependency 'faraday', '~> 2.0'
|
|
34
35
|
spec.add_dependency 'faraday-retry', '~> 2.0'
|
|
35
36
|
end
|
data/lib/carddb/batch.rb
CHANGED
|
@@ -52,6 +52,13 @@ module CardDB
|
|
|
52
52
|
BatchProxy.new(self, :records)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
# Access the Decks resource for batching
|
|
56
|
+
#
|
|
57
|
+
# @return [BatchProxy]
|
|
58
|
+
def decks
|
|
59
|
+
BatchProxy.new(self, :decks)
|
|
60
|
+
end
|
|
61
|
+
|
|
55
62
|
# Add an operation to the batch
|
|
56
63
|
#
|
|
57
64
|
# @param resource [Symbol] The resource type
|
|
@@ -120,6 +127,8 @@ module CardDB
|
|
|
120
127
|
build_dataset_query(op, index)
|
|
121
128
|
when :records
|
|
122
129
|
build_record_query(op, index)
|
|
130
|
+
when :decks
|
|
131
|
+
build_deck_query(op, index)
|
|
123
132
|
else
|
|
124
133
|
raise ArgumentError, "Unknown resource: #{op[:resource]}"
|
|
125
134
|
end
|
|
@@ -201,6 +210,27 @@ module CardDB
|
|
|
201
210
|
end
|
|
202
211
|
end
|
|
203
212
|
|
|
213
|
+
def build_deck_query(op, index)
|
|
214
|
+
case op[:method]
|
|
215
|
+
when :fetch
|
|
216
|
+
var_name = "deckId#{index}"
|
|
217
|
+
query = "#{op[:alias]}: fetchDeck(id: $#{var_name}) { #{deck_fields} }"
|
|
218
|
+
[query, { var_name => op[:args][0] }, { var_name => 'UUID' }]
|
|
219
|
+
when :get
|
|
220
|
+
if op[:kwargs][:external_ref]
|
|
221
|
+
var_name = "deckExternalRef#{index}"
|
|
222
|
+
query = "#{op[:alias]}: deckByExternalRef(externalRef: $#{var_name}) { #{deck_fields} }"
|
|
223
|
+
[query, { var_name => op[:kwargs][:external_ref] }, { var_name => 'String' }]
|
|
224
|
+
else
|
|
225
|
+
var_name = "deckId#{index}"
|
|
226
|
+
query = "#{op[:alias]}: deck(id: $#{var_name}) { #{deck_fields} }"
|
|
227
|
+
[query, { var_name => op[:args][0] }, { var_name => 'UUID' }]
|
|
228
|
+
end
|
|
229
|
+
else
|
|
230
|
+
raise ArgumentError, "Unsupported batch method for decks: #{op[:method]}"
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
204
234
|
def build_variable_definitions(variables)
|
|
205
235
|
return '' if variables.empty?
|
|
206
236
|
|
|
@@ -231,6 +261,8 @@ module CardDB
|
|
|
231
261
|
Dataset.new(result, client: @client)
|
|
232
262
|
when :records
|
|
233
263
|
Record.new(result, client: @client)
|
|
264
|
+
when :decks
|
|
265
|
+
Deck.new(result, client: @client)
|
|
234
266
|
else
|
|
235
267
|
result
|
|
236
268
|
end
|
|
@@ -263,6 +295,23 @@ module CardDB
|
|
|
263
295
|
def record_fields
|
|
264
296
|
'id datasetId data createdAt updatedAt dataset { id key name gameId publisherId }'
|
|
265
297
|
end
|
|
298
|
+
|
|
299
|
+
def deck_fields
|
|
300
|
+
[
|
|
301
|
+
'id ownerType ownerAccountId ownerApiApplicationId environment',
|
|
302
|
+
'createdByAccountId createdByApiApplicationId accountId apiApplicationId',
|
|
303
|
+
'gameId game { id key name publisher { id name slug } }',
|
|
304
|
+
'slug identifier title description formatKey visibility accessMode',
|
|
305
|
+
'discoverability state archivedAt deletedAt unpublishedAt',
|
|
306
|
+
'externalRefApiApplicationId externalRef externalSubjectRef',
|
|
307
|
+
'rulesetId sourceUrl metadata',
|
|
308
|
+
'entries { id datasetId recordId identifier quantity section sortOrder annotations display }',
|
|
309
|
+
'sectionDefinitions { key label description order default aliases minCards maxCards excludedFromDeckSize legalCardTypes metadata }',
|
|
310
|
+
'latestPublishedVersion { id deckId versionNumber slug identifier title description formatKey visibility state publishedAt }',
|
|
311
|
+
'publishedAt draftRevision draftUpdatedAt draftUpdatedByAccountId draftUpdatedByApiApplicationId',
|
|
312
|
+
'hasUnpublishedChanges createdAt updatedAt'
|
|
313
|
+
].join(' ')
|
|
314
|
+
end
|
|
266
315
|
end
|
|
267
316
|
|
|
268
317
|
# Proxy class for batching operations on a specific resource
|
|
@@ -279,8 +328,8 @@ module CardDB
|
|
|
279
328
|
end
|
|
280
329
|
|
|
281
330
|
# Proxy get calls to the batch
|
|
282
|
-
def get(**kwargs)
|
|
283
|
-
@batch.add_operation(resource: @resource, method: :get, kwargs: kwargs)
|
|
331
|
+
def get(*args, **kwargs)
|
|
332
|
+
@batch.add_operation(resource: @resource, method: :get, args: args, kwargs: kwargs)
|
|
284
333
|
nil # Return nil since we're batching
|
|
285
334
|
end
|
|
286
335
|
end
|
data/lib/carddb/collection.rb
CHANGED
|
@@ -30,8 +30,8 @@ module CardDB
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# Iterate over items
|
|
33
|
-
def each(&
|
|
34
|
-
items.each(&
|
|
33
|
+
def each(&)
|
|
34
|
+
items.each(&)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
# Check if there are more pages
|
|
@@ -242,8 +242,8 @@ module CardDB
|
|
|
242
242
|
data
|
|
243
243
|
end
|
|
244
244
|
|
|
245
|
-
def to_json(*
|
|
246
|
-
data.to_json(*
|
|
245
|
+
def to_json(*)
|
|
246
|
+
data.to_json(*)
|
|
247
247
|
end
|
|
248
248
|
|
|
249
249
|
private
|
|
@@ -581,7 +581,7 @@ module CardDB
|
|
|
581
581
|
# @yield [FilterBuilder] Optional block for filter DSL
|
|
582
582
|
# @return [Collection<Record>] Collection of records
|
|
583
583
|
# @raise [CardDB::Error] If no client is available
|
|
584
|
-
def records(first: nil, filter: nil, include_pricing: false, &
|
|
584
|
+
def records(first: nil, filter: nil, include_pricing: false, &)
|
|
585
585
|
raise Error, 'No client available to fetch records' unless client
|
|
586
586
|
|
|
587
587
|
publisher_slug = publisher&.[]('slug')
|
|
@@ -597,7 +597,7 @@ module CardDB
|
|
|
597
597
|
first: first,
|
|
598
598
|
filter: filter,
|
|
599
599
|
include_pricing: include_pricing,
|
|
600
|
-
&
|
|
600
|
+
&
|
|
601
601
|
)
|
|
602
602
|
end
|
|
603
603
|
|
|
@@ -1804,6 +1804,29 @@ module CardDB
|
|
|
1804
1804
|
end
|
|
1805
1805
|
end
|
|
1806
1806
|
|
|
1807
|
+
class DeckSessionToken < Resource
|
|
1808
|
+
def id = data['id']
|
|
1809
|
+
def account_id = data['accountId']
|
|
1810
|
+
def api_application_id = data['apiApplicationId']
|
|
1811
|
+
def game_id = data['gameId']
|
|
1812
|
+
def environment = data['environment']
|
|
1813
|
+
def external_subject = data['externalSubject']
|
|
1814
|
+
def scopes = data['scopes'] || []
|
|
1815
|
+
def expires_at = parse_time(data['expiresAt'])
|
|
1816
|
+
def revoked_at = parse_time(data['revokedAt'])
|
|
1817
|
+
def last_used_at = parse_time(data['lastUsedAt'])
|
|
1818
|
+
def created_at = parse_time(data['createdAt'])
|
|
1819
|
+
def updated_at = parse_time(data['updatedAt'])
|
|
1820
|
+
end
|
|
1821
|
+
|
|
1822
|
+
class DeckSessionTokenExchangePayload < Resource
|
|
1823
|
+
def token = data['token']
|
|
1824
|
+
|
|
1825
|
+
def session_token
|
|
1826
|
+
@session_token ||= data['sessionToken'] ? DeckSessionToken.new(data['sessionToken'], client: client) : nil
|
|
1827
|
+
end
|
|
1828
|
+
end
|
|
1829
|
+
|
|
1807
1830
|
class DeckSectionDefinition < Resource
|
|
1808
1831
|
def key = data['key']
|
|
1809
1832
|
def label = data['label']
|
data/lib/carddb/configuration.rb
CHANGED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
require 'ed25519'
|
|
5
|
+
require 'json'
|
|
6
|
+
require 'openssl'
|
|
7
|
+
|
|
8
|
+
module CardDB
|
|
9
|
+
# Server-side helpers for minting direct signed deck access tokens.
|
|
10
|
+
module DeckTokens
|
|
11
|
+
TOKEN_USE = 'carddb.deck_access.v1'
|
|
12
|
+
AUDIENCE = 'carddb.deck_access'
|
|
13
|
+
ED25519_PKCS8_PREFIX = [
|
|
14
|
+
'302e020100300506032b657004220420'
|
|
15
|
+
].pack('H*').freeze
|
|
16
|
+
READ_MODES = {
|
|
17
|
+
'PUBLIC' => 'public',
|
|
18
|
+
'EMBED' => 'embed',
|
|
19
|
+
'FULL' => 'full'
|
|
20
|
+
}.freeze
|
|
21
|
+
private_constant :READ_MODES
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
# Generate an Ed25519 keypair for CardDB direct deck access token signing.
|
|
25
|
+
#
|
|
26
|
+
# @return [Hash{Symbol => String}] Includes a PEM private key and the base64-encoded raw public key
|
|
27
|
+
def generate_direct_access_key_pair
|
|
28
|
+
signing_key = Ed25519::SigningKey.generate
|
|
29
|
+
|
|
30
|
+
{
|
|
31
|
+
private_key_pem: seed_to_pem(signing_key.to_bytes),
|
|
32
|
+
public_key_base64: Base64.strict_encode64(signing_key.verify_key.to_bytes)
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Sign a direct deck access token that CardDB can verify with the issuer public key.
|
|
37
|
+
#
|
|
38
|
+
# @param issuer_id [String]
|
|
39
|
+
# @param deck_id [String]
|
|
40
|
+
# @param api_application_id [String]
|
|
41
|
+
# @param key_id [String]
|
|
42
|
+
# @param private_key [OpenSSL::PKey::PKey, String] Ed25519 private key as an OpenSSL key or PEM/DER string
|
|
43
|
+
# @param read_mode [String] PUBLIC, EMBED, or FULL
|
|
44
|
+
# @param subject [String, nil]
|
|
45
|
+
# @param token_id [String, nil]
|
|
46
|
+
# @param issued_at [Time]
|
|
47
|
+
# @param expires_at [Time]
|
|
48
|
+
# @return [String]
|
|
49
|
+
# @raise [ArgumentError]
|
|
50
|
+
def sign_direct_access_token(issuer_id:, deck_id:, api_application_id:, key_id:, private_key:, read_mode:,
|
|
51
|
+
expires_at:, subject: nil, token_id: nil, issued_at: Time.now)
|
|
52
|
+
issued_at, expires_at = validate_signing_input!(
|
|
53
|
+
issuer_id: issuer_id,
|
|
54
|
+
deck_id: deck_id,
|
|
55
|
+
api_application_id: api_application_id,
|
|
56
|
+
key_id: key_id,
|
|
57
|
+
issued_at: issued_at,
|
|
58
|
+
expires_at: expires_at
|
|
59
|
+
)
|
|
60
|
+
normalized_read_mode = normalize_read_mode!(read_mode)
|
|
61
|
+
key = normalize_private_key!(private_key)
|
|
62
|
+
header = { alg: 'EdDSA', kid: key_id.strip }
|
|
63
|
+
payload = build_payload(
|
|
64
|
+
issuer_id: issuer_id,
|
|
65
|
+
deck_id: deck_id,
|
|
66
|
+
api_application_id: api_application_id,
|
|
67
|
+
read_mode: normalized_read_mode,
|
|
68
|
+
subject: subject,
|
|
69
|
+
token_id: token_id,
|
|
70
|
+
issued_at: issued_at,
|
|
71
|
+
expires_at: expires_at
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
encoded_header = base64url_encode(JSON.generate(header))
|
|
75
|
+
encoded_payload = base64url_encode(JSON.generate(payload))
|
|
76
|
+
signing_input = "#{encoded_header}.#{encoded_payload}"
|
|
77
|
+
signature = sign_with_private_key(key, signing_input)
|
|
78
|
+
|
|
79
|
+
[encoded_header, encoded_payload, base64url_encode(signature)].join('.')
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def validate_signing_input!(issuer_id:, deck_id:, api_application_id:, key_id:, issued_at:, expires_at:)
|
|
85
|
+
validate_required_string!(issuer_id, 'issuer_id')
|
|
86
|
+
validate_required_string!(deck_id, 'deck_id')
|
|
87
|
+
validate_required_string!(api_application_id, 'api_application_id')
|
|
88
|
+
validate_required_string!(key_id, 'key_id')
|
|
89
|
+
|
|
90
|
+
issued_at = normalize_time!(issued_at, 'issued_at')
|
|
91
|
+
expires_at = normalize_time!(expires_at, 'expires_at')
|
|
92
|
+
raise ArgumentError, 'expires_at must be after issued_at' unless expires_at > issued_at
|
|
93
|
+
|
|
94
|
+
[issued_at, expires_at]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def build_payload(issuer_id:, deck_id:, api_application_id:, read_mode:, subject:, token_id:, issued_at:,
|
|
98
|
+
expires_at:)
|
|
99
|
+
payload = {
|
|
100
|
+
token_use: TOKEN_USE,
|
|
101
|
+
deck_id: deck_id.strip,
|
|
102
|
+
app_id: api_application_id.strip,
|
|
103
|
+
read_mode: read_mode,
|
|
104
|
+
iss: issuer_id.strip,
|
|
105
|
+
aud: AUDIENCE,
|
|
106
|
+
iat: issued_at.to_i,
|
|
107
|
+
exp: expires_at.to_i
|
|
108
|
+
}
|
|
109
|
+
add_optional_claim!(payload, :sub, subject)
|
|
110
|
+
add_optional_claim!(payload, :jti, token_id)
|
|
111
|
+
payload
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def add_optional_claim!(payload, key, value)
|
|
115
|
+
trimmed = value&.strip
|
|
116
|
+
payload[key] = trimmed if trimmed&.length&.positive?
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def validate_required_string!(value, name)
|
|
120
|
+
raise ArgumentError, "#{name} is required" unless value.is_a?(String) && !value.strip.empty?
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def normalize_time!(value, name)
|
|
124
|
+
raise ArgumentError, "#{name} must be a Time" unless value.is_a?(Time)
|
|
125
|
+
|
|
126
|
+
value
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def normalize_read_mode!(read_mode)
|
|
130
|
+
READ_MODES.fetch(read_mode.to_s.upcase) do
|
|
131
|
+
raise ArgumentError, 'read_mode must be PUBLIC, EMBED, or FULL'
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def normalize_private_key!(private_key)
|
|
136
|
+
return private_key if private_key.is_a?(OpenSSL::PKey::PKey)
|
|
137
|
+
|
|
138
|
+
if private_key.is_a?(String)
|
|
139
|
+
key = try_read_openssl_private_key(private_key)
|
|
140
|
+
return key if key
|
|
141
|
+
|
|
142
|
+
seed = try_extract_seed(private_key)
|
|
143
|
+
return Ed25519::SigningKey.new(seed) if seed
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
raise ArgumentError, 'private_key must be an Ed25519 private key'
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def try_read_openssl_private_key(value)
|
|
150
|
+
key = OpenSSL::PKey.read(value)
|
|
151
|
+
key.sign(nil, 'carddb-test')
|
|
152
|
+
key
|
|
153
|
+
rescue OpenSSL::OpenSSLError, ArgumentError
|
|
154
|
+
nil
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def try_extract_seed(value)
|
|
158
|
+
der = decode_private_key_der(value)
|
|
159
|
+
return nil unless der.bytesize == ED25519_PKCS8_PREFIX.bytesize + Ed25519::KEY_SIZE
|
|
160
|
+
return nil unless der.start_with?(ED25519_PKCS8_PREFIX)
|
|
161
|
+
|
|
162
|
+
der.byteslice(ED25519_PKCS8_PREFIX.bytesize, Ed25519::KEY_SIZE)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def decode_private_key_der(value)
|
|
166
|
+
if value.include?('BEGIN PRIVATE KEY')
|
|
167
|
+
Base64.decode64(value.gsub(/-----BEGIN PRIVATE KEY-----|-----END PRIVATE KEY-----|\s+/, ''))
|
|
168
|
+
else
|
|
169
|
+
value
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def sign_with_private_key(private_key, message)
|
|
174
|
+
case private_key
|
|
175
|
+
when OpenSSL::PKey::PKey
|
|
176
|
+
private_key.sign(nil, message)
|
|
177
|
+
when Ed25519::SigningKey
|
|
178
|
+
private_key.sign(message)
|
|
179
|
+
else
|
|
180
|
+
raise ArgumentError, 'private_key must be an Ed25519 private key'
|
|
181
|
+
end
|
|
182
|
+
rescue OpenSSL::OpenSSLError, Ed25519::Error => e
|
|
183
|
+
raise ArgumentError, "private_key must be an Ed25519 private key: #{e.message}"
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def seed_to_pem(seed)
|
|
187
|
+
der = ED25519_PKCS8_PREFIX + seed
|
|
188
|
+
encoded = Base64.strict_encode64(der).scan(/.{1,64}/).join("\n")
|
|
189
|
+
"-----BEGIN PRIVATE KEY-----\n#{encoded}\n-----END PRIVATE KEY-----\n"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def base64url_encode(value)
|
|
193
|
+
Base64.urlsafe_encode64(value, padding: false)
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
@@ -36,9 +36,9 @@ module CardDB
|
|
|
36
36
|
#
|
|
37
37
|
# @yield Block to define filters
|
|
38
38
|
# @return [Hash] The filter hash
|
|
39
|
-
def self.build(&
|
|
39
|
+
def self.build(&)
|
|
40
40
|
builder = new
|
|
41
|
-
builder.instance_eval(&
|
|
41
|
+
builder.instance_eval(&)
|
|
42
42
|
builder.to_filter
|
|
43
43
|
end
|
|
44
44
|
|
|
@@ -62,9 +62,9 @@ module CardDB
|
|
|
62
62
|
#
|
|
63
63
|
# @yield Block to define OR conditions
|
|
64
64
|
# @return [self]
|
|
65
|
-
def any(&
|
|
65
|
+
def any(&)
|
|
66
66
|
or_builder = FilterBuilder.new
|
|
67
|
-
or_builder.instance_eval(&
|
|
67
|
+
or_builder.instance_eval(&)
|
|
68
68
|
or_conditions = or_builder.conditions_array
|
|
69
69
|
@or_groups << { '$or' => or_conditions } if or_conditions.any?
|
|
70
70
|
self
|
data/lib/carddb/query_builder.rb
CHANGED
|
@@ -1416,6 +1416,30 @@ module CardDB
|
|
|
1416
1416
|
GRAPHQL
|
|
1417
1417
|
end
|
|
1418
1418
|
|
|
1419
|
+
def exchange_deck_session_token
|
|
1420
|
+
<<~GRAPHQL
|
|
1421
|
+
mutation DeckSessionTokenExchange($input: DeckSessionTokenExchangeInput!) {
|
|
1422
|
+
deckSessionTokenExchange(input: $input) {
|
|
1423
|
+
token
|
|
1424
|
+
sessionToken {
|
|
1425
|
+
id
|
|
1426
|
+
accountId
|
|
1427
|
+
apiApplicationId
|
|
1428
|
+
gameId
|
|
1429
|
+
environment
|
|
1430
|
+
externalSubject
|
|
1431
|
+
scopes
|
|
1432
|
+
expiresAt
|
|
1433
|
+
revokedAt
|
|
1434
|
+
lastUsedAt
|
|
1435
|
+
createdAt
|
|
1436
|
+
updatedAt
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
GRAPHQL
|
|
1441
|
+
end
|
|
1442
|
+
|
|
1419
1443
|
def revoke_deck_access_token
|
|
1420
1444
|
<<~GRAPHQL
|
|
1421
1445
|
mutation DeckAccessTokenRevoke($id: UUID!) {
|
|
@@ -587,6 +587,14 @@ module CardDB
|
|
|
587
587
|
DeckAccessTokenExchangePayload.new(data['deckAccessTokenExchange'], client: client)
|
|
588
588
|
end
|
|
589
589
|
|
|
590
|
+
# Exchange the current secret API application credential for an app-owned deck session token.
|
|
591
|
+
def exchange_session_token(input:)
|
|
592
|
+
config.require_secret_credential!('decks.exchange_session_token')
|
|
593
|
+
|
|
594
|
+
data = connection.execute(QueryBuilder.exchange_deck_session_token, { input: input })
|
|
595
|
+
DeckSessionTokenExchangePayload.new(data['deckSessionTokenExchange'], client: client)
|
|
596
|
+
end
|
|
597
|
+
|
|
590
598
|
# rubocop:disable Naming/PredicateMethod
|
|
591
599
|
def revoke_access_token(id:)
|
|
592
600
|
config.require_secret_credential!('decks.revoke_access_token')
|
|
@@ -18,9 +18,9 @@ module CardDB
|
|
|
18
18
|
before: nil,
|
|
19
19
|
validate_schema: nil,
|
|
20
20
|
cache: nil,
|
|
21
|
-
&
|
|
21
|
+
&
|
|
22
22
|
)
|
|
23
|
-
final_filter = block_given? ? FilterBuilder.build(&
|
|
23
|
+
final_filter = block_given? ? FilterBuilder.build(&) : filter
|
|
24
24
|
query = QueryBuilder.list_dataset_records(
|
|
25
25
|
dataset_id: dataset_id,
|
|
26
26
|
filter: final_filter,
|
|
@@ -206,7 +206,7 @@ module CardDB
|
|
|
206
206
|
after: nil,
|
|
207
207
|
validate_schema: nil,
|
|
208
208
|
include_pricing: false,
|
|
209
|
-
&
|
|
209
|
+
&
|
|
210
210
|
)
|
|
211
211
|
resolved_publisher = resolve_publisher(publisher_slug)
|
|
212
212
|
resolved_game = resolve_game(game_key)
|
|
@@ -215,7 +215,7 @@ module CardDB
|
|
|
215
215
|
|
|
216
216
|
# Build filter from DSL block if provided
|
|
217
217
|
final_filter = if block_given?
|
|
218
|
-
FilterBuilder.build(&
|
|
218
|
+
FilterBuilder.build(&)
|
|
219
219
|
else
|
|
220
220
|
filter
|
|
221
221
|
end
|
|
@@ -27,22 +27,22 @@ module CardDB
|
|
|
27
27
|
#
|
|
28
28
|
# @param dataset_key [String] Rules dataset key (defaults to "rules")
|
|
29
29
|
# @return [Collection<Record>] Collection of rule records
|
|
30
|
-
def list(dataset_key: 'rules',
|
|
31
|
-
search_records(dataset_key: dataset_key,
|
|
30
|
+
def list(dataset_key: 'rules', **, &)
|
|
31
|
+
search_records(dataset_key: dataset_key, **, &)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# List deck/game formats from the game's formats dataset.
|
|
35
35
|
#
|
|
36
36
|
# @param dataset_key [String] Formats dataset key (defaults to "formats")
|
|
37
37
|
# @return [Collection<Record>] Collection of format records
|
|
38
|
-
def formats(dataset_key: 'formats',
|
|
39
|
-
search_records(dataset_key: dataset_key,
|
|
38
|
+
def formats(dataset_key: 'formats', **, &)
|
|
39
|
+
search_records(dataset_key: dataset_key, **, &)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
private
|
|
43
43
|
|
|
44
|
-
def search_records(dataset_key:,
|
|
45
|
-
client.records.search(dataset_key: dataset_key,
|
|
44
|
+
def search_records(dataset_key:, **, &)
|
|
45
|
+
client.records.search(dataset_key: dataset_key, **, &)
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
end
|
data/lib/carddb/version.rb
CHANGED
data/lib/carddb.rb
CHANGED
|
@@ -8,6 +8,7 @@ require_relative 'carddb/query_builder'
|
|
|
8
8
|
require_relative 'carddb/filter_builder'
|
|
9
9
|
require_relative 'carddb/collection'
|
|
10
10
|
require_relative 'carddb/cache'
|
|
11
|
+
require_relative 'carddb/deck_tokens'
|
|
11
12
|
require_relative 'carddb/resources/base'
|
|
12
13
|
require_relative 'carddb/resources/publishers'
|
|
13
14
|
require_relative 'carddb/resources/games'
|
|
@@ -185,8 +186,8 @@ module CardDB
|
|
|
185
186
|
# results[0] # => Game
|
|
186
187
|
# results[1] # => Game
|
|
187
188
|
# results[2] # => Publisher
|
|
188
|
-
def batch(&
|
|
189
|
-
default_client.batch(&
|
|
189
|
+
def batch(&)
|
|
190
|
+
default_client.batch(&)
|
|
190
191
|
end
|
|
191
192
|
end
|
|
192
193
|
end
|
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.3.
|
|
4
|
+
version: 0.3.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- CardDB Team
|
|
@@ -9,6 +9,20 @@ bindir: exe
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: ed25519
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.3'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.3'
|
|
12
26
|
- !ruby/object:Gem::Dependency
|
|
13
27
|
name: faraday
|
|
14
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -40,7 +54,7 @@ dependencies:
|
|
|
40
54
|
description: A Ruby client library for interacting with the CardDB GraphQL API. Search
|
|
41
55
|
and fetch card game data with an expressive filter DSL.
|
|
42
56
|
email:
|
|
43
|
-
- support@carddb.
|
|
57
|
+
- support@carddb.dev
|
|
44
58
|
executables: []
|
|
45
59
|
extensions: []
|
|
46
60
|
extra_rdoc_files: []
|
|
@@ -65,6 +79,7 @@ files:
|
|
|
65
79
|
- lib/carddb/collection.rb
|
|
66
80
|
- lib/carddb/configuration.rb
|
|
67
81
|
- lib/carddb/connection.rb
|
|
82
|
+
- lib/carddb/deck_tokens.rb
|
|
68
83
|
- lib/carddb/errors.rb
|
|
69
84
|
- lib/carddb/filter_builder.rb
|
|
70
85
|
- lib/carddb/query_builder.rb
|
|
@@ -81,13 +96,13 @@ files:
|
|
|
81
96
|
- lib/carddb/resources/rules.rb
|
|
82
97
|
- lib/carddb/version.rb
|
|
83
98
|
- scripts/publish.sh
|
|
84
|
-
homepage: https://
|
|
99
|
+
homepage: https://carddb.dev
|
|
85
100
|
licenses:
|
|
86
101
|
- MIT
|
|
87
102
|
metadata:
|
|
88
|
-
homepage_uri: https://
|
|
89
|
-
source_code_uri: https://github.com/
|
|
90
|
-
changelog_uri: https://github.com/
|
|
103
|
+
homepage_uri: https://carddb.dev
|
|
104
|
+
source_code_uri: https://github.com/carddb/carddb-ruby
|
|
105
|
+
changelog_uri: https://github.com/carddb/carddb-ruby/blob/main/CHANGELOG.md
|
|
91
106
|
rubygems_mfa_required: 'true'
|
|
92
107
|
rdoc_options: []
|
|
93
108
|
require_paths:
|
|
@@ -96,7 +111,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
96
111
|
requirements:
|
|
97
112
|
- - ">="
|
|
98
113
|
- !ruby/object:Gem::Version
|
|
99
|
-
version: 3.
|
|
114
|
+
version: 3.2.0
|
|
100
115
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
116
|
requirements:
|
|
102
117
|
- - ">="
|