Skip to content
201 changes: 201 additions & 0 deletions examples/TileDB.CSharp.Example/ExampleDimensionLabels.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
using System;
using System.IO;
using System.Linq;

namespace TileDB.CSharp.Examples
{
public static class ExampleDimensionLabels
{
private static readonly string ArrayPath = ExampleUtil.MakeExamplePath("dimension-labels");
private static readonly Context Ctx = Context.GetDefault();

private static void CreateArray()
{
using var xIndex = Dimension.Create(Ctx, "x_index", 0, 5, 6);
using var sample = Dimension.Create(Ctx, "sample", 0, 3, 4);

using var domain = new Domain(Ctx);
domain.AddDimensions(xIndex, sample);

using var a = Attribute.Create<short>(Ctx, "a");

using var schema = new ArraySchema(Ctx, ArrayType.Dense);
schema.SetCellOrder(LayoutType.RowMajor);
schema.SetTileOrder(LayoutType.RowMajor);
schema.SetDomain(domain);
schema.AddAttribute(a);
schema.AddDimensionLabel(0, "x", DataOrder.Increasing, DataType.Float64);
schema.AddDimensionLabel(0, "y", DataOrder.Increasing, DataType.Float64);
schema.AddDimensionLabel(1, "timestamp", DataOrder.Increasing, DataType.DateTimeSecond);

Array.Create(Ctx, ArrayPath, schema);
}

private static void WriteArrayAndLabels()
{
short[] a = Enumerable.Range(1, 24).Select(x => (short)x).ToArray();
double[] x = { -1.0, -0.6, -0.2, 0.2, 0.6, 1.0 };
double[] y = { 0.0, 2.0, 4.0, 6.0, 8.0, 10.0 };
long[] timestamp = { 31943, 32380, 33131, 33228 };

using Array array = new Array(Ctx, ArrayPath);
array.Open(QueryType.Write);

using Query query = new Query(Ctx, array);
query.SetLayout(LayoutType.RowMajor);
query.SetDataBuffer("a", a);
query.SetDataBuffer("x", x);
query.SetDataBuffer("y", y);
query.SetDataBuffer("timestamp", timestamp);

query.Submit();

if (query.Status() != QueryStatus.Completed)
{
throw new Exception("Write query did not complete.");
}

array.Close();
}

private static void ReadArrayAndLabels()
{
Console.WriteLine("Read from main array");

using var array = new Array(Ctx, ArrayPath);
array.Open(QueryType.Read);

using var subarray = new Subarray(array);
subarray.AddRange(0, 1, 2);
subarray.AddRange(1, 0, 2);

short[] a = new short[6];
double[] x = new double[2];
double[] y = new double[2];
long[] timestamp = new long[3];

using var query = new Query(Ctx, array);
query.SetLayout(LayoutType.RowMajor);
query.SetSubarray(subarray);
query.SetDataBuffer("a", a);
query.SetDataBuffer("x", x);
query.SetDataBuffer("y", y);
query.SetDataBuffer("timestamp", timestamp);

query.Submit();

if (query.Status() != QueryStatus.Completed)
{
throw new Exception("Read query did not complete.");
}

for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
int x_val = i + 1;
int sample_val = j;
Console.WriteLine($"Cell ({x_val}, {sample_val})");
Console.WriteLine($" * a({x_val}, {sample_val}) = {a[3 * i + j]}");
Console.WriteLine($" * x({x_val}) = {x[i]}");
Console.WriteLine($" * y({x_val}) = {y[i]}");
Console.WriteLine($" * timestamp({sample_val}) = {TimeSpan.FromSeconds(timestamp[j])}");
}
}

array.Close();
}

private static void ReadTimestampData()
{
Console.WriteLine("Read from dimension label");

using var array = new Array(Ctx, ArrayPath);
array.Open(QueryType.Read);

using var subarray = new Subarray(array);
subarray.AddRange(1, 1, 3);

long[] timestamp = new long[3];

using var query = new Query(Ctx, array);
query.SetLayout(LayoutType.RowMajor);
query.SetSubarray(subarray);
query.SetDataBuffer("timestamp", timestamp);

query.Submit();

if (query.Status() != QueryStatus.Completed)
{
throw new Exception("Read query did not complete.");
}

for (int i = 0; i < 3; i++)
{
int sample_val = i + 1;
Console.WriteLine($"Cell ({sample_val})");
Console.WriteLine($" * timestamp({sample_val}) = {TimeSpan.FromSeconds(timestamp[i])}");
}

array.Close();
}

private static void ReadArrayByLabel()
{
Console.WriteLine("Read array from label ranges");

using var array = new Array(Ctx, ArrayPath);
array.Open(QueryType.Read);

using var subarray = new Subarray(array);
subarray.AddLabelRange("y", 3.0, 8.0);
subarray.AddLabelRange<long>("timestamp", 31943, 32380);

short[] a = new short[6];
double[] y = new double[3];
long[] timestamp = new long[2];

using var query = new Query(Ctx, array);
query.SetLayout(LayoutType.RowMajor);
query.SetSubarray(subarray);
query.SetDataBuffer("y", y);
query.SetDataBuffer("timestamp", timestamp);
query.SetDataBuffer("a", a);

query.Submit();

if (query.Status() != QueryStatus.Completed)
{
throw new Exception("Read query did not complete.");
}

for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
Console.WriteLine($"Cell ({y[i]}, {TimeSpan.FromSeconds(timestamp[j])})");
Console.WriteLine($" * a = {a[2 * i + j]}");
}
}

array.Close();
}

public static void Run()
{
if (Directory.Exists(ArrayPath))
{
Directory.Delete(ArrayPath, true);
}

CreateArray();
WriteArrayAndLabels();
ReadArrayAndLabels();
Console.WriteLine();
ReadTimestampData();
Console.WriteLine();
ReadArrayByLabel();
Console.WriteLine();
}
}
}
3 changes: 2 additions & 1 deletion examples/TileDB.CSharp.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using TileDB.CSharp;
namespace TileDB.CSharp.Examples;
Expand All @@ -17,6 +17,7 @@ static void Main(string[] args)
ExampleWritingSparseGlobal.Run();
ExampleDataframe.Run();
ExampleAggregateQuery.Run();
ExampleDimensionLabels.Run();

ExampleFile.RunLocal();
// ExampleFile.RunCloud("tiledb_api_token", "tiledb_namespace", "new_cloud_array_name", "s3://bucket/prefix/");
Expand Down
106 changes: 106 additions & 0 deletions sources/TileDB.CSharp/ArraySchema.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using TileDB.CSharp.Marshalling.SafeHandles;
using TileDB.Interop;
using ArraySchemaHandle = TileDB.CSharp.Marshalling.SafeHandles.ArraySchemaHandle;
Expand Down Expand Up @@ -81,6 +82,46 @@ public void AddEnumeration(Enumeration enumeration)
_ctx.handle_error(Methods.tiledb_array_schema_add_enumeration(ctxHandle, handle, enumHandle));
}

/// <summary>
/// Adds a dimension label to the <see cref="ArraySchema"/>.
/// </summary>
/// <param name="dimensionIndex">The dimension's index.</param>
/// <param name="name">The dimension label's name.</param>
/// <param name="labelOrder">The data order of the dimension label.</param>
/// <param name="labelType">The dimension lable's data type.</param>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public void AddDimensionLabel(uint dimensionIndex, string name, DataOrder labelOrder, DataType labelType)
{
using var ctxHandle = _ctx.Handle.Acquire();
using var handle = _handle.Acquire();
using var ms_name = new MarshaledString(name);
_ctx.handle_error(Methods.tiledb_array_schema_add_dimension_label(ctxHandle, handle, dimensionIndex, ms_name, (tiledb_data_order_t)labelOrder, (tiledb_datatype_t)labelType));
}

/// <summary>
/// Adds a dimension label to the <see cref="ArraySchema"/>, that has a specified tile extent.
/// </summary>
/// <param name="dimensionIndex">The dimension's index.</param>
/// <param name="name">The dimension label's name.</param>
/// <param name="labelOrder">The data order of the dimension label.</param>
/// <param name="labelType">The dimension lable's data type.</param>
/// <param name="extent">The dimension label's tile extent.</param>
/// <exception cref="InvalidOperationException"><typeparamref name="T"/> and <paramref name="labelType"/> do not match.</exception>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public void AddDimensionLabel<T>(uint dimensionIndex, string name, DataOrder labelOrder, DataType labelType, T extent) where T : struct
{
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>() || typeof(T) != EnumUtil.DataTypeToType(labelType))
{
ThrowHelpers.ThrowTypeMismatch(labelType);
}

using var ctxHandle = _ctx.Handle.Acquire();
using var handle = _handle.Acquire();
using var ms_name = new MarshaledString(name);
_ctx.handle_error(Methods.tiledb_array_schema_add_dimension_label(ctxHandle, handle, dimensionIndex, ms_name, (tiledb_data_order_t)labelOrder, (tiledb_datatype_t)labelType));
_ctx.handle_error(Methods.tiledb_array_schema_set_dimension_label_tile_extent(ctxHandle, handle, ms_name, (tiledb_datatype_t)labelType, &extent));
}

/// <summary>
/// Sets whether cells with duplicate coordinates are allowed in the <see cref="ArraySchema"/>.
/// </summary>
Expand Down Expand Up @@ -145,6 +186,21 @@ public void SetCellOrder(LayoutType layoutType)
_ctx.handle_error(Methods.tiledb_array_schema_set_cell_order(ctxHandle, handle, tiledb_layout));
}

/// <summary>
/// Sets the <see cref="FilterList"/> of filters that will be applied in one of the <see cref="ArraySchema"/>'s dimension labels.
/// </summary>
/// <param name="name">The dimension label's name.</param>
/// <param name="filterList">The dimension label's filter list.</param>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public void SetDimensionLabelFilterList(string name, FilterList filterList)
{
using var ctxHandle = _ctx.Handle.Acquire();
using var handle = _handle.Acquire();
using var ms_name = new MarshaledString(name);
using var filterListHandle = filterList.Handle.Acquire();
_ctx.handle_error(Methods.tiledb_array_schema_set_dimension_label_filter_list(ctxHandle, handle, ms_name, filterListHandle));
}

/// <summary>
/// Sets the <see cref="ArraySchema"/>'s tile order.
/// </summary>
Expand Down Expand Up @@ -491,6 +547,56 @@ public bool HasAttribute(string name)
return has_attr > 0;
}

/// <summary>
/// Gets a <see cref="CSharp.DimensionLabel"/> from the <see cref="ArraySchema"/> by name.
/// </summary>
/// <param name="name">The dimension label's name.</param>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public DimensionLabel DimensionLabel(string name)
{
var handle = new DimensionLabelHandle();
var successful = false;
tiledb_dimension_label_t* dimension_label_p = null;
try
{
using (var ctxHandle = _ctx.Handle.Acquire())
using (var schemaHandle = _handle.Acquire())
using (var ms_name = new MarshaledString(name))
{
_ctx.handle_error(Methods.tiledb_array_schema_get_dimension_label_from_name(ctxHandle, schemaHandle, ms_name, &dimension_label_p));
}
successful = true;
}
finally
{
if (successful)
{
handle.InitHandle(dimension_label_p);
}
else
{
handle.SetHandleAsInvalid();
}
}

return new DimensionLabel(_ctx, handle);
}

/// <summary>
/// Checks if a dimension label with the given name exists in the <see cref="ArraySchema"/> or not.
/// </summary>
/// <param name="name">The name to check.</param>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public bool HasDimensionLabel(string name)
{
int has_attr;
using var ctxHandle = _ctx.Handle.Acquire();
using var handle = _handle.Acquire();
using var ms_name = new MarshaledString(name);
_ctx.handle_error(Methods.tiledb_array_schema_has_dimension_label(ctxHandle, handle, ms_name, &has_attr));
return has_attr > 0;
}

/// <summary>
/// Load an <see cref="ArraySchema"/> from a URI.
/// </summary>
Expand Down
24 changes: 24 additions & 0 deletions sources/TileDB.CSharp/DataOrder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using TileDB.Interop;

namespace TileDB.CSharp
{
/// <summary>
/// Specifies the order of data in dimension labels.
/// </summary>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public enum DataOrder
{
/// <summary>
/// Data are not ordered.
/// </summary>
Unordered = tiledb_data_order_t.TILEDB_UNORDERED_DATA,
/// <summary>
/// Data are stored in increasing order.
/// </summary>
Increasing = tiledb_data_order_t.TILEDB_INCREASING_DATA,
/// <summary>
/// Data are stored in decreasing order.
/// </summary>
Decreasing = tiledb_data_order_t.TILEDB_DECREASING_DATA
}
}
Loading