Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions crates/sqllib/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,21 @@ where
{
value.map(|value| map_keys_(value))
}

#[doc(hidden)]
pub fn map_values_<I, T>(value: Map<I, T>) -> Array<T>
where
I: Ord + Clone,
T: Clone,
{
Arc::new(value.values().cloned().collect())
}

#[doc(hidden)]
pub fn map_valuesN<I, T>(value: Option<Map<I, T>>) -> Option<Array<T>>
where
I: Ord + Clone,
T: Clone,
{
value.map(|value| map_values_(value))
}
1 change: 1 addition & 0 deletions docs.feldera.com/docs/sql/function-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
* `MAP`: [map](map.md#map-literals)
* `MAP_CONTAINS_KEY`: [map](map.md#map_contains_key)
* `MAP_KEYS`: [map](map.md#map_keys)
* `MAP_VALUES`: [map](map.md#map_values)
* `MAX` (aggregate): [aggregates](aggregates.md#max), [aggregates](aggregates.md#window-max)
* `MD5`: [string](string.md#md5), [binary](binary.md#md5)
* `MIN` (aggregate): [aggregates](aggregates.md#min), [aggregates](aggregates.md#window-min)
Expand Down
1 change: 1 addition & 0 deletions docs.feldera.com/docs/sql/map.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Comparison operations (`=`, `<>`, `!=`, `>`, `<`, `>=`, `<=`) can be applied to
| <a id="cardinality"></a>`CARDINALITY`(map) | Returns the number of key-value pairs in the map. | `CARDINALITY(MAP['x', 4])` => 1 |
| <a id="map_contains_key"></a>`MAP_CONTAINS_KEY`(map, key) | Returns true when the map has an item with the specified key; `NULL` if any argument is `NULL`. | `MAP_CONTAINS_KEY(MAP['x', 4], 'x')` => `true` |
| <a id="map_keys"></a>`MAP_KEYS`(map) | Returns a sorted ARRAY of the appropriate type with all the keys of the MAP. | `MAP_KEYS(MAP['x', 4, 'y', 5])` => `['x', 'y']` |
| <a id="map_values"></a>`MAP_VALUES`(map) | Returns an ARRAY of the appropriate type with all the values of the MAP. | `MAP_VALUES(MAP['x', 4, 'y', 5])` => `[4, 5]` |

## The `UNNEST` Operator

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1892,6 +1892,7 @@ else if (arg0Type.is(DBSPTypeMap.class))
return next;
}
case MAP_KEYS:
case MAP_VALUES:
validateArgCount(node, operationName, ops.size(), 1);
DBSPExpression arg0 = ops.get(0);
String method = getArrayOrMapCallName(call, arg0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,9 @@ record Func(SqlOperator function, String functionName, SqlLibrary library,
new Func(SqlLibraryOperators.IFNULL, "IFNULL", SqlLibrary.BIG_QUERY,
"comparisons#ifnull", FunctionDocumentation.NO_FILE, false),
new Func(SqlLibraryOperators.MAP_KEYS, "MAP_KEYS", SqlLibrary.SPARK,
"map#map_keys", FunctionDocumentation.NO_FILE, false)
"map#map_keys", FunctionDocumentation.NO_FILE, false),
new Func(SqlLibraryOperators.MAP_VALUES, "MAP_VALUES", SqlLibrary.SPARK,
"map#map_values", FunctionDocumentation.NO_FILE, false)
// new Func(SqlLibraryOperators.SAFE_ORDINAL, "SAFE_ORDINAL", SqlLibrary.BIG_QUERY, "array", FunctionDocumentation.NO_FILE, false),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ static boolean sameFunction(FunctionDescription left, FunctionDescription right)

static void checkTestedBy(FunctionDescription description, TextFileCache fileContents) throws IOException {
// A list of file names separated by pipe symbols
String[] patterns = description.testedBy().split("\\|");
String[] patterns = description.testedBy().replace("\n", "").split("\\|");
Path pythonTests = Paths.get(PYTHON_TESTS);
for (String pattern: patterns) {
if (pattern.equalsIgnoreCase("nofile.py"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.dbsp.sqlCompiler.ir.expression.DBSPTupleExpression;
import org.dbsp.sqlCompiler.ir.expression.literal.DBSPI32Literal;
import org.dbsp.sqlCompiler.ir.expression.DBSPMapExpression;
import org.dbsp.sqlCompiler.ir.expression.literal.DBSPLiteral;
import org.dbsp.sqlCompiler.ir.expression.literal.DBSPStringLiteral;
import org.dbsp.sqlCompiler.ir.expression.DBSPZSetExpression;
import org.dbsp.sqlCompiler.ir.type.DBSPType;
Expand Down Expand Up @@ -184,7 +185,7 @@ public void testMapKeys() {
}

@Test
public void mapVariant() {
public void mapKeyVariant() {
var ccs = this.getCCS("""
create table j(j VARCHAR);

Expand All @@ -207,4 +208,41 @@ SELECT cast(contacts as MAP<varchar, variant>) contacts
d| 1
e| 1""");
}

@Test
public void testMapValues() {
String sql = "SELECT map_values(map['foo', 1, 'bar', 2])";
DBSPZSetExpression result = new DBSPZSetExpression(
new DBSPTupleExpression(new DBSPArrayExpression(
false,
new DBSPI32Literal(2),
new DBSPI32Literal(1))));
this.testQuery("", sql, new InputOutputChangeStream()
.addPair(new Change(), new Change("V", result)));
}

@Test
public void mapValuesVariant() {
var ccs = this.getCCS("""
create table j(j VARCHAR);

create LOCAL view user_props AS
SELECT PARSE_JSON(j) AS contacts FROM j;

create view abc as
WITH ref_profile AS (
SELECT cast(contacts as MAP<varchar, variant>) contacts
FROM user_props
) SELECT TO_JSON(value)
FROM ref_profile profile_0, UNNEST(MAP_VALUES(profile_0.contacts)) AS t(value)""");
ccs.step("""
INSERT INTO j VALUES('{ "a": "1", "b": 2, "c": [1, 2, 3], "d": null, "e": { "f": 1 } }');""", """
key | weight
------------------------
"1"| 1
2| 1
[1,2,3]| 1
null| 1
{"f":1}| 1""");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.dbsp.util.Linq;
import org.dbsp.util.Logger;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;

import java.sql.SQLException;
Expand Down