-
-
Notifications
You must be signed in to change notification settings - Fork 112
Adding support for filtering on array column types #520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 19 commits
a013f22
793254a
4f08594
fb61169
163707e
91b6b17
c425f8f
237a0a8
809047a
ee149f2
9851b3c
4cc6752
201154d
a080c4f
0a45e97
83c5ea9
384e394
a792bc1
c2ee53d
dd9784a
498d35c
26be47c
761f226
e658d83
3e3fb84
86b11fe
2e2a6be
c1a4ebe
02c273f
ca2890b
edcf8e0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1116,6 +1116,7 @@ pub struct OrderByEntityType { | |
pub enum FilterableType { | ||
Scalar(Scalar), | ||
Enum(EnumType), | ||
List(ListType), | ||
} | ||
|
||
#[derive(Clone, Debug, Eq, PartialEq, Hash)] | ||
|
@@ -1129,6 +1130,10 @@ impl FilterTypeType { | |
match &self.entity { | ||
FilterableType::Scalar(s) => s.name().expect("scalar name should exist"), | ||
FilterableType::Enum(e) => e.name().expect("enum type name should exist"), | ||
FilterableType::List(l) => match l.of_type().unwrap().name() { | ||
imor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
None => panic!("inner list type name should exist"), | ||
Some(name) => format!("{}List", name) | ||
}, | ||
} | ||
} | ||
} | ||
|
@@ -3328,6 +3333,9 @@ pub enum FilterOp { | |
ILike, | ||
RegEx, | ||
IRegEx, | ||
Contains, | ||
ContainedBy, | ||
Overlap, | ||
} | ||
|
||
impl ToString for FilterOp { | ||
|
@@ -3346,6 +3354,9 @@ impl ToString for FilterOp { | |
Self::ILike => "ilike", | ||
Self::RegEx => "regex", | ||
Self::IRegEx => "iregex", | ||
Self::Contains => "cs", | ||
Self::ContainedBy => "cd", | ||
Self::Overlap => "ov", | ||
} | ||
.to_string() | ||
} | ||
|
@@ -3369,6 +3380,9 @@ impl FromStr for FilterOp { | |
"ilike" => Ok(Self::ILike), | ||
"regex" => Ok(Self::RegEx), | ||
"iregex" => Ok(Self::IRegEx), | ||
"cs" => Ok(Self::Contains), | ||
"cd" => Ok(Self::ContainedBy), | ||
"ov" => Ok(Self::Overlap), | ||
_ => Err("Invalid filter operation".to_string()), | ||
} | ||
} | ||
|
@@ -3541,6 +3555,8 @@ impl ___Type for FilterTypeType { | |
default_value: None, | ||
sql_type: None, | ||
}, | ||
// shouldn't happen since we've covered all cases in supported_ops | ||
_ => panic!("encountered unknown FilterOp") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Scalar's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should restructure the |
||
}) | ||
.collect() | ||
} | ||
|
@@ -3583,6 +3599,36 @@ impl ___Type for FilterTypeType { | |
}, | ||
] | ||
} | ||
FilterableType::List(list_type) => { | ||
let supported_ops = vec![ | ||
FilterOp::Contains, | ||
FilterOp::ContainedBy, | ||
FilterOp::Equal, | ||
FilterOp::GreaterThan, | ||
FilterOp::GreaterThanEqualTo, | ||
FilterOp::LessThan, | ||
FilterOp::LessThanEqualTo, | ||
FilterOp::NotEqual, | ||
FilterOp::Overlap, | ||
]; | ||
|
||
supported_ops | ||
.iter() | ||
.map(|op| match op { | ||
_ => __InputValue { | ||
name_: op.to_string(), | ||
type_: __Type::List(ListType { | ||
type_: Box::new(__Type::NonNull(NonNullType { | ||
type_: Box::new(*list_type.type_.clone()), | ||
})), | ||
}), | ||
description: None, | ||
default_value: None, | ||
sql_type: None, | ||
}, | ||
}) | ||
.collect() | ||
} | ||
}; | ||
|
||
infields.sort_by_key(|a| a.name()); | ||
|
@@ -3620,14 +3666,11 @@ impl ___Type for FilterEntityType { | |
.columns | ||
.iter() | ||
.filter(|x| x.permissions.is_selectable) | ||
// No filtering on arrays | ||
.filter(|x| !x.type_name.ends_with("[]")) | ||
// No filtering on composites | ||
.filter(|x| !self.schema.context.is_composite(x.type_oid)) | ||
// No filtering on json/b. they do not support = or <> | ||
.filter(|x| !["json", "jsonb"].contains(&x.type_name.as_ref())) | ||
.filter_map(|col| { | ||
// Should be a scalar | ||
if let Some(utype) = sql_column_to_graphql_type(col, &self.schema) { | ||
let column_graphql_name = self.schema.graphql_column_field_name(col); | ||
|
||
|
@@ -3641,22 +3684,33 @@ impl ___Type for FilterEntityType { | |
not_column_exists = true; | ||
} | ||
|
||
match utype.unmodified_type() { | ||
__Type::Scalar(s) => Some(__InputValue { | ||
match utype.nullable_type() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that we support filtering by array columns, we want to respect the fact that the |
||
__Type::Scalar(s) => { | ||
Some(__InputValue { | ||
name_: column_graphql_name, | ||
type_: __Type::FilterType(FilterTypeType { | ||
entity: FilterableType::Scalar(s), | ||
schema: Arc::clone(&self.schema), | ||
}), | ||
description: None, | ||
default_value: None, | ||
sql_type: Some(NodeSQLType::Column(Arc::clone(col))), | ||
}) | ||
}, | ||
__Type::Enum(e) => Some(__InputValue { | ||
name_: column_graphql_name, | ||
type_: __Type::FilterType(FilterTypeType { | ||
entity: FilterableType::Scalar(s), | ||
entity: FilterableType::Enum(e), | ||
schema: Arc::clone(&self.schema), | ||
}), | ||
description: None, | ||
default_value: None, | ||
sql_type: Some(NodeSQLType::Column(Arc::clone(col))), | ||
}), | ||
// ERROR HERE | ||
__Type::Enum(s) => Some(__InputValue { | ||
__Type::List(l) => Some(__InputValue { | ||
name_: column_graphql_name, | ||
type_: __Type::FilterType(FilterTypeType { | ||
entity: FilterableType::Enum(s), | ||
entity: FilterableType::List(l), | ||
schema: Arc::clone(&self.schema), | ||
}), | ||
description: None, | ||
|
@@ -3829,13 +3883,12 @@ impl ___Type for OrderByEntityType { | |
.columns | ||
.iter() | ||
.filter(|x| x.permissions.is_selectable) | ||
// No filtering on arrays | ||
// No ordering by arrays | ||
.filter(|x| !x.type_name.ends_with("[]")) | ||
// No filtering on composites | ||
// No ordering by composites | ||
.filter(|x| !self.schema.context.is_composite(x.type_oid)) | ||
// No filtering on json/b. they do not support = or <> | ||
// No ordering by json/b. they do not support = or <> | ||
.filter(|x| !["json", "jsonb"].contains(&x.type_name.as_ref())) | ||
// TODO filter out arrays, json and composites | ||
.map(|col| __InputValue { | ||
name_: self.schema.graphql_column_field_name(col), | ||
type_: __Type::OrderBy(OrderByType {}), | ||
|
@@ -3968,6 +4021,72 @@ impl __Schema { | |
entity: FilterableType::Scalar(Scalar::Opaque), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::ID)) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::Int)) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::Float)) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::String(None))) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::Boolean)) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::Date)) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::Time)) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::Datetime)) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::BigInt)) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::UUID)) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::FilterType(FilterTypeType { | ||
entity: FilterableType::List(ListType { | ||
type_: Box::new(__Type::Scalar(Scalar::BigFloat)) | ||
}), | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
__Type::Query(QueryType { | ||
schema: Arc::clone(&schema_rc), | ||
}), | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This column was added to allow live validation beyond just the regression tests for filtering by array columns!