bluejay 0.1.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
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