Skip to content

Commit

Permalink
Add filtered index support for SQLite
Browse files Browse the repository at this point in the history
  • Loading branch information
sjp committed Jul 14, 2022
1 parent 7f6ab0d commit fd00c89
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using SJP.Schematic.Tests.Utilities;

namespace SJP.Schematic.Sqlite.Tests.Integration;

Expand Down Expand Up @@ -96,4 +97,18 @@ public async Task Indexes_WhenGivenTableWithUniqueIndex_ReturnsIndexWithIsUnique

Assert.That(index.IsUnique, Is.True);
}

[Test]
public async Task Indexes_WhenGivenTableWithFilteredIndexes_ReturnsIndexWithFilteredDefinition()
{
var table = await GetTableAsync("table_test_table_38").ConfigureAwait(false);
var index1 = table.Indexes.Single(i => i.Name.LocalName == "ix_test_table_38_1");
var index2 = table.Indexes.Single(i => i.Name.LocalName == "ix_test_table_38_2");

Assert.Multiple(() =>
{
Assert.That(index1.FilterDefinition, OptionIs.None);
Assert.That(index2.FilterDefinition.UnwrapSome(), Is.EqualTo("where test_column_2 < 100 and test_column_2 > 3"));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,14 @@ test_column_3 int generated always as (test_column_1 * test_column_1 * test_colu
test_column_4 int constraint computed_col_constraint as (test_column_1 * test_column_1 * test_column_1 * test_column_1) virtual
)", CancellationToken.None).ConfigureAwait(false);

await DbConnection.ExecuteAsync(@"
create table table_test_table_38 (
test_column_1 int not null,
test_column_2 int not null
)", CancellationToken.None).ConfigureAwait(false);
await DbConnection.ExecuteAsync("create index ix_test_table_38_1 on table_test_table_38 (test_column_1)", CancellationToken.None).ConfigureAwait(false);
await DbConnection.ExecuteAsync("create index ix_test_table_38_2 on table_test_table_38 (test_column_2) where test_column_2 < 100 and test_column_2 > 3", CancellationToken.None).ConfigureAwait(false);

await DbConnection.ExecuteAsync("create table trigger_test_table_1 (table_id integer primary key not null)", CancellationToken.None).ConfigureAwait(false);
await DbConnection.ExecuteAsync("create table trigger_test_table_2 (table_id integer primary key not null)", CancellationToken.None).ConfigureAwait(false);
await DbConnection.ExecuteAsync(@"create trigger trigger_test_table_1_trigger_1
Expand Down
25 changes: 25 additions & 0 deletions src/SJP.Schematic.Sqlite/Queries/GetIndexDefinition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using SJP.Schematic.Core;
using SJP.Schematic.Core.Extensions;

namespace SJP.Schematic.Sqlite.Queries;

internal static class GetIndexDefinition
{
internal sealed record Query
{
public string TableName { get; init; } = default!;

public string IndexName { get; init; } = default!;
}

internal static string Sql(IDatabaseDialect dialect, string schemaName)
{
if (dialect == null)
throw new ArgumentNullException(nameof(dialect));
if (schemaName.IsNullOrWhiteSpace())
throw new ArgumentNullException(nameof(schemaName));

return $"select sql from { dialect.QuoteIdentifier(schemaName) }.sqlite_master where type = 'index' and tbl_name = @{ nameof(Query.TableName) } and name = @{ nameof(Query.IndexName) }";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,31 @@ private async Task<IReadOnlyCollection<IDatabaseIndex>> LoadIndexesAsyncCore(Ide
.Select(i => columnLookup[i.name!])
.ToList();

var index = new SqliteDatabaseIndex(indexList.name, indexList.unique, indexColumns, includedColumns, Option<string>.None);
var indexSchema = await DbConnection.ExecuteScalarAsync<string>(
GetIndexDefinition.Sql(Dialect, tableName.Schema!),
new GetIndexDefinition.Query { TableName = tableName.LocalName, IndexName = indexList.name },
cancellationToken
).ConfigureAwait(false);

var filterDefinition = Option<string>.None;
if (indexSchema != null)
{
var tokens = Tokenizer.TryTokenize(indexSchema);
if (tokens.HasValue)
{
var whereToken = tokens.Value.FirstOrDefault(t => t.Kind == SqliteToken.Where);
if (whereToken.Kind == SqliteToken.Where)
{
var location = whereToken.Position.Absolute;
var definition = indexSchema[location..];
filterDefinition = !definition.IsNullOrWhiteSpace()
? Option<string>.Some(definition)
: Option<string>.None;
}
}
}

var index = new SqliteDatabaseIndex(indexList.name, indexList.unique, indexColumns, includedColumns, filterDefinition);
result.Add(index);
}

Expand Down

0 comments on commit fd00c89

Please sign in to comment.