bluejay 0.1.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Cargo.lock +423 -0
- data/Cargo.toml +2 -0
- data/LICENSE +21 -0
- data/README.md +33 -0
- data/ext/Cargo.toml +17 -0
- data/ext/extconf.rb +6 -0
- data/ext/src/execution/coerce_result.rs +54 -0
- data/ext/src/execution/engine.rs +466 -0
- data/ext/src/execution/execution_error.rs +28 -0
- data/ext/src/execution/field_error.rs +8 -0
- data/ext/src/execution/key_store.rs +23 -0
- data/ext/src/execution.rs +10 -0
- data/ext/src/helpers/public_name.rs +21 -0
- data/ext/src/helpers/typed_frozen_r_array.rs +56 -0
- data/ext/src/helpers/wrapped_definition.rs +79 -0
- data/ext/src/helpers/wrapped_struct.rs +97 -0
- data/ext/src/helpers.rs +8 -0
- data/ext/src/lib.rs +10 -0
- data/ext/src/ruby_api/arguments_definition.rs +8 -0
- data/ext/src/ruby_api/coerce_input.rs +6 -0
- data/ext/src/ruby_api/coercion_error.rs +61 -0
- data/ext/src/ruby_api/custom_scalar_type_definition.rs +62 -0
- data/ext/src/ruby_api/enum_type_definition.rs +107 -0
- data/ext/src/ruby_api/enum_value_definition.rs +58 -0
- data/ext/src/ruby_api/enum_value_definitions.rs +8 -0
- data/ext/src/ruby_api/execution_error.rs +48 -0
- data/ext/src/ruby_api/execution_result.rs +40 -0
- data/ext/src/ruby_api/field_definition.rs +112 -0
- data/ext/src/ruby_api/fields_definition.rs +8 -0
- data/ext/src/ruby_api/input_fields_definition.rs +8 -0
- data/ext/src/ruby_api/input_object_type_definition.rs +138 -0
- data/ext/src/ruby_api/input_type_reference.rs +358 -0
- data/ext/src/ruby_api/input_value_definition.rs +98 -0
- data/ext/src/ruby_api/interface_implementation.rs +42 -0
- data/ext/src/ruby_api/interface_implementations.rs +8 -0
- data/ext/src/ruby_api/interface_type_definition.rs +82 -0
- data/ext/src/ruby_api/json_value.rs +111 -0
- data/ext/src/ruby_api/object_type_definition.rs +100 -0
- data/ext/src/ruby_api/output_type_reference.rs +238 -0
- data/ext/src/ruby_api/r_result.rs +84 -0
- data/ext/src/ruby_api/scalar.rs +45 -0
- data/ext/src/ruby_api/schema_definition.rs +270 -0
- data/ext/src/ruby_api/union_member_type.rs +41 -0
- data/ext/src/ruby_api/union_member_types.rs +8 -0
- data/ext/src/ruby_api/union_type_definition.rs +89 -0
- data/ext/src/ruby_api/validation_error.rs +63 -0
- data/ext/src/ruby_api.rs +75 -0
- data/lib/bluejay/base_input_type_reference.rb +13 -0
- data/lib/bluejay/base_output_type_reference.rb +15 -0
- data/lib/bluejay/custom_scalar_type.rb +40 -0
- data/lib/bluejay/enum_type.rb +44 -0
- data/lib/bluejay/ext.bundle +0 -0
- data/lib/bluejay/finalize.rb +27 -0
- data/lib/bluejay/input_type.rb +64 -0
- data/lib/bluejay/input_type_reference_shorthands.rb +28 -0
- data/lib/bluejay/interface_type.rb +60 -0
- data/lib/bluejay/json_value.rb +16 -0
- data/lib/bluejay/name_from_class.rb +18 -0
- data/lib/bluejay/object_type.rb +68 -0
- data/lib/bluejay/output_type_reference_shorthands.rb +28 -0
- data/lib/bluejay/schema.rb +63 -0
- data/lib/bluejay/union_type.rb +43 -0
- data/lib/bluejay/version.rb +5 -0
- data/lib/bluejay.rb +28 -0
- data/lib/rbi_ext/model.rb +64 -0
- data/lib/tapioca/dsl/compilers/input_type.rb +34 -0
- data/lib/tapioca/dsl/compilers/interface_type.rb +29 -0
- data/lib/tapioca/dsl/compilers/object_type.rb +43 -0
- data/lib/tapioca/dsl/compilers/schema.rb +42 -0
- 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
|
+
}
|
data/ext/src/ruby_api.rs
ADDED
@@ -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
|
+
}
|