Package dev.frostlake.values
Class VariantUndefined
java.lang.Object
dev.frostlake.values.VariantUndefined
The VARIANT
undefined boundary — where a SQL NULL becomes an UndefinedNode and where the
sentinel must be told apart from a JSON null.
Live-verified on a real account. With ac = ARRAY_CONSTRUCT(1,NULL,2) (which
renders [1,undefined,2]) and pj = PARSE_JSON('[1,null,2]'):
ARRAY_CONSTRUCT(1,NULL,2) [1,NULL,2] ARRAY_APPEND([1],NULL) ARRAY_PREPEND([1],NULL)
ARRAY_INSERT([1],4,9) ARRAY_REPEAT(NULL,3) TRANSFORM([1,2], x -> NULL) [** NULL]
-> every SQL NULL entering an ARRAY becomes `undefined`
PARSE_JSON('[1,null,2]') ARRAY_CONSTRUCT(PARSE_JSON('null')) OBJECT_CONSTRUCT_KEEP_NULL('k',NULL)
-> keep the JSON null; TO_ARRAY(NULL) is SQL NULL, OBJECT_CONSTRUCT('k',NULL) is {}
TYPEOF(GET(ac,1)) -> SQL NULL TYPEOF(GET(pj,1)) -> 'NULL_VALUE'
GET(ac,1) IS NULL -> TRUE GET(pj,1) IS NULL -> FALSE
IS_NULL_VALUE(GET(ac,1)) -> SQL NULL IS_NULL_VALUE(GET(pj,1)) -> TRUE
TO_JSON(ac) -> [1,undefined,2] ac = pj -> FALSE
Because an undefined never escapes the variant layer as a value, the sentinel deliberately
reports JsonNode.isNull() — every consumer that has not heard of it reads SQL NULL, which is the
right answer. Only the sites that must distinguish the two nulls call isUndefined(JsonNode).
An undefined lives only in an ARRAY. As an OBJECT member or as a whole VARIANT it degrades:
live, PARSE_JSON('{"a":undefined}') is {"a":null} and PARSE_JSON('undefined') is
SQL NULL — both handled by restore(JsonNode).
-
Method Summary
Modifier and TypeMethodDescriptionstatic tools.jackson.databind.JsonNodeasObjectMember(tools.jackson.databind.JsonNode node) The node an ARRAY element takes when it MOVES INTO an object: anundefineddegrades to a JSON null, everything else passes through.static ObjectelementValue(tools.jackson.databind.JsonNode node) The runtime value an ARRAY element binds to in a lambda or any other scalar context: anundefinedis SQL NULL, everything else is its typed semi-structured value.static booleanisUndefined(tools.jackson.databind.JsonNode node) Whether this tree node is theundefinedsentinel rather than a JSON null (or anything else).static StringmarkTokens(String text) Replaces every bareundefinedtoken OUTSIDE of double-quoted strings withMARKER_LITERALso a JSON parser accepts it.static booleanmayContainToken(String text) A cheap pre-check: the text cannot hold a bareundefinedtoken unless it contains the word.static tools.jackson.databind.JsonNodenode()Theundefinedsentinel node.static tools.jackson.databind.JsonNodeParses JSON text that may carry Snowflake's bareundefinedtokens.static tools.jackson.databind.JsonNoderestore(tools.jackson.databind.JsonNode node) Turns every placeholder left bymarkTokens(String)into the sentinel, applying Snowflake's placement rules: an ARRAY element keepsundefined, an OBJECT member degrades to a JSON null (live:PARSE_JSON('{"a":undefined}')is{"a":null}) and a whole-valueundefinedis returned as the sentinel for the caller to read as SQL NULL (live:PARSE_JSON('undefined')is SQL NULL).
-
Method Details
-
node
public static tools.jackson.databind.JsonNode node()Theundefinedsentinel node. -
isUndefined
public static boolean isUndefined(tools.jackson.databind.JsonNode node) Whether this tree node is theundefinedsentinel rather than a JSON null (or anything else). -
asObjectMember
public static tools.jackson.databind.JsonNode asObjectMember(tools.jackson.databind.JsonNode node) The node an ARRAY element takes when it MOVES INTO an object: anundefineddegrades to a JSON null, everything else passes through. Live-verified:ARRAYS_ZIP(ARRAY_CONSTRUCT(1,NULL), ARRAY_CONSTRUCT(2,3))is[{"$1":1,"$2":2},{"$1":null,"$2":3}]andARRAYS_TO_OBJECT(['a','b'], ARRAY_CONSTRUCT(1,NULL))is{"a":1,"b":null}. -
elementValue
The runtime value an ARRAY element binds to in a lambda or any other scalar context: anundefinedis SQL NULL, everything else is its typed semi-structured value. Live-verifiedREDUCE(ARRAY_CONSTRUCT(1,NULL,2), 0, (acc,x) -> acc + COALESCE(x::int,10))is 13, so the lambda saw SQL NULL for the middle element. -
readTree
public static tools.jackson.databind.JsonNode readTree(tools.jackson.databind.ObjectMapper mapper, String text) Parses JSON text that may carry Snowflake's bareundefinedtokens. Text without one is handed straight tomapper, so the ordinary path is untouched. -
mayContainToken
A cheap pre-check: the text cannot hold a bareundefinedtoken unless it contains the word. -
markTokens
Replaces every bareundefinedtoken OUTSIDE of double-quoted strings withMARKER_LITERALso a JSON parser accepts it. Word boundaries are honored (myundefinedstays untouched) and text inside string values is never rewritten, so["undefined"]keeps its genuine string element. -
restore
public static tools.jackson.databind.JsonNode restore(tools.jackson.databind.JsonNode node) Turns every placeholder left bymarkTokens(String)into the sentinel, applying Snowflake's placement rules: an ARRAY element keepsundefined, an OBJECT member degrades to a JSON null (live:PARSE_JSON('{"a":undefined}')is{"a":null}) and a whole-valueundefinedis returned as the sentinel for the caller to read as SQL NULL (live:PARSE_JSON('undefined')is SQL NULL).
-