From cf68d8dc6bf421ea9c82c27760af03dd64b24a29 Mon Sep 17 00:00:00 2001 From: Stephanie Wang Date: Tue, 9 Feb 2021 15:50:06 -0500 Subject: [PATCH] feat: add support for javascript UDFs determinism level (#1094) Fixes #1083 --- .../clirr-ignored-differences.xml | 11 ++----- .../com/google/cloud/bigquery/Routine.java | 6 ++++ .../google/cloud/bigquery/RoutineInfo.java | 28 ++++++++++++++++++ .../cloud/bigquery/RoutineInfoTest.java | 5 ++++ .../google/cloud/bigquery/RoutineTest.java | 5 ++++ .../cloud/bigquery/it/ITBigQueryTest.java | 29 ++++++++++++++++++- 6 files changed, 75 insertions(+), 9 deletions(-) diff --git a/google-cloud-bigquery/clirr-ignored-differences.xml b/google-cloud-bigquery/clirr-ignored-differences.xml index bfd3ee754..6c1fd8cd6 100644 --- a/google-cloud-bigquery/clirr-ignored-differences.xml +++ b/google-cloud-bigquery/clirr-ignored-differences.xml @@ -1,15 +1,10 @@ - + 7013 - com/google/cloud/bigquery/ExternalTableDefinition - java.lang.String getConnectionId() - - - 7013 - com/google/cloud/bigquery/ExternalTableDefinition$Builder - com.google.cloud.bigquery.ExternalTableDefinition$Builder setConnectionId(java.lang.String) + com/google/cloud/bigquery/RoutineInfo$Builder + com.google.cloud.bigquery.RoutineInfo$Builder setDeterminismLevel(java.lang.String) \ No newline at end of file diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java index f324f9d50..2fbf1d67d 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java @@ -87,6 +87,12 @@ Builder setLastModifiedTime(Long lastModifiedMillis) { return this; } + @Override + public Builder setDeterminismLevel(String determinismLevel) { + infoBuilder.setDeterminismLevel(determinismLevel); + return this; + } + @Override public Builder setLanguage(String language) { infoBuilder.setLanguage(language); diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java index ba93b3d83..1f9c252d2 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java @@ -62,6 +62,7 @@ public Routine apply(RoutineInfo routineInfo) { private final String routineType; private final Long creationTime; private final String description; + private final String determinismLevel; private final Long lastModifiedTime; private final String language; private final List argumentList; @@ -89,6 +90,12 @@ public abstract static class Builder { abstract Builder setLastModifiedTime(Long lastModifiedMillis); + /** + * Sets the JavaScript UDF determinism levels (e.g. DETERMINISM_LEVEL_UNSPECIFIED, + * DETERMINISTIC, NOT_DETERMINISTIC) only applicable to Javascript UDFs. + */ + public abstract Builder setDeterminismLevel(String determinismLevel); + /** Sets the language for the routine (e.g. SQL or JAVASCRIPT) */ public abstract Builder setLanguage(String language); @@ -147,6 +154,7 @@ static class BuilderImpl extends Builder { private String routineType; private Long creationTime; private String description; + private String determinismLevel; private Long lastModifiedTime; private String language; private List argumentList; @@ -162,6 +170,7 @@ static class BuilderImpl extends Builder { this.routineType = routineInfo.routineType; this.creationTime = routineInfo.creationTime; this.description = routineInfo.description; + this.determinismLevel = routineInfo.determinismLevel; this.lastModifiedTime = routineInfo.lastModifiedTime; this.language = routineInfo.language; this.argumentList = routineInfo.argumentList; @@ -176,6 +185,7 @@ static class BuilderImpl extends Builder { this.routineType = routinePb.getRoutineType(); this.creationTime = routinePb.getCreationTime(); this.description = routinePb.getDescription(); + this.determinismLevel = routinePb.getDeterminismLevel(); this.lastModifiedTime = routinePb.getLastModifiedTime(); this.language = routinePb.getLanguage(); if (routinePb.getArguments() != null) { @@ -223,6 +233,12 @@ public Builder setDescription(String description) { return this; } + @Override + public Builder setDeterminismLevel(String determinismLevel) { + this.determinismLevel = determinismLevel; + return this; + } + @Override Builder setLastModifiedTime(Long lastModifiedMillis) { this.lastModifiedTime = lastModifiedMillis; @@ -271,6 +287,7 @@ public RoutineInfo build() { this.routineType = builder.routineType; this.creationTime = builder.creationTime; this.description = builder.description; + this.determinismLevel = builder.determinismLevel; this.lastModifiedTime = builder.lastModifiedTime; this.language = builder.language; this.argumentList = builder.argumentList; @@ -304,6 +321,11 @@ public String getDescription() { return description; } + /** Returns the determinism level of the JavaScript UDF if defined. */ + public String getDeterminismLevel() { + return determinismLevel; + } + /** * Returns the last modification time of the routine, represented as milliseconds since the epoch. */ @@ -354,6 +376,7 @@ public String toString() { .add("routineType", routineType) .add("creationTime", creationTime) .add("description", description) + .add("determinismLevel", determinismLevel) .add("lastModifiedTime", lastModifiedTime) .add("language", language) .add("arguments", argumentList) @@ -371,6 +394,7 @@ public int hashCode() { routineType, creationTime, description, + determinismLevel, lastModifiedTime, language, argumentList, @@ -412,6 +436,7 @@ Routine toPb() { .setDefinitionBody(getBody()) .setCreationTime(getCreationTime()) .setDescription(getDescription()) + .setDeterminismLevel(getDeterminismLevel()) .setLastModifiedTime(getLastModifiedTime()) .setLanguage(getLanguage()); if (getRoutineId() != null) { @@ -420,6 +445,9 @@ Routine toPb() { if (getArguments() != null) { routinePb.setArguments(Lists.transform(getArguments(), RoutineArgument.TO_PB_FUNCTION)); } + if (getReturnType() != null) { + routinePb.setReturnType(getReturnType().toPb()); + } return routinePb; } diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineInfoTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineInfoTest.java index ce613193c..1f1181433 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineInfoTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineInfoTest.java @@ -29,6 +29,7 @@ public class RoutineInfoTest { private static final String ROUTINE_TYPE = "SCALAR_FUNCTION"; private static final Long CREATION_TIME = 10L; private static final String DESCRIPTION = "description"; + private static final String DETERMINISM = "DETERMINISTIC"; private static final Long LAST_MODIFIED_TIME = 20L; private static final String LANGUAGE = "SQL"; @@ -55,6 +56,7 @@ public class RoutineInfoTest { .setRoutineType(ROUTINE_TYPE) .setCreationTime(CREATION_TIME) .setDescription(DESCRIPTION) + .setDeterminismLevel(DETERMINISM) .setLastModifiedTime(LAST_MODIFIED_TIME) .setLanguage(LANGUAGE) .setArguments(ARGUMENT_LIST) @@ -81,6 +83,7 @@ public void testBuilder() { assertEquals(ROUTINE_TYPE, ROUTINE_INFO.getRoutineType()); assertEquals(CREATION_TIME, ROUTINE_INFO.getCreationTime()); assertEquals(DESCRIPTION, ROUTINE_INFO.getDescription()); + assertEquals(DETERMINISM, ROUTINE_INFO.getDeterminismLevel()); assertEquals(LAST_MODIFIED_TIME, ROUTINE_INFO.getLastModifiedTime()); assertEquals(LANGUAGE, ROUTINE_INFO.getLanguage()); assertEquals(ARGUMENT_LIST, ROUTINE_INFO.getArguments()); @@ -97,6 +100,7 @@ public void testOf() { assertNull(routineInfo.getRoutineType()); assertNull(routineInfo.getCreationTime()); assertNull(routineInfo.getDescription()); + assertNull(routineInfo.getDeterminismLevel()); assertNull(routineInfo.getLastModifiedTime()); assertNull(routineInfo.getLanguage()); assertNull(routineInfo.getArguments()); @@ -121,6 +125,7 @@ public void compareRoutineInfo(RoutineInfo expected, RoutineInfo value) { assertEquals(expected.getRoutineType(), value.getRoutineType()); assertEquals(expected.getCreationTime(), value.getCreationTime()); assertEquals(expected.getDescription(), value.getDescription()); + assertEquals(expected.getDeterminismLevel(), value.getDeterminismLevel()); assertEquals(expected.getLastModifiedTime(), value.getLastModifiedTime()); assertEquals(expected.getLanguage(), value.getLanguage()); assertEquals(expected.getArguments(), value.getArguments()); diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineTest.java index c51c77193..f0e29410d 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineTest.java @@ -38,6 +38,7 @@ public class RoutineTest { private static final RoutineId ROUTINE_ID = RoutineId.of("dataset", "routine"); + private static final String DETERMINISM_LEVEL = "DETERMINISTIC"; private static final String ETAG = "etag"; private static final String ROUTINE_TYPE = "SCALAR_FUNCTION"; private static final Long CREATION_TIME = 10L; @@ -65,6 +66,7 @@ public class RoutineTest { .setEtag(ETAG) .setRoutineType(ROUTINE_TYPE) .setCreationTime(CREATION_TIME) + .setDeterminismLevel(DETERMINISM_LEVEL) .setLastModifiedTime(LAST_MODIFIED_TIME) .setLanguage(LANGUAGE) .setArguments(ARGUMENT_LIST) @@ -96,6 +98,7 @@ public void testBuilder() { .setEtag(ETAG) .setRoutineType(ROUTINE_TYPE) .setCreationTime(CREATION_TIME) + .setDeterminismLevel(DETERMINISM_LEVEL) .setLastModifiedTime(LAST_MODIFIED_TIME) .setLanguage(LANGUAGE) .setArguments(ARGUMENT_LIST) @@ -104,6 +107,7 @@ public void testBuilder() { .setBody(BODY) .build(); assertEquals(ETAG, builtRoutine.getEtag()); + assertEquals(DETERMINISM_LEVEL, builtRoutine.getDeterminismLevel()); assertSame(bigquery, builtRoutine.getBigQuery()); } @@ -191,6 +195,7 @@ public void compareRoutineInfo(RoutineInfo expected, RoutineInfo value) { assertEquals(expected.getEtag(), value.getEtag()); assertEquals(expected.getRoutineType(), value.getRoutineType()); assertEquals(expected.getCreationTime(), value.getCreationTime()); + assertEquals(expected.getDeterminismLevel(), value.getDeterminismLevel()); assertEquals(expected.getLastModifiedTime(), value.getLastModifiedTime()); assertEquals(expected.getLanguage(), value.getLanguage()); assertEquals(expected.getArguments(), value.getArguments()); diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index b15e59f5e..dc8b3c355 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -1522,7 +1522,6 @@ public void testEmptyListRoutines() { @Test public void testRoutineLifecycle() throws InterruptedException { - String routineName = RemoteBigQueryHelper.generateRoutineName(); // Create a routine using SQL. String sql = @@ -1587,6 +1586,34 @@ public void testRoutineAPICreation() { assertEquals(routine.getRoutineType(), "SCALAR_FUNCTION"); } + @Test + public void testRoutineAPICreationJavascriptUDF() { + String routineName = RemoteBigQueryHelper.generateRoutineName(); + RoutineId routineId = RoutineId.of(ROUTINE_DATASET, routineName); + RoutineInfo routineInfo = + RoutineInfo.newBuilder(routineId) + .setLanguage("JAVASCRIPT") + .setRoutineType("SCALAR_FUNCTION") + .setDeterminismLevel("DETERMINISTIC") + .setArguments( + ImmutableList.of( + RoutineArgument.newBuilder() + .setName("instr") + .setKind("FIXED_TYPE") + .setDataType(StandardSQLDataType.newBuilder("STRING").build()) + .build())) + .setReturnType(StandardSQLDataType.newBuilder("STRING").build()) + .setBody("return instr.toUpperCase();") + .build(); + + Routine routine = bigquery.create(routineInfo); + assertNotNull(routine); + assertEquals(routine.getLanguage(), "JAVASCRIPT"); + assertEquals(routine.getDeterminismLevel(), "DETERMINISTIC"); + assertEquals(routine.getRoutineType(), "SCALAR_FUNCTION"); + assertEquals(routine.getReturnType(), StandardSQLDataType.newBuilder("STRING").build()); + } + @Test public void testAuthorizeRoutine() { String routineName = RemoteBigQueryHelper.generateRoutineName();