Skip to content

Commit

Permalink
Microsoft.Data.Sqlite: Add Default Timeout connection string keyword
Browse files Browse the repository at this point in the history
- Fixes dotnet#22505
  • Loading branch information
Nicolas Michels committed Oct 24, 2020
1 parent d24705b commit 0cbb867
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 6 deletions.
5 changes: 5 additions & 0 deletions src/Microsoft.Data.Sqlite.Core/SqliteConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,11 @@ public override void Open()
this.ExecuteNonQuery("PRAGMA recursive_triggers = 1;");
}

if (ConnectionOptions.DefaultTimeout.HasValue)
{
DefaultTimeout = ConnectionOptions.DefaultTimeout.Value;
}

if (_collations != null)
{
foreach (var item in _collations)
Expand Down
36 changes: 32 additions & 4 deletions src/Microsoft.Data.Sqlite.Core/SqliteConnectionStringBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class SqliteConnectionStringBuilder : DbConnectionStringBuilder
private const string PasswordKeyword = "Password";
private const string ForeignKeysKeyword = "Foreign Keys";
private const string RecursiveTriggersKeyword = "Recursive Triggers";
private const string DefaultTimeoutKeyword = "Default Timeout";
private const string CommandTimeoutKeyword = "Command Timeout";

private enum Keywords
{
Expand All @@ -35,7 +37,8 @@ private enum Keywords
Cache,
Password,
ForeignKeys,
RecursiveTriggers
RecursiveTriggers,
DefaultTimeout
}

private static readonly IReadOnlyList<string> _validKeywords;
Expand All @@ -47,30 +50,34 @@ private enum Keywords
private string _password = string.Empty;
private bool? _foreignKeys;
private bool _recursiveTriggers;
private int? _defaultTimeout;

static SqliteConnectionStringBuilder()
{
var validKeywords = new string[6];
var validKeywords = new string[7];
validKeywords[(int)Keywords.DataSource] = DataSourceKeyword;
validKeywords[(int)Keywords.Mode] = ModeKeyword;
validKeywords[(int)Keywords.Cache] = CacheKeyword;
validKeywords[(int)Keywords.Password] = PasswordKeyword;
validKeywords[(int)Keywords.ForeignKeys] = ForeignKeysKeyword;
validKeywords[(int)Keywords.RecursiveTriggers] = RecursiveTriggersKeyword;
validKeywords[(int)Keywords.DefaultTimeout] = DefaultTimeoutKeyword;
_validKeywords = validKeywords;

_keywords = new Dictionary<string, Keywords>(8, StringComparer.OrdinalIgnoreCase)
_keywords = new Dictionary<string, Keywords>(10, StringComparer.OrdinalIgnoreCase)
{
[DataSourceKeyword] = Keywords.DataSource,
[ModeKeyword] = Keywords.Mode,
[CacheKeyword] = Keywords.Cache,
[PasswordKeyword] = Keywords.Password,
[ForeignKeysKeyword] = Keywords.ForeignKeys,
[RecursiveTriggersKeyword] = Keywords.RecursiveTriggers,
[DefaultTimeoutKeyword] = Keywords.DefaultTimeout,

// aliases
[FilenameKeyword] = Keywords.DataSource,
[DataSourceNoSpaceKeyword] = Keywords.DataSource
[DataSourceNoSpaceKeyword] = Keywords.DataSource,
[CommandTimeoutKeyword] = Keywords.DefaultTimeout
};
}

Expand Down Expand Up @@ -182,6 +189,16 @@ public bool RecursiveTriggers
set => base[RecursiveTriggersKeyword] = _recursiveTriggers = value;
}

/// <summary>
/// Gets or sets a value indicating the Default Connection Timeout.
/// </summary>
/// <value>The Default Connection Timeout in seconds.</value>
public int? DefaultTimeout
{
get => _defaultTimeout;
set => base[DefaultTimeoutKeyword] = _defaultTimeout = value;
}

/// <summary>
/// Gets or sets the value associated with the specified key.
/// </summary>
Expand Down Expand Up @@ -225,6 +242,10 @@ public bool RecursiveTriggers
RecursiveTriggers = Convert.ToBoolean(value, CultureInfo.InvariantCulture);
return;

case Keywords.DefaultTimeout:
DefaultTimeout = Convert.ToInt32(value);
return;

default:
Debug.Assert(false, "Unexpected keyword: " + keyword);
return;
Expand Down Expand Up @@ -365,6 +386,9 @@ private object GetAt(Keywords index)
case Keywords.RecursiveTriggers:
return RecursiveTriggers;

case Keywords.DefaultTimeout:
return DefaultTimeout;

default:
Debug.Assert(false, "Unexpected keyword: " + index);
return null;
Expand Down Expand Up @@ -404,6 +428,10 @@ private void Reset(Keywords index)
_recursiveTriggers = false;
return;

case Keywords.DefaultTimeout:
_defaultTimeout = null;
return;

default:
Debug.Assert(false, "Unexpected keyword: " + index);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,14 @@ public void Keys_works()
var keys = (ICollection<string>)new SqliteConnectionStringBuilder().Keys;

Assert.True(keys.IsReadOnly);
Assert.Equal(6, keys.Count);
Assert.Equal(7, keys.Count);
Assert.Contains("Data Source", keys);
Assert.Contains("Mode", keys);
Assert.Contains("Cache", keys);
Assert.Contains("Password", keys);
Assert.Contains("Foreign Keys", keys);
Assert.Contains("Recursive Triggers", keys);
Assert.Contains("Default Timeout", keys);
}

[Fact]
Expand All @@ -132,7 +133,7 @@ public void Values_works()
var values = (ICollection<object>)new SqliteConnectionStringBuilder().Values;

Assert.True(values.IsReadOnly);
Assert.Equal(6, values.Count);
Assert.Equal(7, values.Count);
}

[Fact]
Expand Down Expand Up @@ -231,6 +232,27 @@ public void Item_throws_when_cannot_convert_to_bool_on_set(object value)
Assert.ThrowsAny<FormatException>(() => builder["Foreign Keys"] = value);
}

[Theory]
[InlineData("250", 250)]
public void Item_converts_to_int_on_set(object value, int? expected)
{
var builder = new SqliteConnectionStringBuilder();

builder["Default Timeout"] = value;

Assert.Equal(expected, builder["Default Timeout"]);
}

[Theory]
[InlineData("test")]
[InlineData("Unknown")]
public void Item_throws_when_cannot_convert_to_int_on_set(object value)
{
var builder = new SqliteConnectionStringBuilder();

Assert.ThrowsAny<FormatException>(() => builder["Default Timeout"] = value);
}

[Fact]
public void Clear_resets_everything()
{
Expand Down
22 changes: 22 additions & 0 deletions test/Microsoft.Data.Sqlite.Tests/SqliteConnectionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,28 @@ public void Open_works_when_uri()
}
}

[Fact]
public void Open_works_when_default_timeout()
{
using (var connection = new SqliteConnection("Data Source=:memory:;Default Timeout=100"))
{
connection.Open();

Assert.Equal(100, connection.DefaultTimeout);
}
}

[Fact]
public void Open_works_when_command_timeout()
{
using (var connection = new SqliteConnection("Data Source=:memory:;Command Timeout=100"))
{
connection.Open();

Assert.Equal(100, connection.DefaultTimeout);
}
}

[Fact]
public void Close_works()
{
Expand Down

0 comments on commit 0cbb867

Please sign in to comment.