blob: 80531e86274b5b61b4af481948e754f1131ce69b [file] [log] [blame]
/*
* 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.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using Apache.Arrow.Adbc.Extensions;
using Apache.Arrow.Types;
using Xunit;
namespace Apache.Arrow.Adbc.Tests
{
/// <summary>
/// Validate StandardSchema.
/// </summary>
public class StandardSchemasTests
{
[Fact]
public void CanValidateSchema()
{
IReadOnlyList<IArrowArray> columnDataArrays = StandardSchemas.ColumnSchema.Validate(GetColumnDataArrays());
IReadOnlyList<IArrowArray> tableDataArrays = StandardSchemas.TableSchema.Validate(GetTableDataArrays(columnDataArrays));
IReadOnlyList<IArrowArray> schemaDataArrays = StandardSchemas.DbSchemaSchema.Validate(GetDbSchemaDataArrays(tableDataArrays));
_ = StandardSchemas.GetObjectsSchema.Validate(GetGetObjectsDataArrays(schemaDataArrays));
}
[Fact]
public void CanInvalidateColumnTypeSchema()
{
Assert.Throws<ArgumentException>(() => StandardSchemas.ColumnSchema.Validate(GetColumnDataArraysInvalidColumnType()));
}
[Fact]
public void CanInvalidateColumnCountSchema()
{
Assert.Throws<ArgumentException>(() => StandardSchemas.ColumnSchema.Validate(GetColumnDataArraysMissingColumn()));
}
[Fact]
public void CanInvalidateTableSchema()
{
IReadOnlyList<IArrowArray> columnDataArrays = GetColumnDataArraysInvalidColumnType();
Assert.Throws<ArgumentException>(() => StandardSchemas.TableSchema.Validate(GetTableDataArrays(columnDataArrays)));
}
[Fact]
public void CanInvalidateDbSchema()
{
IReadOnlyList<IArrowArray> columnDataArrays = GetColumnDataArraysInvalidColumnType();
IReadOnlyList<IArrowArray> tableDataArrays = GetTableDataArrays(columnDataArrays);
Assert.Throws<ArgumentException>(() => StandardSchemas.DbSchemaSchema.Validate(GetDbSchemaDataArrays(tableDataArrays)));
}
[Fact]
public void CanInvalidateGetObjectsSchema()
{
IReadOnlyList<IArrowArray> columnDataArrays = GetColumnDataArraysInvalidColumnType();
IReadOnlyList<IArrowArray> tableDataArrays = GetTableDataArrays(columnDataArrays);
IReadOnlyList<IArrowArray?> schemaDataArrays = GetDbSchemaDataArrays(tableDataArrays);
Assert.Throws<ArgumentException>(() => StandardSchemas.GetObjectsSchema.Validate(GetGetObjectsDataArrays(schemaDataArrays)));
}
[Fact]
public void CanValidateGetInfoSchema()
{
_ = StandardSchemas.GetInfoSchema.Validate(GetGetInfoDataArrays());
}
[Fact]
public void CanInvalidateGetInfoSchema()
{
Exception exception = Assert.Throws<ArgumentException>(() => StandardSchemas.GetInfoSchema.Validate(GetGetInfoDataArraysWithInvalidType()));
Assert.Contains("Expecting data type Apache.Arrow.Types.StringType but found Apache.Arrow.Types.Int32Type on field with name item.", exception.Message);
}
private IReadOnlyList<IArrowArray> GetGetObjectsDataArrays(IReadOnlyList<IArrowArray?> schemaDataArrays)
{
List<IArrowArray?> catalogDbSchemasValues = new List<IArrowArray?>()
{
new StructArray(
new StructType(StandardSchemas.DbSchemaSchema),
0,
schemaDataArrays,
new ArrowBuffer.BitmapBuilder().Build())
};
IReadOnlyList<IArrowArray> getObjectsDataArrays = new List<IArrowArray>
{
new StringArray.Builder().Build(),
catalogDbSchemasValues.BuildListArrayForType(new StructType(StandardSchemas.DbSchemaSchema)),
};
return getObjectsDataArrays;
}
private IReadOnlyList<IArrowArray> GetDbSchemaDataArrays(IReadOnlyList<IArrowArray> tableDataArrays)
{
List<IArrowArray> dbSchemaTablesValues = new List<IArrowArray>()
{
new StructArray(
new StructType(StandardSchemas.TableSchema),
0,
tableDataArrays,
new ArrowBuffer.BitmapBuilder().Build())
};
List<IArrowArray> schemaDataArrays = new List<IArrowArray>
{
new StringArray.Builder().Build(),
dbSchemaTablesValues.BuildListArrayForType(new StructType(StandardSchemas.TableSchema)),
};
return schemaDataArrays;
}
private IReadOnlyList<IArrowArray> GetTableDataArrays(IReadOnlyList<IArrowArray> columnDataArrays)
{
var columnData = new StructArray(
new StructType(StandardSchemas.ColumnSchema),
0,
columnDataArrays,
new ArrowBuffer.BitmapBuilder().Build());
List<IArrowArray?> tableColumnsValues = new List<IArrowArray?>()
{
columnData,
};
List<IArrowArray?> tableConstraintsValues = new List<IArrowArray?>()
{
null,
};
List<IArrowArray> tableDataArrays = new List<IArrowArray>
{
new StringArray.Builder().Build(),
new StringArray.Builder().Build(),
tableColumnsValues.BuildListArrayForType(new StructType(StandardSchemas.ColumnSchema)),
tableConstraintsValues.BuildListArrayForType(new StructType(StandardSchemas.ConstraintSchema))
};
return tableDataArrays;
}
private static List<IArrowArray> GetColumnDataArrays() => new List<IArrowArray>
{
new StringArray.Builder().Build(),
new Int32Array.Builder().Build(),
new StringArray.Builder().Build(),
new Int16Array.Builder().Build(),
new StringArray.Builder().Build(),
new Int32Array.Builder().Build(),
new Int16Array.Builder().Build(),
new Int16Array.Builder().Build(),
new Int16Array.Builder().Build(),
new StringArray.Builder().Build(),
new Int16Array.Builder().Build(),
new Int16Array.Builder().Build(),
new Int32Array.Builder().Build(),
new StringArray.Builder().Build(),
new StringArray.Builder().Build(),
new StringArray.Builder().Build(),
new StringArray.Builder().Build(),
new BooleanArray.Builder().Build(),
new BooleanArray.Builder().Build(),
};
private static List<IArrowArray> GetColumnDataArraysInvalidColumnType() => new List<IArrowArray>
{
new StringArray.Builder().Build(),
new Int32Array.Builder().Build(),
new StringArray.Builder().Build(),
new Int16Array.Builder().Build(),
new StringArray.Builder().Build(),
new Int32Array.Builder().Build(),
new Int16Array.Builder().Build(),
new Int16Array.Builder().Build(),
new Int16Array.Builder().Build(),
new StringArray.Builder().Build(),
new Int16Array.Builder().Build(),
new Int16Array.Builder().Build(),
new Int32Array.Builder().Build(),
new StringArray.Builder().Build(),
new StringArray.Builder().Build(),
new StringArray.Builder().Build(),
new StringArray.Builder().Build(),
new BooleanArray.Builder().Build(),
new StringArray.Builder().Build(), // invalid type, expects BooleanArray
};
private static List<IArrowArray> GetColumnDataArraysMissingColumn() => new List<IArrowArray>
{
new StringArray.Builder().Build(),
new Int32Array.Builder().Build(),
new StringArray.Builder().Build(),
new Int16Array.Builder().Build(),
new StringArray.Builder().Build(),
new Int32Array.Builder().Build(),
new Int16Array.Builder().Build(),
new Int16Array.Builder().Build(),
new Int16Array.Builder().Build(),
new StringArray.Builder().Build(),
new Int16Array.Builder().Build(),
new Int16Array.Builder().Build(),
new Int32Array.Builder().Build(),
new StringArray.Builder().Build(),
new StringArray.Builder().Build(),
new StringArray.Builder().Build(),
new StringArray.Builder().Build(),
new BooleanArray.Builder().Build(),
// new BooleanArray.Builder().Build(), // missing column
};
private static List<IArrowArray> GetGetInfoDataArrays()
{
UnionType infoUnionType = new UnionType(
new List<Field>()
{
new Field("string_value", StringType.Default, true),
new Field("bool_value", BooleanType.Default, true),
new Field("int64_value", Int64Type.Default, true),
new Field("int32_bitmask", Int32Type.Default, true),
new Field(
"string_list",
new ListType(
new Field("item", StringType.Default, true)
),
false
),
new Field(
"int32_to_int32_list_map",
new ListType(
new Field("entries", new StructType(
new List<Field>()
{
new Field("key", Int32Type.Default, false),
new Field("value", Int32Type.Default, true),
}
), false)
),
true
)
},
new int[] { 0, 1, 2, 3, 4, 5 }.ToArray(),
UnionMode.Dense);
UInt32Array.Builder infoNameBuilder = new UInt32Array.Builder();
ArrowBuffer.Builder<byte> typeBuilder = new ArrowBuffer.Builder<byte>();
ArrowBuffer.Builder<int> offsetBuilder = new ArrowBuffer.Builder<int>();
StringArray.Builder stringInfoBuilder = new StringArray.Builder();
int nullCount = 0;
int arrayLength = 0;
StructType entryType = new StructType(
new List<Field>(){
new Field("key", Int32Type.Default, false),
new Field("value", Int32Type.Default, true)});
StructArray entriesDataArray = new StructArray(entryType, 0,
new[] { new Int32Array.Builder().Build(), new Int32Array.Builder().Build() },
new ArrowBuffer.BitmapBuilder().Build());
List<IArrowArray> childrenArrays = new List<IArrowArray>()
{
stringInfoBuilder.Build(),
new BooleanArray.Builder().Build(),
new Int64Array.Builder().Build(),
new Int32Array.Builder().Build(),
new ListArray.Builder(StringType.Default).Build(),
new List<IArrowArray?>(){ entriesDataArray }.BuildListArrayForType(entryType)
};
DenseUnionArray infoValue = new DenseUnionArray(infoUnionType, arrayLength, childrenArrays, typeBuilder.Build(), offsetBuilder.Build(), nullCount);
List<IArrowArray> dataArrays = new List<IArrowArray>
{
infoNameBuilder.Build(),
infoValue
};
return dataArrays;
}
private static List<IArrowArray> GetGetInfoDataArraysWithInvalidType()
{
UnionType infoUnionType = new UnionType(
new List<Field>()
{
new Field("string_value", StringType.Default, true),
new Field("bool_value", BooleanType.Default, true),
new Field("int64_value", Int64Type.Default, true),
new Field("int32_bitmask", Int32Type.Default, true),
new Field(
"string_list",
new ListType(
new Field("item", StringType.Default, true)
),
false
),
new Field(
"int32_to_int32_list_map",
new ListType(
new Field("entries", new StructType(
new List<Field>()
{
new Field("key", Int32Type.Default, false),
new Field("value", Int32Type.Default, true),
}
), false)
),
true
)
},
new int[] { 0, 1, 2, 3, 4, 5 }.ToArray(),
UnionMode.Dense);
UInt32Array.Builder infoNameBuilder = new UInt32Array.Builder();
ArrowBuffer.Builder<byte> typeBuilder = new ArrowBuffer.Builder<byte>();
ArrowBuffer.Builder<int> offsetBuilder = new ArrowBuffer.Builder<int>();
StringArray.Builder stringInfoBuilder = new StringArray.Builder();
int nullCount = 0;
int arrayLength = 0;
StructType entryType = new StructType(
new List<Field>(){
new Field("key", Int32Type.Default, false),
new Field("value", Int32Type.Default, true)});
StructArray entriesDataArray = new StructArray(
entryType,
0,
new[] { new Int32Array.Builder().Build(), new Int32Array.Builder().Build() },
new ArrowBuffer.BitmapBuilder().Build());
List<IArrowArray> childrenArrays = new List<IArrowArray>()
{
stringInfoBuilder.Build(),
new BooleanArray.Builder().Build(),
new Int64Array.Builder().Build(),
new Int32Array.Builder().Build(),
new ListArray.Builder(Int32Type.Default).Build(), // Should be StringType.Default
new List<IArrowArray?>(){ entriesDataArray }.BuildListArrayForType(entryType)
};
DenseUnionArray infoValue = new DenseUnionArray(infoUnionType, arrayLength, childrenArrays, typeBuilder.Build(), offsetBuilder.Build(), nullCount);
List<IArrowArray> dataArrays = new List<IArrowArray>
{
infoNameBuilder.Build(),
infoValue
};
return dataArrays;
}
}
}