-
Notifications
You must be signed in to change notification settings - Fork 128
feat(client): add the DECIMAL (BigDecimal) property data type #771
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
base: master
Are you sure you want to change the base?
Changes from all commits
e828355
a57545f
56fcad0
268af65
4ca9ce2
991a97f
5255714
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 |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with this | ||
| * work for additional information regarding copyright ownership. The ASF | ||
| * licenses this file to You under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
| * License for the specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| package org.apache.hugegraph.serializer; | ||
|
|
||
| import java.io.IOException; | ||
| import java.math.BigDecimal; | ||
|
|
||
| import org.apache.hugegraph.structure.constant.DataType; | ||
|
|
||
| import com.fasterxml.jackson.core.JsonGenerator; | ||
| import com.fasterxml.jackson.databind.SerializerProvider; | ||
| import com.fasterxml.jackson.databind.ser.std.StdSerializer; | ||
|
|
||
| /** | ||
| * Write a BigDecimal as a plain JSON number ("1.10", never "1.1E+2"). | ||
| * Jackson's default is the scientific form of BigDecimal.toString(); the | ||
| * plain form carries every digit, so a server that reads fractions as | ||
| * BigDecimal (apache/hugegraph#3209) stores a DECIMAL value exactly, and a | ||
| * server that reads them as double behaves as it always did. The value stays | ||
| * a number, so numeric keys (DOUBLE, FLOAT, LONG, INT) accept it too. | ||
| */ | ||
| public class BigDecimalSerializer extends StdSerializer<BigDecimal> { | ||
|
|
||
| private static final long serialVersionUID = 1L; | ||
|
|
||
| public BigDecimalSerializer() { | ||
| super(BigDecimal.class); | ||
| } | ||
|
|
||
| @Override | ||
| public void serialize(BigDecimal value, JsonGenerator generator, | ||
| SerializerProvider provider) throws IOException { | ||
| generator.writeNumber(exactString(value)); | ||
| } | ||
|
|
||
| /** | ||
| * The plain form while the value is within the DECIMAL bounds the server | ||
| * accepts, else the scientific form: still exact and still a JSON number, | ||
| * but a value such as 1E+999999999 is not expanded into a billion | ||
| * characters on the client before the server rejects it. | ||
| */ | ||
| public static String exactString(BigDecimal value) { | ||
| int scale = value.scale(); | ||
| if (value.precision() <= DataType.DECIMAL_MAX_PRECISION && | ||
| scale >= -DataType.DECIMAL_MAX_SCALE && scale <= DataType.DECIMAL_MAX_SCALE) { | ||
| return value.toPlainString(); | ||
|
Member
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. |
||
| } | ||
| return value.toString(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
| import java.io.OutputStream; | ||
| import java.nio.ByteBuffer; | ||
| import java.util.Arrays; | ||
| import java.math.BigDecimal; | ||
| import java.util.Date; | ||
| import java.util.UUID; | ||
|
|
||
|
|
@@ -750,6 +751,13 @@ public void writeProperty(DataType dataType, Object value) { | |
| this.writeLong(uuid.getMostSignificantBits()); | ||
| this.writeLong(uuid.getLeastSignificantBits()); | ||
| break; | ||
| case DECIMAL: | ||
| // Same layout as the server: unscaled two's-complement | ||
| // bytes followed by the scale, exact for any precision | ||
| BigDecimal decimal = dataType.valueToDecimal(value); | ||
|
Contributor
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.
Please apply the same bounds in both client
Author
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. Done: both |
||
| this.writeBytes(decimal.unscaledValue().toByteArray()); | ||
| this.writeVInt(decimal.scale()); | ||
| break; | ||
| default: | ||
| //this.writeBytes(KryoUtil.toKryoWithType(value)); | ||
| break; | ||
|
|
||
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.
JsonUtilCommonmapper, so everyBigDecimalin any request body now goes out as"1.5", not only values for DECIMAL keys.On the server, a DOUBLE/FLOAT/LONG/INT key goes through
DataType.valueToNumber, which returns null unless the value is aNumberor one of the Infinity/NaN strings. So a client that today writesvertex.property("price", new BigDecimal("1.5"))to aasDouble()key (common when values come from JDBCNUMERICcolumns) gets a 400Invalid property valueafter this change, and aBigDecimalGremlin binding turns into a string inside the script. The loader and spark connector are safe only because they convert toDoublefirst.Please either make the server accept numeric strings for numeric keys as part of #3209, or limit the string form to values headed for DECIMAL keys, and add an API test that writes a
BigDecimalto a DOUBLE key. If the behaviour change is intended, it needs a line in the PR description and release notes under "public API".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.
Good catch, thanks: a client feeding JDBC
NUMERICinto anasDouble()key would have got a 400. I changed the approach in a57545f: aBigDecimalis no longer a string but a plain JSON number intoPlainString()form (1000, not1E+3; every digit). For numeric keys nothing changes against any server, sincevalueToNumberaccepts anyNumber; for DECIMAL the exactness comes from the server side: in apache/hugegraph#3209 (0146849b) Jersey now reads JSON fractions asBigDecimal(ObjectMapperResolver,USE_BIG_DECIMAL_FOR_FLOATS), so a 39-digit literal reaches a DECIMAL key intact while a DOUBLE key narrows it to a double as before.VertexApiTest.testCreateWithBigDecimalOnDoubleKeywritesnew BigDecimal("1.5")to a DOUBLE key and reads 1.5 back; it runs in the regularApiTestSuite, i.e. against the 1.7.0 server in CI as well. A Gremlin binding holding aBigDecimalstays a number. There is no public-behaviour change left to note in the release notes; the PR description's "public API" section is updated accordingly.