Skip to content

Commit

Permalink
Allow all types in graphql, move to float to prevent overflow (#376)
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Henneberger <git@danielhenneberger.com>
  • Loading branch information
henneberger committed Oct 13, 2023
1 parent ec0a6d9 commit d79b4a4
Show file tree
Hide file tree
Showing 19 changed files with 168 additions and 225 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ public static GraphQLType getInOutTypeHelper(RelDataType type) {
case TINYINT:
case SMALLINT:
case INTEGER:
case BIGINT:
return Scalars.GraphQLInt;
case BIGINT: //treat bigint as float to prevent overflow
case DECIMAL:
case FLOAT:
case REAL:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.tools.RelBuilder;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Preconditions;
Expand Down Expand Up @@ -118,7 +117,7 @@ private InferredQuery resolveQueries(ObjectTypeDefinition query) {
private InferredField resolveQueryFromSchema(FieldDefinition fieldDefinition,
List<InferredField> fields, ObjectTypeDefinition parent) {
SQRLTable table = resolveRootSQRLTable(fieldDefinition, fieldDefinition.getType(), fieldDefinition.getName(), "Query");
return inferObjectField(fieldDefinition, table, fields, parent, null, false);
return inferObjectField(fieldDefinition, table, fields, parent, null);
}

private SQRLTable resolveRootSQRLTable(FieldDefinition fieldDefinition,
Expand Down Expand Up @@ -175,8 +174,7 @@ private Optional<ImplementingTypeDefinition> lookupType(Type type) {
}

private InferredField inferObjectField(FieldDefinition fieldDefinition, SQRLTable table,
List<InferredField> fields, ObjectTypeDefinition parent, SQRLTable parentTable,
boolean isSubscription) {
List<InferredField> fields, ObjectTypeDefinition parent, SQRLTable parentTable) {
checkValidArrayNonNullType(fieldDefinition.getType());
TypeDefinition typeDef = unwrapObjectType(fieldDefinition.getType());

Expand All @@ -196,7 +194,7 @@ private InferredField inferObjectField(FieldDefinition fieldDefinition, SQRLTabl
visitedObj.put(obj, table);
InferredObjectField inferredObjectField = new InferredObjectField(parentTable, parent, fieldDefinition,
(ObjectTypeDefinition) typeDef, table);
fields.addAll(walkChildren((ObjectTypeDefinition) typeDef, table, fields, isSubscription));
fields.addAll(walkChildren((ObjectTypeDefinition) typeDef, table, fields));
return inferredObjectField;
} else {
throw new RuntimeException("Could not infer non-object type on graphql schema: " + fieldDefinition.getName());
Expand All @@ -212,7 +210,7 @@ private void checkState(boolean b, SourceLocation sourceLocation, String message
}

private List<InferredField> walkChildren(ObjectTypeDefinition typeDef, SQRLTable table,
List<InferredField> fields, boolean isSubscription) {
List<InferredField> fields) {
List<FieldDefinition> invalidFields = getInvalidFields(typeDef, table);
boolean structurallyEqual = structurallyEqual(typeDef, table);
//todo clean up, add lazy evaluation
Expand All @@ -225,74 +223,36 @@ private List<InferredField> walkChildren(ObjectTypeDefinition typeDef, SQRLTable

return typeDef.getFieldDefinitions().stream()
.filter(f -> !visited.contains(f))
.map(f -> walk(f, table.getField(Name.system(f.getName())).get(), fields, typeDef, isSubscription))
.map(f -> walk(f, table.getField(Name.system(f.getName())).get(), fields, typeDef))
.collect(Collectors.toList());
}

private InferredField walk(FieldDefinition fieldDefinition, Field field,
List<InferredField> fields, ObjectTypeDefinition parent, boolean isSubscription) {
List<InferredField> fields, ObjectTypeDefinition parent) {
visited.add(fieldDefinition);
if (field instanceof Relationship) {
return walkRel(fieldDefinition, (Relationship) field, fields, parent, isSubscription);
return walkRel(fieldDefinition, (Relationship) field, fields, parent);
} else {
return walkScalar(fieldDefinition, (Column) field, parent, isSubscription);
return walkScalar(fieldDefinition, (Column) field, parent);
}
}

private InferredField walkRel(FieldDefinition fieldDefinition, Relationship relationship,
List<InferredField> fields, ObjectTypeDefinition parent, boolean isSubscription) {
List<InferredField> fields, ObjectTypeDefinition parent) {
return new NestedField(relationship,
inferObjectField(fieldDefinition, relationship.getToTable(),
fields, parent, relationship.getFromTable(), isSubscription));
fields, parent, relationship.getFromTable()));
}

private InferredField walkScalar(FieldDefinition fieldDefinition, Column column,
ObjectTypeDefinition parent, boolean isSubscription) {
ObjectTypeDefinition parent) {
checkValidArrayNonNullType(fieldDefinition.getType());

TypeDefinition type = unwrapObjectType(fieldDefinition.getType());
//Todo: expand server to allow type coercion
//Todo: enums
Preconditions.checkState(type instanceof ScalarTypeDefinition,
"Unknown type found: %s", type);
ScalarTypeDefinition scalarTypeDefinition = (ScalarTypeDefinition) type;
SqlParserPos pos = toParserPos(fieldDefinition.getType().getSourceLocation());

SqlTypeName sqlTypeName = column.getType().getComponentType() != null ?
column.getType().getComponentType().getSqlTypeName() : column.getType().getSqlTypeName();
switch (scalarTypeDefinition.getName()) {
case "Int":
if (!SqlTypeName.INT_TYPES.contains(sqlTypeName)) {
throw new SqrlAstException(ErrorLabel.GENERIC, pos, parent.getName() + ":"+fieldDefinition.getName()+" expected SQRL Int type, found: %s",
sqlTypeName.getName());
}
break;
case "Float":
if (!SqlTypeName.NUMERIC_TYPES.contains(sqlTypeName)) {
throw new SqrlAstException(ErrorLabel.GENERIC, pos, "Expected SQRL Numeric type, found: %s %s",
sqlTypeName.getName(), column.getName().getDisplay());
}
break;
case "String":
if (!SqlTypeName.STRING_TYPES.contains(sqlTypeName) &&
!SqlTypeName.DATETIME_TYPES.contains(sqlTypeName)) {
throw new SqrlAstException(ErrorLabel.GENERIC, pos, "Expected SQRL String or Date type, found: %s %s",
sqlTypeName.getName(), column.getName().getDisplay());
}
break;
case "Boolean":
if (!SqlTypeName.BOOLEAN_TYPES.contains(sqlTypeName)) {
throw new SqrlAstException(ErrorLabel.GENERIC, pos, "Expected SQRL boolean type, found: %s %s",
sqlTypeName.getName(), column.getName().getDisplay());
}
break;
case "ID":
default:
throw new SqrlAstException(ErrorLabel.GENERIC,
toParserPos(type.getSourceLocation()),
"Unrecognized type: %s", sqlTypeName.getName());
}


return new InferredScalarField(fieldDefinition, column, parent);
}
Expand Down Expand Up @@ -347,10 +307,6 @@ private TypeDefinition unwrapObjectType(Type type) {
return typeDef.get();
}

private boolean isListType(Type type) {
return unboxNonNull(type) instanceof ListType;
}

private Type unboxNonNull(Type type) {
if (type instanceof NonNullType) {
return unboxNonNull(((NonNullType) type).getType());
Expand Down Expand Up @@ -544,7 +500,7 @@ private InferredSubscriptions resolveSubscriptions(ObjectTypeDefinition s) {
Field field = table.getField(Name.system(definition.getName()))
.orElseThrow(() -> new RuntimeException("Unrecognized field " + definition.getName() +
" in " + objectTypeDefinition.getName()));
InferredField inferredField = walk(definition, field, fields, objectTypeDefinition, true);
InferredField inferredField = walk(definition, field, fields, objectTypeDefinition);
fields.add(inferredField);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,6 @@ public void renameNestedTableTest() {
}
}

@Test
public void typeNotCoercableTest() {
inferSchemaModelQueries(planner, "type Orders {\n\tid: Boolean\n}\n"
+ "type Query {\n\torders: Orders\n}");
validateErrorsAndAddContent();
}

@Test
public void structuralObjectTest() {
inferSchemaModelQueries(planner, ""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
type Query {
pRoDuCt(productid: Int, name: String, description: String, category: String): [pRoDuCt!]
pRoDuCt(productid: Float, name: String, description: String, category: String): [pRoDuCt!]
}

type pRoDuCt {
productid: Int!
productid: Float!
name: String!
description: String!
category: String!
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
type Product {
productid: Int!
productid: Float!
name: String!
description: String!
category: String!
}

type Query {
Product(productid: Int, name: String, description: String, category: String): [Product!]
Product(productid: Float, name: String, description: String, category: String): [Product!]
}

Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
type Orders {
id: Int!
customerid: Int!
id: Float!
customerid: Float!
time: String!
entries(productid: Int, quantity: Int, unit_price: Float, discount: Float): [entries!]
entries(productid: Float, quantity: Float, unit_price: Float, discount: Float): [entries!]
}

type Query {
Orders(id: Int, customerid: Int, time: String): [Orders!]
Orders(id: Float, customerid: Float, time: String): [Orders!]
}

type entries {
productid: Int!
quantity: Int!
productid: Float!
quantity: Float!
unit_price: Float!
discount: Float
parent: Orders!
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
type Query {
product(productid: Int, name: String, description: String, category: String): [product!]
product(productid: Float, name: String, description: String, category: String): [product!]
}

type product {
productid: Int!
productid: Float!
name: String!
description: String!
category: String!
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
type Orders {
customerid: Int!
entries(discount: Float, productid: Int, quantity: Int, unit_price: Float): [entries!]
id: Int!
customerid: Float!
entries(discount: Float, productid: Float, quantity: Float, unit_price: Float): [entries!]
id: Float!
time: String!
}

type Product {
category: String!
description: String!
name: String!
productid: Int!
productid: Float!
}

type Query {
Orders(customerid: Int, id: Int, time: String): [Orders!]
Product(category: String, description: String, name: String, productid: Int): [Product!]
Orders(customerid: Float, id: Float, time: String): [Orders!]
Product(category: String, description: String, name: String, productid: Float): [Product!]
}

type entries {
discount: Float
parent: Orders!
productid: Int!
quantity: Int!
productid: Float!
quantity: Float!
unit_price: Float!
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,61 +1,61 @@
type Category {
name: String!
products(productid: Int, name: String, description: String, category: String, updateTime: String): [Product!]
products(productid: Float, name: String, description: String, category: String, updateTime: String): [Product!]
}

type Customer {
customerid: Int!
customerid: Float!
email: String!
name: String!
lastUpdated: Int!
lastUpdated: Float!
updateTime: String!
orders(id: Int, customerid: Int, time: String): [Orders!]
order_again(productid: Int, quantity: Int, num_orders: Int, most_recent: String): [order_again!]
orders(id: Float, customerid: Float, time: String): [Orders!]
order_again(productid: Float, quantity: Float, num_orders: Float, most_recent: String): [order_again!]
favorite_categories(category_name: String, total: Float): [favorite_categories!]
order_stats(total_spend: Float, num_orders: Int): [order_stats!]
order_stats(total_spend: Float, num_orders: Float): [order_stats!]
}

type NewCustomerPromotion {
customerid: Int!
customerid: Float!
email: String!
name: String!
total_spend: Float!
num_orders: Int!
num_orders: Float!
}

type Orders {
id: Int!
customerid: Int!
id: Float!
customerid: Float!
time: String!
entries(productid: Int, quantity: Int, unit_price: Float, discount: Float, discount0: Float, total: Float): [entries!]
total(price: Float, discount: Float, num: Int): [total!]
entries(productid: Float, quantity: Float, unit_price: Float, discount: Float, discount0: Float, total: Float): [entries!]
total(price: Float, discount: Float, num: Float): [total!]
}

type Product {
productid: Int!
productid: Float!
name: String!
description: String!
category: String!
updateTime: String!
}

type Query {
Product(productid: Int, name: String, description: String, category: String, updateTime: String): [Product!]
NewCustomerPromotion(customerid: Int, email: String, name: String, total_spend: Float, num_orders: Int): [NewCustomerPromotion!]
Orders(id: Int, customerid: Int, time: String): [Orders!]
Customer(customerid: Int, email: String, name: String, lastUpdated: Int, updateTime: String): [Customer!]
Product(productid: Float, name: String, description: String, category: String, updateTime: String): [Product!]
NewCustomerPromotion(customerid: Float, email: String, name: String, total_spend: Float, num_orders: Float): [NewCustomerPromotion!]
Orders(id: Float, customerid: Float, time: String): [Orders!]
Customer(customerid: Float, email: String, name: String, lastUpdated: Float, updateTime: String): [Customer!]
Category(name: String): [Category!]
}

type entries {
productid: Int!
quantity: Int!
productid: Float!
quantity: Float!
unit_price: Float!
discount: Float
discount0: Float!
total: Float!
parent: Orders!
product(productid: Int, name: String, description: String, category: String, updateTime: String): [Product!]
product(productid: Float, name: String, description: String, category: String, updateTime: String): [Product!]
}

type favorite_categories {
Expand All @@ -66,23 +66,23 @@ type favorite_categories {
}

type order_again {
productid: Int!
quantity: Int!
num_orders: Int!
productid: Float!
quantity: Float!
num_orders: Float!
most_recent: String!
parent: Customer!
}

type order_stats {
total_spend: Float!
num_orders: Int!
num_orders: Float!
parent: Customer!
}

type total {
price: Float!
discount: Float!
num: Int!
num: Float!
parent: Orders!
}

Loading

0 comments on commit d79b4a4

Please sign in to comment.