bluejay 0.1.0.alpha.1

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.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +423 -0
  3. data/Cargo.toml +2 -0
  4. data/LICENSE +21 -0
  5. data/README.md +33 -0
  6. data/ext/Cargo.toml +17 -0
  7. data/ext/extconf.rb +6 -0
  8. data/ext/src/execution/coerce_result.rs +54 -0
  9. data/ext/src/execution/engine.rs +466 -0
  10. data/ext/src/execution/execution_error.rs +28 -0
  11. data/ext/src/execution/field_error.rs +8 -0
  12. data/ext/src/execution/key_store.rs +23 -0
  13. data/ext/src/execution.rs +10 -0
  14. data/ext/src/helpers/public_name.rs +21 -0
  15. data/ext/src/helpers/typed_frozen_r_array.rs +56 -0
  16. data/ext/src/helpers/wrapped_definition.rs +79 -0
  17. data/ext/src/helpers/wrapped_struct.rs +97 -0
  18. data/ext/src/helpers.rs +8 -0
  19. data/ext/src/lib.rs +10 -0
  20. data/ext/src/ruby_api/arguments_definition.rs +8 -0
  21. data/ext/src/ruby_api/coerce_input.rs +6 -0
  22. data/ext/src/ruby_api/coercion_error.rs +61 -0
  23. data/ext/src/ruby_api/custom_scalar_type_definition.rs +62 -0
  24. data/ext/src/ruby_api/enum_type_definition.rs +107 -0
  25. data/ext/src/ruby_api/enum_value_definition.rs +58 -0
  26. data/ext/src/ruby_api/enum_value_definitions.rs +8 -0
  27. data/ext/src/ruby_api/execution_error.rs +48 -0
  28. data/ext/src/ruby_api/execution_result.rs +40 -0
  29. data/ext/src/ruby_api/field_definition.rs +112 -0
  30. data/ext/src/ruby_api/fields_definition.rs +8 -0
  31. data/ext/src/ruby_api/input_fields_definition.rs +8 -0
  32. data/ext/src/ruby_api/input_object_type_definition.rs +138 -0
  33. data/ext/src/ruby_api/input_type_reference.rs +358 -0
  34. data/ext/src/ruby_api/input_value_definition.rs +98 -0
  35. data/ext/src/ruby_api/interface_implementation.rs +42 -0
  36. data/ext/src/ruby_api/interface_implementations.rs +8 -0
  37. data/ext/src/ruby_api/interface_type_definition.rs +82 -0
  38. data/ext/src/ruby_api/json_value.rs +111 -0
  39. data/ext/src/ruby_api/object_type_definition.rs +100 -0
  40. data/ext/src/ruby_api/output_type_reference.rs +238 -0
  41. data/ext/src/ruby_api/r_result.rs +84 -0
  42. data/ext/src/ruby_api/scalar.rs +45 -0
  43. data/ext/src/ruby_api/schema_definition.rs +270 -0
  44. data/ext/src/ruby_api/union_member_type.rs +41 -0
  45. data/ext/src/ruby_api/union_member_types.rs +8 -0
  46. data/ext/src/ruby_api/union_type_definition.rs +89 -0
  47. data/ext/src/ruby_api/validation_error.rs +63 -0
  48. data/ext/src/ruby_api.rs +75 -0
  49. data/lib/bluejay/base_input_type_reference.rb +13 -0
  50. data/lib/bluejay/base_output_type_reference.rb +15 -0
  51. data/lib/bluejay/custom_scalar_type.rb +40 -0
  52. data/lib/bluejay/enum_type.rb +44 -0
  53. data/lib/bluejay/ext.bundle +0 -0
  54. data/lib/bluejay/finalize.rb +27 -0
  55. data/lib/bluejay/input_type.rb +64 -0
  56. data/lib/bluejay/input_type_reference_shorthands.rb +28 -0
  57. data/lib/bluejay/interface_type.rb +60 -0
  58. data/lib/bluejay/json_value.rb +16 -0
  59. data/lib/bluejay/name_from_class.rb +18 -0
  60. data/lib/bluejay/object_type.rb +68 -0
  61. data/lib/bluejay/output_type_reference_shorthands.rb +28 -0
  62. data/lib/bluejay/schema.rb +63 -0
  63. data/lib/bluejay/union_type.rb +43 -0
  64. data/lib/bluejay/version.rb +5 -0
  65. data/lib/bluejay.rb +28 -0
  66. data/lib/rbi_ext/model.rb +64 -0
  67. data/lib/tapioca/dsl/compilers/input_type.rb +34 -0
  68. data/lib/tapioca/dsl/compilers/interface_type.rb +29 -0
  69. data/lib/tapioca/dsl/compilers/object_type.rb +43 -0
  70. data/lib/tapioca/dsl/compilers/schema.rb +42 -0
  71. metadata +131 -0
@@ -0,0 +1,84 @@
1
+ use magnus::{function, Error, Module, Value, TypedData, gc, DataTypeFunctions, method, Object, exception, rb_sys::AsRawValue};
2
+ use super::{root};
3
+ use crate::helpers::WrappedStruct;
4
+
5
+ #[derive(Clone, Debug, TypedData)]
6
+ #[magnus(class = "Bluejay::Result", mark)]
7
+ pub struct RResult(Result<Value, Value>);
8
+
9
+ impl RResult {
10
+ fn is_ok(&self) -> bool {
11
+ self.0.is_ok()
12
+ }
13
+
14
+ fn is_err(&self) -> bool {
15
+ self.0.is_err()
16
+ }
17
+
18
+ fn unwrap_err(&self) -> Result<Value, Error> {
19
+ match self.0 {
20
+ Ok(_) => Err(Error::new(
21
+ exception::runtime_error(),
22
+ "Ok variant does not have an error value".to_owned(),
23
+ )),
24
+ Err(err) => Ok(err),
25
+ }
26
+ }
27
+
28
+ fn unwrap(&self) -> Result<Value, Error> {
29
+ match self.0 {
30
+ Ok(ok) => Ok(ok),
31
+ Err(_) => Err(Error::new(
32
+ exception::runtime_error(),
33
+ "Error variant does not have an ok value".to_owned(),
34
+ )),
35
+ }
36
+ }
37
+
38
+ fn inspect(rb_self: WrappedStruct<Self>) -> Result<String, Error> {
39
+ let rs_self = rb_self.get();
40
+
41
+ Ok(format!(
42
+ "#<Bluejay::Result:0x{:016x} @{}={:?}>",
43
+ rb_self.to_value().as_raw(),
44
+ match rs_self.0 {
45
+ Ok(_) => "ok_value",
46
+ Err(_) => "error_value"
47
+ },
48
+ match rs_self.0 {
49
+ Ok(val) => val,
50
+ Err(val) => val,
51
+ },
52
+ ))
53
+ }
54
+ }
55
+
56
+ impl DataTypeFunctions for RResult {
57
+ fn mark(&self) {
58
+ let value = match &self.0 {
59
+ Ok(ok) => ok,
60
+ Err(err) => err,
61
+ };
62
+ gc::mark(value)
63
+ }
64
+ }
65
+
66
+ impl<T: Into<Value>, E: Into<Value>> From<Result<T, E>> for RResult {
67
+ fn from(r: Result<T, E>) -> Self {
68
+ Self(r.map(Into::into).map_err(Into::into))
69
+ }
70
+ }
71
+
72
+ pub fn init() -> Result<(), Error> {
73
+ let class = root().define_class("Result", Default::default())?;
74
+
75
+ // class.define_singleton_method("new", function!(RResult::new, 1))?;
76
+ class.define_singleton_method("[]", function!(|_: Value, _: Value| RResult::class(), 2))?;
77
+ class.define_method("ok?", method!(RResult::is_ok, 0))?;
78
+ class.define_method("err?", method!(RResult::is_err, 0))?;
79
+ class.define_method("unwrap", method!(RResult::unwrap, 0))?;
80
+ class.define_method("unwrap_err", method!(RResult::unwrap_err, 0))?;
81
+ class.define_method("inspect", method!(RResult::inspect, 0))?;
82
+
83
+ Ok(())
84
+ }
@@ -0,0 +1,45 @@
1
+ use bluejay_core::BuiltinScalarDefinition;
2
+ use magnus::{Error, Module, TypedData, DataTypeFunctions};
3
+ use super::{root};
4
+
5
+ #[derive(Clone, Debug, TypedData)]
6
+ #[magnus(class = "Bluejay::Scalar", mark)]
7
+ pub struct Scalar(BuiltinScalarDefinition);
8
+
9
+ impl DataTypeFunctions for Scalar {}
10
+
11
+ impl Into<BuiltinScalarDefinition> for Scalar {
12
+ fn into(self) -> BuiltinScalarDefinition {
13
+ self.0
14
+ }
15
+ }
16
+
17
+ impl From<BuiltinScalarDefinition> for Scalar {
18
+ fn from(value: BuiltinScalarDefinition) -> Self {
19
+ Self(value)
20
+ }
21
+ }
22
+
23
+ impl Scalar {
24
+ pub fn sorbet_type_fully_qualified_name(&self) -> &str {
25
+ match self.0 {
26
+ BuiltinScalarDefinition::Boolean => "T::Boolean",
27
+ BuiltinScalarDefinition::Float => "Float",
28
+ BuiltinScalarDefinition::ID => "T.any(String, Integer)",
29
+ BuiltinScalarDefinition::Int => "Integer",
30
+ BuiltinScalarDefinition::String => "String",
31
+ }
32
+ }
33
+ }
34
+
35
+ pub fn init() -> Result<(), Error> {
36
+ let class = root().define_class("Scalar", Default::default())?;
37
+
38
+ class.const_set("Int", Scalar(BuiltinScalarDefinition::Int))?;
39
+ class.const_set("Float", Scalar(BuiltinScalarDefinition::Float))?;
40
+ class.const_set("String", Scalar(BuiltinScalarDefinition::String))?;
41
+ class.const_set("Boolean", Scalar(BuiltinScalarDefinition::Boolean))?;
42
+ class.const_set("ID", Scalar(BuiltinScalarDefinition::ID))?;
43
+
44
+ Ok(())
45
+ }
@@ -0,0 +1,270 @@
1
+ use std::collections::{HashMap, hash_map::Entry};
2
+ use super::object_type_definition::ObjectTypeDefinition;
3
+ use super::input_object_type_definition::InputObjectTypeDefinition;
4
+ use super::enum_type_definition::EnumTypeDefinition;
5
+ use super::union_type_definition::UnionTypeDefinition;
6
+ use super::interface_type_definition::InterfaceTypeDefinition;
7
+ use super::custom_scalar_type_definition::CustomScalarTypeDefinition;
8
+ use super::input_value_definition::InputValueDefinition;
9
+ use super::field_definition::FieldDefinition;
10
+ use super::input_fields_definition::InputFieldsDefinition;
11
+ use super::arguments_definition::ArgumentsDefinition;
12
+ use super::fields_definition::FieldsDefinition;
13
+ use super::interface_implementation::InterfaceImplementation;
14
+ use super::interface_implementations::InterfaceImplementations;
15
+ use super::union_member_type::UnionMemberType;
16
+ use super::union_member_types::UnionMemberTypes;
17
+ use super::validation_error::ValidationError;
18
+ use super::{root, ExecutionResult, BaseInputTypeReference, InputTypeReference, BaseOutputTypeReference, OutputTypeReference};
19
+ use crate::helpers::{WrappedStruct, WrappedDefinition};
20
+ use crate::execution::{Engine as ExecutionEngine};
21
+ use magnus::{function, Error, Module, Object, scan_args::get_kwargs, RHash, RArray, Value, TypedData, DataTypeFunctions, method};
22
+ use bluejay_core::validation::executable::Validator;
23
+ use bluejay_core::{BuiltinScalarDefinition, IntoEnumIterator, AsIter};
24
+
25
+ #[derive(Clone, Debug, TypedData)]
26
+ #[magnus(class = "Bluejay::SchemaDefinition", mark)]
27
+ pub struct SchemaDefinition {
28
+ description: Option<String>,
29
+ query: WrappedDefinition<ObjectTypeDefinition>,
30
+ mutation: Option<WrappedDefinition<ObjectTypeDefinition>>,
31
+ contained_types: HashMap<String, TypeDefinitionReference>,
32
+ }
33
+
34
+ impl SchemaDefinition {
35
+ pub fn new(kw: RHash) -> Result<Self, Error> {
36
+ let args = get_kwargs(kw, &["description", "query", "mutation"], &[])?;
37
+ let (description, query, mutation): (Option<String>, WrappedDefinition<ObjectTypeDefinition>, Option<WrappedDefinition<ObjectTypeDefinition>>) = args.required;
38
+ let _: () = args.optional;
39
+ let _: () = args.splat;
40
+ let contained_types = SchemaTypeVisitor::compute_contained_types(&query, mutation.as_ref());
41
+ Ok(Self { description, query, mutation, contained_types })
42
+ }
43
+
44
+ pub fn query(&self) -> WrappedStruct<ObjectTypeDefinition> {
45
+ *self.query.get()
46
+ }
47
+
48
+ pub fn r#type(&self, name: &str) -> Option<&TypeDefinitionReference> {
49
+ self.contained_types.get(name)
50
+ }
51
+
52
+ fn execute(&self, query: String, operation_name: Option<String>, variable_values: RHash, initial_value: Value) -> Result<ExecutionResult, Error> {
53
+ ExecutionEngine::execute_request(self, query.as_str(), operation_name.as_ref().map(String::as_str), variable_values, initial_value)
54
+ }
55
+
56
+ fn validate_query(&self, query: String) -> RArray {
57
+ let (document, _) = bluejay_parser::parse(query.as_str());
58
+
59
+ RArray::from_iter(
60
+ Validator::validate(&document, self)
61
+ .map(|error| -> WrappedStruct<ValidationError> {
62
+ WrappedStruct::wrap(error.into())
63
+ })
64
+ )
65
+ }
66
+ }
67
+
68
+ impl DataTypeFunctions for SchemaDefinition {
69
+ fn mark(&self) {
70
+ self.query.mark();
71
+ if let Some(mutation) = &self.mutation {
72
+ mutation.mark();
73
+ }
74
+ }
75
+ }
76
+
77
+ pub type TypeDefinitionReference = bluejay_core::definition::TypeDefinitionReference<
78
+ CustomScalarTypeDefinition,
79
+ WrappedDefinition<CustomScalarTypeDefinition>,
80
+ ObjectTypeDefinition,
81
+ WrappedDefinition<ObjectTypeDefinition>,
82
+ InputObjectTypeDefinition,
83
+ WrappedDefinition<InputObjectTypeDefinition>,
84
+ EnumTypeDefinition,
85
+ WrappedDefinition<EnumTypeDefinition>,
86
+ UnionTypeDefinition,
87
+ WrappedDefinition<UnionTypeDefinition>,
88
+ InterfaceTypeDefinition,
89
+ WrappedDefinition<InterfaceTypeDefinition>,
90
+ >;
91
+
92
+ impl<'a> bluejay_core::definition::SchemaDefinition<'a> for SchemaDefinition {
93
+ type InputValueDefinition = InputValueDefinition;
94
+ type InputFieldsDefinition = InputFieldsDefinition;
95
+ type ArgumentsDefinition = ArgumentsDefinition;
96
+ type FieldDefinition = FieldDefinition;
97
+ type FieldsDefinition = FieldsDefinition;
98
+ type InterfaceImplementation = InterfaceImplementation;
99
+ type InterfaceImplementations = InterfaceImplementations;
100
+ type UnionMemberType = UnionMemberType;
101
+ type UnionMemberTypes = UnionMemberTypes;
102
+ type BaseInputTypeReference = BaseInputTypeReference;
103
+ type InputTypeReference = InputTypeReference;
104
+ type BaseOutputTypeReference = BaseOutputTypeReference;
105
+ type OutputTypeReference = OutputTypeReference;
106
+ type CustomScalarTypeDefinition = CustomScalarTypeDefinition;
107
+ type ObjectTypeDefinition = ObjectTypeDefinition;
108
+ type InterfaceTypeDefinition = InterfaceTypeDefinition;
109
+ type UnionTypeDefinition = UnionTypeDefinition;
110
+ type InputObjectTypeDefinition = InputObjectTypeDefinition;
111
+ type EnumTypeDefinition = EnumTypeDefinition;
112
+ type TypeDefinitionReference = TypeDefinitionReference;
113
+
114
+ fn description(&self) -> Option<&str> {
115
+ self.description.as_ref().map(String::as_str)
116
+ }
117
+
118
+ fn query(&self) -> &Self::ObjectTypeDefinition {
119
+ self.query.as_ref()
120
+ }
121
+
122
+ fn mutation(&self) -> Option<&Self::ObjectTypeDefinition> {
123
+ self.mutation.as_ref().map(AsRef::as_ref)
124
+ }
125
+
126
+ fn get_type(&self, name: &str) -> Option<&Self::TypeDefinitionReference> {
127
+ self.contained_types.get(name)
128
+ }
129
+ }
130
+
131
+ impl TryFrom<&BaseInputTypeReference> for TypeDefinitionReference {
132
+ type Error = ();
133
+
134
+ fn try_from(value: &BaseInputTypeReference) -> Result<Self, Self::Error> {
135
+ match value {
136
+ BaseInputTypeReference::BuiltinScalarType(_) => Err(()),
137
+ BaseInputTypeReference::CustomScalarType(cstd) => Ok(Self::CustomScalarType(cstd.clone(), Default::default())),
138
+ BaseInputTypeReference::EnumType(etd) => Ok(Self::EnumType(etd.clone(), Default::default())),
139
+ BaseInputTypeReference::InputObjectType(iotd) => Ok(Self::InputObjectType(iotd.clone(), Default::default())),
140
+ }
141
+ }
142
+ }
143
+
144
+ impl TryInto<BaseInputTypeReference> for &TypeDefinitionReference {
145
+ type Error = ();
146
+
147
+ fn try_into(self) -> Result<BaseInputTypeReference, Self::Error> {
148
+ match self {
149
+ TypeDefinitionReference::BuiltinScalarType(bstd) => Ok(BaseInputTypeReference::BuiltinScalarType(*bstd)),
150
+ TypeDefinitionReference::CustomScalarType(cstd, _) => Ok(BaseInputTypeReference::CustomScalarType(cstd.clone())),
151
+ TypeDefinitionReference::EnumType(etd, _) => Ok(BaseInputTypeReference::EnumType(etd.clone())),
152
+ TypeDefinitionReference::InputObjectType(iotd, _) => Ok(BaseInputTypeReference::InputObjectType(iotd.clone())),
153
+ TypeDefinitionReference::InterfaceType(_, _) | TypeDefinitionReference::ObjectType(_, _) | TypeDefinitionReference::UnionType(_, _) => Err(()),
154
+ }
155
+ }
156
+ }
157
+
158
+ impl TryFrom<&BaseOutputTypeReference> for TypeDefinitionReference {
159
+ type Error = ();
160
+
161
+ fn try_from(value: &BaseOutputTypeReference) -> Result<Self, Self::Error> {
162
+ match value {
163
+ BaseOutputTypeReference::BuiltinScalarType(_) => Err(()),
164
+ BaseOutputTypeReference::CustomScalarType(cstd) => Ok(Self::CustomScalarType(cstd.clone(), Default::default())),
165
+ BaseOutputTypeReference::EnumType(etd) => Ok(Self::EnumType(etd.clone(), Default::default())),
166
+ BaseOutputTypeReference::ObjectType(otd) => Ok(Self::ObjectType(otd.clone(), Default::default())),
167
+ BaseOutputTypeReference::InterfaceType(itd) => Ok(Self::InterfaceType(itd.clone(), Default::default())),
168
+ BaseOutputTypeReference::UnionType(utd) => Ok(Self::UnionType(utd.clone(), Default::default())),
169
+ }
170
+ }
171
+ }
172
+
173
+ struct SchemaTypeVisitor {
174
+ types: HashMap<String, TypeDefinitionReference>,
175
+ }
176
+
177
+ impl Into<HashMap<String, TypeDefinitionReference>> for SchemaTypeVisitor {
178
+ fn into(self) -> HashMap<String, TypeDefinitionReference> {
179
+ self.types
180
+ }
181
+ }
182
+
183
+ impl SchemaTypeVisitor {
184
+ pub fn compute_contained_types(query: &WrappedDefinition<ObjectTypeDefinition>, mutation: Option<&WrappedDefinition<ObjectTypeDefinition>>) -> HashMap<String, TypeDefinitionReference> {
185
+ let mut type_visitor = Self::new();
186
+ type_visitor.visit_type(TypeDefinitionReference::ObjectType(query.clone(), Default::default()));
187
+ if let Some(mutation) = mutation {
188
+ type_visitor.visit_type(TypeDefinitionReference::ObjectType(mutation.clone(), Default::default()));
189
+ }
190
+ type_visitor.visit_builtin_scalar_definitions();
191
+ type_visitor.into()
192
+ }
193
+
194
+ fn new() -> Self {
195
+ Self { types: HashMap::new() }
196
+ }
197
+
198
+ fn visit_object_type_definition(&mut self, otd: &ObjectTypeDefinition) {
199
+ self.visit_field_definitions(otd.fields_definition())
200
+ }
201
+
202
+ fn visit_union_type_definition(&mut self, utd: &UnionTypeDefinition) {
203
+ for union_member in utd.member_types().iter() {
204
+ let t = TypeDefinitionReference::ObjectType(union_member.r#type(), Default::default());
205
+ self.visit_type(t);
206
+ }
207
+ }
208
+
209
+ fn visit_interface_type_definition(&mut self, itd: &InterfaceTypeDefinition) {
210
+ self.visit_field_definitions(itd.fields_definition())
211
+ }
212
+
213
+ fn visit_input_object_type_definition(&mut self, iotd: &InputObjectTypeDefinition) {
214
+ self.visit_input_value_definitions(iotd.input_fields_definition())
215
+ }
216
+
217
+ fn visit_type(&mut self, t: TypeDefinitionReference) {
218
+ let name = t.name().to_owned();
219
+ match self.types.entry(name) {
220
+ Entry::Occupied(_) => {},
221
+ Entry::Vacant(entry) => {
222
+ entry.insert(t.clone());
223
+ match t {
224
+ TypeDefinitionReference::BuiltinScalarType(_) | TypeDefinitionReference::CustomScalarType(_, _) | TypeDefinitionReference::EnumType(_, _) => {},
225
+ TypeDefinitionReference::ObjectType(otd, _) => self.visit_object_type_definition(otd.as_ref()),
226
+ TypeDefinitionReference::UnionType(utd, _) => self.visit_union_type_definition(utd.as_ref()),
227
+ TypeDefinitionReference::InterfaceType(itd, _) => self.visit_interface_type_definition(itd.as_ref()),
228
+ TypeDefinitionReference::InputObjectType(iotd, _) => self.visit_input_object_type_definition(iotd.as_ref()),
229
+ }
230
+ }
231
+ }
232
+ }
233
+
234
+ fn visit_field_definitions(&mut self, fields_definition: &FieldsDefinition) {
235
+ for field_definition in fields_definition.iter() {
236
+ self.visit_input_value_definitions(field_definition.argument_definitions());
237
+ let base_type = field_definition.r#type().as_ref().base();
238
+ let t: Result<TypeDefinitionReference, ()> = base_type.try_into();
239
+ if let Ok(t) = t {
240
+ self.visit_type(t);
241
+ }
242
+ }
243
+ }
244
+
245
+ fn visit_input_value_definitions(&mut self, input_fields_definition: &InputFieldsDefinition) {
246
+ for input_value_definition in input_fields_definition.iter() {
247
+ let base_type = input_value_definition.r#type().as_ref().base();
248
+ let t: Result<TypeDefinitionReference, ()> = base_type.try_into();
249
+ if let Ok(t) = t {
250
+ self.visit_type(t);
251
+ }
252
+ }
253
+ }
254
+
255
+ fn visit_builtin_scalar_definitions(&mut self) {
256
+ BuiltinScalarDefinition::iter().for_each(|bisd| {
257
+ self.visit_type(TypeDefinitionReference::BuiltinScalarType(bisd));
258
+ })
259
+ }
260
+ }
261
+
262
+ pub fn init() -> Result<(), Error> {
263
+ let class = root().define_class("SchemaDefinition", Default::default())?;
264
+
265
+ class.define_singleton_method("new", function!(SchemaDefinition::new, 1))?;
266
+ class.define_method("execute", method!(SchemaDefinition::execute, 4))?;
267
+ class.define_method("validate_query", method!(SchemaDefinition::validate_query, 1))?;
268
+
269
+ Ok(())
270
+ }
@@ -0,0 +1,41 @@
1
+ use super::{root, object_type_definition::ObjectTypeDefinition};
2
+ use magnus::{RClass, function, Error, Module, Object, TypedData, DataTypeFunctions};
3
+ use crate::helpers::WrappedDefinition;
4
+
5
+ #[derive(Clone, Debug, TypedData)]
6
+ #[magnus(class = "Bluejay::UnionMemberType", mark)]
7
+ pub struct UnionMemberType {
8
+ r#type: WrappedDefinition<ObjectTypeDefinition>,
9
+ }
10
+
11
+ impl UnionMemberType {
12
+ pub fn new(r#type: RClass) -> Result<Self, Error> {
13
+ WrappedDefinition::new(r#type).map(|r#type| Self { r#type })
14
+ }
15
+
16
+ pub fn r#type(&self) -> WrappedDefinition<ObjectTypeDefinition> {
17
+ self.r#type.clone()
18
+ }
19
+ }
20
+
21
+ impl DataTypeFunctions for UnionMemberType {
22
+ fn mark(&self) {
23
+ self.r#type.mark();
24
+ }
25
+ }
26
+
27
+ impl bluejay_core::definition::UnionMemberType for UnionMemberType {
28
+ type ObjectTypeDefinition = ObjectTypeDefinition;
29
+
30
+ fn member_type(&self) -> &Self::ObjectTypeDefinition {
31
+ self.r#type.as_ref()
32
+ }
33
+ }
34
+
35
+ pub fn init() -> Result<(), Error> {
36
+ let class = root().define_class("UnionMemberType", Default::default())?;
37
+
38
+ class.define_singleton_method("new", function!(UnionMemberType::new, 1))?;
39
+
40
+ Ok(())
41
+ }
@@ -0,0 +1,8 @@
1
+ use super::{union_member_type::UnionMemberType};
2
+ use crate::helpers::{WrappedStruct, TypedFrozenRArray};
3
+
4
+ pub type UnionMemberTypes = TypedFrozenRArray<WrappedStruct<UnionMemberType>>;
5
+
6
+ impl bluejay_core::definition::UnionMemberTypes for UnionMemberTypes {
7
+ type UnionMemberType = UnionMemberType;
8
+ }
@@ -0,0 +1,89 @@
1
+ use magnus::{function, Error, Module, Object, scan_args::get_kwargs, RHash, memoize, TypedData, RArray, DataTypeFunctions, RClass, gc};
2
+ use super::{root, object_type_definition::ObjectTypeDefinition, union_member_types::UnionMemberTypes};
3
+ use crate::helpers::{HasDefinitionWrapper};
4
+ use bluejay_core::AsIter;
5
+
6
+ #[derive(Debug, TypedData)]
7
+ #[magnus(class = "Bluejay::UnionTypeDefinition", mark)]
8
+ pub struct UnionTypeDefinition {
9
+ name: String,
10
+ description: Option<String>,
11
+ member_types: UnionMemberTypes,
12
+ }
13
+
14
+ impl UnionTypeDefinition {
15
+ fn new(kw: RHash) -> Result<Self, Error> {
16
+ let args = get_kwargs(kw, &["name", "member_types", "description"], &[])?;
17
+ let (name, member_types, description): (String, RArray, Option<String>) = args.required;
18
+ let _: () = args.optional;
19
+ let _: () = args.splat;
20
+ let member_types = UnionMemberTypes::new(member_types)?;
21
+ Ok(Self { name, description, member_types })
22
+ }
23
+
24
+ pub fn name(&self) -> &str {
25
+ self.name.as_str()
26
+ }
27
+
28
+ pub fn description(&self) -> Option<&str> {
29
+ self.description.as_ref().map(String::as_str)
30
+ }
31
+
32
+ pub fn member_types(&self) -> &UnionMemberTypes {
33
+ &self.member_types
34
+ }
35
+
36
+ pub fn contains_type(&self, t: &ObjectTypeDefinition) -> bool {
37
+ self.member_types
38
+ .iter()
39
+ .any(|mt| mt.r#type().as_ref().name() == t.name())
40
+ }
41
+
42
+ pub fn sorbet_type(&self) -> String {
43
+ format!(
44
+ "T.any({})",
45
+ itertools::join(
46
+ self.member_types
47
+ .iter()
48
+ .map(|member_type| member_type.r#type().fully_qualified_name()),
49
+ ", ",
50
+ ),
51
+ )
52
+ }
53
+ }
54
+
55
+ impl DataTypeFunctions for UnionTypeDefinition {
56
+ fn mark(&self) {
57
+ gc::mark(self.member_types);
58
+ }
59
+ }
60
+
61
+ impl HasDefinitionWrapper for UnionTypeDefinition {
62
+ fn wrapping_class() -> RClass {
63
+ *memoize!(RClass: root().define_class("UnionType", Default::default()).unwrap())
64
+ }
65
+ }
66
+
67
+ impl bluejay_core::definition::UnionTypeDefinition for UnionTypeDefinition {
68
+ type UnionMemberTypes = UnionMemberTypes;
69
+
70
+ fn description(&self) -> Option<&str> {
71
+ self.description.as_ref().map(String::as_str)
72
+ }
73
+
74
+ fn name(&self) -> &str {
75
+ self.name.as_str()
76
+ }
77
+
78
+ fn union_member_types(&self) -> &Self::UnionMemberTypes {
79
+ &self.member_types
80
+ }
81
+ }
82
+
83
+ pub fn init() -> Result<(), Error> {
84
+ let class = root().define_class("UnionTypeDefinition", Default::default())?;
85
+
86
+ class.define_singleton_method("new", function!(UnionTypeDefinition::new, 1))?;
87
+
88
+ Ok(())
89
+ }
@@ -0,0 +1,63 @@
1
+ use super::root;
2
+ use crate::helpers::WrappedStruct;
3
+ use bluejay_core::validation::executable::{Error as CoreError};
4
+ use bluejay_parser::ast::executable::ExecutableDocument;
5
+ use crate::ruby_api::SchemaDefinition;
6
+ use magnus::{function, Error, Module, Object, Value, method, rb_sys::AsRawValue};
7
+
8
+ #[derive(Clone, Debug, PartialEq)]
9
+ #[magnus::wrap(class = "Bluejay::ValidationError", mark)]
10
+ pub struct ValidationError {
11
+ message: String,
12
+ }
13
+
14
+ impl ValidationError {
15
+ pub fn new(message: String) -> Self {
16
+ Self { message }
17
+ }
18
+
19
+ pub fn message(&self) -> &str {
20
+ self.message.as_str()
21
+ }
22
+
23
+ pub fn eql(&self, other: Value) -> bool {
24
+ if let Ok(other) = other.try_convert::<&Self>() {
25
+ self == other
26
+ } else {
27
+ false
28
+ }
29
+ }
30
+
31
+ fn inspect(rb_self: WrappedStruct<Self>) -> Result<String, Error> {
32
+ let rs_self = rb_self.get();
33
+
34
+ Ok(format!(
35
+ "#<Bluejay::ValidationError:0x{:016x} @message={:?}>",
36
+ rb_self.to_value().as_raw(),
37
+ rs_self.message,
38
+ ))
39
+ }
40
+ }
41
+
42
+ impl<'a> From<CoreError<'a, ExecutableDocument<'a>, SchemaDefinition>> for ValidationError {
43
+ fn from(value: CoreError<'a, ExecutableDocument<'a>, SchemaDefinition>) -> Self {
44
+ match value {
45
+ CoreError::NotLoneAnonymousOperation { anonymous_operations: _ } => Self::new("Anonymous operations are not allowed when there is more than one operation".to_string()),
46
+ CoreError::NonUniqueOperationNames { name, operations: _ } => Self::new(format!("More than one operation named `{}`", name)),
47
+ CoreError::SubscriptionRootNotSingleField { operation: _ } => Self::new("Subscription operations can only select one field at the root".to_string()),
48
+ CoreError::FieldDoesNotExistOnType { field, r#type } => Self::new(format!("Field `{}` does not exist on `{}`", field.name(), r#type.name())),
49
+ CoreError::FieldSelectionsDoNotMerge { selection_set: _ } => Self::new("Field selections do not merge".to_string()),
50
+ }
51
+ }
52
+ }
53
+
54
+ pub fn init() -> Result<(), Error> {
55
+ let class = root().define_class("ValidationError", Default::default())?;
56
+
57
+ class.define_singleton_method("new", function!(ValidationError::new, 1))?;
58
+ class.define_method("message", method!(ValidationError::message, 0))?;
59
+ class.define_method("==", method!(ValidationError::eql, 1))?;
60
+ class.define_method("inspect", method!(ValidationError::inspect, 0))?;
61
+
62
+ Ok(())
63
+ }
@@ -0,0 +1,75 @@
1
+ use magnus::{define_module, memoize, Error, RModule, function};
2
+
3
+ mod arguments_definition;
4
+ mod coerce_input;
5
+ mod coercion_error;
6
+ mod custom_scalar_type_definition;
7
+ mod enum_type_definition;
8
+ mod enum_value_definition;
9
+ mod enum_value_definitions;
10
+ mod execution_error;
11
+ mod execution_result;
12
+ mod field_definition;
13
+ mod fields_definition;
14
+ mod input_fields_definition;
15
+ mod input_type_reference;
16
+ mod input_object_type_definition;
17
+ mod input_value_definition;
18
+ mod interface_implementation;
19
+ mod interface_implementations;
20
+ mod interface_type_definition;
21
+ mod json_value;
22
+ mod object_type_definition;
23
+ mod output_type_reference;
24
+ mod r_result;
25
+ mod scalar;
26
+ mod schema_definition;
27
+ mod union_member_type;
28
+ mod union_member_types;
29
+ mod union_type_definition;
30
+ mod validation_error;
31
+
32
+ pub use schema_definition::{SchemaDefinition, TypeDefinitionReference};
33
+ pub use execution_error::ExecutionError;
34
+ pub use input_type_reference::{BaseInputTypeReference, InputTypeReference};
35
+ pub use coerce_input::CoerceInput;
36
+ pub use coercion_error::CoercionError;
37
+ pub use execution_result::ExecutionResult;
38
+ pub use object_type_definition::ObjectTypeDefinition;
39
+ pub use output_type_reference::{BaseOutputTypeReference, OutputTypeReference};
40
+ pub use input_value_definition::InputValueDefinition;
41
+ pub use field_definition::FieldDefinition;
42
+ pub use interface_type_definition::InterfaceTypeDefinition;
43
+ pub use union_type_definition::UnionTypeDefinition;
44
+
45
+ pub fn root() -> RModule {
46
+ *memoize!(RModule: define_module("Bluejay").unwrap())
47
+ }
48
+
49
+ pub fn init() -> Result<(), Error> {
50
+ let r = root();
51
+
52
+ coercion_error::init()?;
53
+ custom_scalar_type_definition::init()?;
54
+ enum_type_definition::init()?;
55
+ enum_value_definition::init()?;
56
+ execution_error::init()?;
57
+ execution_result::init()?;
58
+ field_definition::init()?;
59
+ input_object_type_definition::init()?;
60
+ input_type_reference::init()?;
61
+ input_value_definition::init()?;
62
+ interface_implementation::init()?;
63
+ interface_type_definition::init()?;
64
+ object_type_definition::init()?;
65
+ output_type_reference::init()?;
66
+ r_result::init()?;
67
+ scalar::init()?;
68
+ schema_definition::init()?;
69
+ union_member_type::init()?;
70
+ union_type_definition::init()?;
71
+ validation_error::init()?;
72
+ r.define_module_function("parse", function!(|s: String| { let (doc, errs) = bluejay_parser::parse(s.as_str()); (doc.operation_definitions().len() + doc.fragment_definitions().len()) > 0 && errs.is_empty() }, 1))?;
73
+
74
+ Ok(())
75
+ }
@@ -0,0 +1,13 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Bluejay
5
+ BaseInputTypeReference = T.type_alias do
6
+ T.any(
7
+ Scalar,
8
+ T.class_of(InputType),
9
+ T.class_of(EnumType),
10
+ T.class_of(CustomScalarType),
11
+ )
12
+ end
13
+ end