Skip to content

cast int64 and numeric to string by default #416

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

Merged
merged 18 commits into from
Apr 16, 2024
Merged

cast int64 and numeric to string by default #416

merged 18 commits into from
Apr 16, 2024

Conversation

soupi
Copy link
Contributor

@soupi soupi commented Apr 9, 2024

What

We want to be able to stringify fields of types int8 and numeric in the query response so that we have better interoperability with javascript clients.

This PR changes the default type representation of int8 and numeric types (maintaining the existing type representation if one exists) and stringify numbers.

This option can be change via the configuration by editing the mapping in the metadata.typeRepresentations:

  { ...
    "metadata": {
      ...
      "typeRepresentations": {
        "Phone": "string",
        "CardSuit": {
          "enum": ["hearts", "clubs", "diamonds", "spades"]
        },
        ...
-       "int8": "int64",
+       "int8": "int64AsString",
-       "numeric": "bigDecimal",
+       "numeric": "bigDecimalAsString",
        ...
      }
      ...
    }
  }

How

  1. We introduce new type representations: Int64AsString, BigDecimalAsString.
  2. Make sure we use the existing type representation configuration and override the default if it exists.
  3. In field selection after getting an expression, we cast it if the type representation requires it. (For arrays, we cast to cast_type[])
  4. For composite types we unpack them if the don't specify fields, and cast required fields recursively.

Comment on lines 331 to 340
fn unpack_and_wrap_fields(
env: &Env,
state: &mut State,
current_table: &TableNameAndReference,
join_relationship_fields: &mut Vec<relationships::JoinFieldInfo>,
column: &str,
alias: sql::ast::ColumnAlias,
type_info: &CollectionOrCompositeTypeInfo<'_>,
nested_field_joins: &mut Vec<JoinNestedFieldInfo>,
) -> Result<(sql::ast::ColumnAlias, sql::ast::Expression), Error> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that I would be partial to inlining this function in the one place where it is used, since its body has to take part in the somewhat complex join_relationship_fields/nested_field_joins handling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually pulled it out because that function has gotten quite big and found this to be more digestible, but we can talk about this if you really prefer it to be inlined.

"address": {
"address_line_1": "Somstreet 159",
"address_line_2": "Second door to the right"
},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, when a QueryRequest requested a nested field column without specifying fields, we would let postgres decide on the field ordering. Now we explicitly request fields in such cases, so they are ordered according to the BTreeMap ordering.

@@ -2926,7 +2926,7 @@ expression: result
"only_occurring_here1": {
"type": {
"type": "named",
"name": "bit"
"name": "int8"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed our sql definition so I can test stuff. Sorry.

@@ -3335,7 +3335,7 @@
"float8": "float64",
"int2": "int16",
"int4": "int32",
"int8": "json",
"int8": "int64",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decided to only set postgres to int64AsString so we can test both behaviours.

Comment on lines +3715 to +3716
"int8": "int64AsString",
"numeric": "bigDecimalAsString",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changing the postgres config (only) so we can test this change in both modes.

) AS "%3_rows"
) AS "%3_rows"
) AS "%2_universe";
LEFT OUTER JOIN LATERAL (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now unpack fields ourselves so we can cast them if needed yey...

Comment on lines +629 to +636
// Int64 returns a number.
metadata::TypeRepresentation::Int64 => models::TypeRepresentation::JSON,
// Int64AsString returns a string.
metadata::TypeRepresentation::Int64AsString => models::TypeRepresentation::Int64,
// BigDecimal returns a number.
metadata::TypeRepresentation::BigDecimal => models::TypeRepresentation::JSON,
// BigDecimalAsString returns a string.
metadata::TypeRepresentation::BigDecimalAsString => models::TypeRepresentation::BigDecimal,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the mapping between our internal type representations and ndc-spec type representations.

@soupi soupi marked this pull request as ready for review April 11, 2024 10:27
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix so it will work when the hash already exists as well.

@soupi soupi changed the title cast int64 to string cast int64 and numeric to string by default Apr 11, 2024
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test of array of composite types.

.type_representations
.0
.get(scalar_type)
.cloned()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stupid nitpick: we only use this as a reference so we could probably return one and not need to clone it.

This is stupid because cloning it will be cheap.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

smart. thanks!

sql::ast::Expression::ColumnReference(nested_column_reference),
))
}
// TODO: Arrays of composite types are not handled yet.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am confused; it looks like they are. Should this say "Arrays of arrays are not handled yet"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! stale comment.

Comment on lines 484 to 503
// In these situations the type representation should be the same as
// the expression, so we don't cast it.
TypeRepresentation::Boolean => None,
TypeRepresentation::String => None,
TypeRepresentation::Float32 => None,
TypeRepresentation::Float64 => None,
TypeRepresentation::Int16 => None,
TypeRepresentation::Int32 => None,
TypeRepresentation::Int64 => None,
TypeRepresentation::BigDecimal => None,
TypeRepresentation::Timestamp => None,
TypeRepresentation::Timestamptz => None,
TypeRepresentation::Time => None,
TypeRepresentation::Timetz => None,
TypeRepresentation::Date => None,
TypeRepresentation::UUID => None,
TypeRepresentation::Geography => None,
TypeRepresentation::Geometry => None,
TypeRepresentation::Json => None,
TypeRepresentation::Enum(_) => None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate you listing these out rather than using a wildcard.

You can use | to join them, though (there's a pedantic warning for this but we haven't enabled it).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool. Thanks!

@soupi soupi enabled auto-merge April 16, 2024 08:58
@soupi soupi added this pull request to the merge queue Apr 16, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Apr 16, 2024
@soupi soupi enabled auto-merge April 16, 2024 09:04
@soupi soupi added this pull request to the merge queue Apr 16, 2024
Merged via the queue into main with commit 819e19d Apr 16, 2024
35 checks passed
@soupi soupi deleted the gil/int64-string branch April 16, 2024 09:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants