Skip to content

Commit 5fda890

Browse files
authored
Merge pull request #100 from jonkeda/master
Allow for a missing datasource
2 parents faa5102 + cb649fd commit 5fda890

File tree

12 files changed

+116
-11
lines changed

12 files changed

+116
-11
lines changed

SQLite.CodeFirst.Console/Entity/Person.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System.ComponentModel.DataAnnotations;
1+
using System;
2+
using System.ComponentModel.DataAnnotations;
3+
using System.ComponentModel.DataAnnotations.Schema;
24

35
namespace SQLite.CodeFirst.Console.Entity
46
{
@@ -18,5 +20,9 @@ public abstract class Person : IEntity
1820

1921
[Required]
2022
public string City { get; set; }
23+
24+
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
25+
[SqlDefaultValue(DefaultValue = "DATETIME('now')")]
26+
public DateTime CreatedUtc { get; set; }
2127
}
2228
}

SQLite.CodeFirst.Console/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ private static void DisplaySeededData(DbContext context)
131131
System.Console.WriteLine("\t\t LastName: {0}", player.LastName);
132132
System.Console.WriteLine("\t\t Street: {0}", player.Street);
133133
System.Console.WriteLine("\t\t City: {0}", player.City);
134+
System.Console.WriteLine("\t\t Created: {0}", player.CreatedUtc);
134135
System.Console.WriteLine();
135136
}
136137
}

SQLite.CodeFirst.Test/IntegrationTests/SqlGenerationTest.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ public class SqlGenerationTest
1515
{
1616
private const string ReferenceSql =
1717
@"CREATE TABLE ""MyTable"" ([Id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [Name] nvarchar NOT NULL, FOREIGN KEY (Id) REFERENCES ""Coaches""(Id));
18-
CREATE TABLE ""Coaches"" ([Id] INTEGER PRIMARY KEY, [FirstName] nvarchar (50) COLLATE NOCASE, [LastName] nvarchar (50), [Street] nvarchar (100), [City] nvarchar NOT NULL);
19-
CREATE TABLE ""TeamPlayer"" ([Id] INTEGER PRIMARY KEY, [Number] int NOT NULL, [TeamId] int NOT NULL, [FirstName] nvarchar (50) COLLATE NOCASE, [LastName] nvarchar (50), [Street] nvarchar (100), [City] nvarchar NOT NULL, [Mentor_Id] int, FOREIGN KEY (Mentor_Id) REFERENCES ""TeamPlayer""(Id), FOREIGN KEY (TeamId) REFERENCES ""MyTable""(Id) ON DELETE CASCADE);
18+
CREATE TABLE ""Coaches"" ([Id] INTEGER PRIMARY KEY, [FirstName] nvarchar (50) COLLATE NOCASE, [LastName] nvarchar (50), [Street] nvarchar (100), [City] nvarchar NOT NULL, [CreatedUtc] datetime NOT NULL DEFAULT (DATETIME('now')));
19+
CREATE TABLE ""TeamPlayer"" ([Id] INTEGER PRIMARY KEY, [Number] int NOT NULL, [TeamId] int NOT NULL, [FirstName] nvarchar (50) COLLATE NOCASE, [LastName] nvarchar (50), [Street] nvarchar (100), [City] nvarchar NOT NULL, [CreatedUtc] datetime NOT NULL DEFAULT (DATETIME('now')), [Mentor_Id] int, FOREIGN KEY (Mentor_Id) REFERENCES ""TeamPlayer""(Id), FOREIGN KEY (TeamId) REFERENCES ""MyTable""(Id) ON DELETE CASCADE);
2020
CREATE TABLE ""Stadions"" ([Name] nvarchar (128) NOT NULL, [Street] nvarchar (128) NOT NULL, [City] nvarchar (128) NOT NULL, [Team_Id] int NOT NULL, PRIMARY KEY(Name, Street, City), FOREIGN KEY (Team_Id) REFERENCES ""MyTable""(Id) ON DELETE CASCADE);
2121
CREATE TABLE ""Foos"" ([FooId] INTEGER PRIMARY KEY, [Name] nvarchar, [FooSelf1Id] int, [FooSelf2Id] int, [FooSelf3Id] int, FOREIGN KEY (FooSelf1Id) REFERENCES ""Foos""(FooId), FOREIGN KEY (FooSelf2Id) REFERENCES ""Foos""(FooId), FOREIGN KEY (FooSelf3Id) REFERENCES ""Foos""(FooId));
2222
CREATE TABLE ""FooSelves"" ([FooSelfId] INTEGER PRIMARY KEY, [FooId] int NOT NULL, [Number] int NOT NULL, FOREIGN KEY (FooId) REFERENCES ""Foos""(FooId) ON DELETE CASCADE);
@@ -37,11 +37,11 @@ public class SqlGenerationTest
3737
private static string generatedSql;
3838

3939
// Does not work on the build server. No clue why.
40-
[Ignore]
40+
4141
[TestMethod]
4242
public void SqliteSqlGeneratorTest()
4343
{
44-
using (DbConnection connection = new SQLiteConnection("data source=:memory:"))
44+
using (DbConnection connection = new SQLiteConnection("FullUri=file::memory:"))
4545
{
4646
// This is important! Else the in memory database will not work.
4747
connection.Open();
@@ -51,7 +51,7 @@ public void SqliteSqlGeneratorTest()
5151
// ReSharper disable once UnusedVariable
5252
Player fo = context.Set<Player>().FirstOrDefault();
5353

54-
Assert.IsTrue(string.Equals(RemoveLineEndings(ReferenceSql), RemoveLineEndings(generatedSql)));
54+
Assert.AreEqual(RemoveLineEndings(ReferenceSql), RemoveLineEndings(generatedSql));
5555
}
5656
}
5757
}

SQLite.CodeFirst.Test/SQLite.CodeFirst.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
<Compile Include="UnitTests\Statement\ColumnConstraint\ColumnConstraintCollectionTest.cs" />
9999
<Compile Include="UnitTests\Statement\ColumnConstraint\NotNullConstraintTest.cs" />
100100
<Compile Include="UnitTests\Statement\ColumnConstraint\CollateConstraintTest.cs" />
101+
<Compile Include="UnitTests\Statement\ColumnConstraint\DefaultValueConstraintTest.cs" />
101102
<Compile Include="UnitTests\Statement\ColumnConstraint\UniqueConstraintTest.cs" />
102103
<Compile Include="UnitTests\Statement\ColumnStatementCollectionTest.cs" />
103104
<Compile Include="UnitTests\Statement\PrimaryKeyStatementTest.cs" />
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using SQLite.CodeFirst.Statement.ColumnConstraint;
3+
4+
namespace SQLite.CodeFirst.Test.UnitTests.Statement.ColumnConstraint
5+
{
6+
[TestClass]
7+
public class DefaultValueConstraintTest
8+
{
9+
[TestMethod]
10+
public void CreateStatement_StatementIsCorrect_IntDefault()
11+
{
12+
var defaultValueConstraint = new DefaultValueConstraint();
13+
defaultValueConstraint.DefaultValue = "0";
14+
string output = defaultValueConstraint.CreateStatement();
15+
Assert.AreEqual(output, "DEFAULT (0)");
16+
}
17+
18+
[TestMethod]
19+
public void CreateStatement_StatementIsCorrect_StringDefault()
20+
{
21+
var defaultValueConstraint = new DefaultValueConstraint();
22+
defaultValueConstraint.DefaultValue = @"'Something'";
23+
string output = defaultValueConstraint.CreateStatement();
24+
Assert.AreEqual(output, "DEFAULT ('Something')");
25+
}
26+
27+
[TestMethod]
28+
public void CreateStatement_StatementIsCorrect_ExpressionDefault()
29+
{
30+
var defaultValueConstraint = new DefaultValueConstraint();
31+
defaultValueConstraint.DefaultValue = @"datetime('now')";
32+
string output = defaultValueConstraint.CreateStatement();
33+
Assert.AreEqual(output, "DEFAULT (datetime('now'))");
34+
}
35+
}
36+
}

SQLite.CodeFirst/Internal/Builder/ColumnStatementCollectionBuilder.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ private IEnumerable<ColumnStatement> CreateColumnStatements()
4141
AddUniqueConstraintIfNecessary(property, columnStatement);
4242
AddCollationConstraintIfNecessary(property, columnStatement);
4343
AddPrimaryKeyConstraintAndAdjustTypeIfNecessary(property, columnStatement);
44+
AddDefaultValueConstraintIfNecessary(property, columnStatement);
4445

4546
yield return columnStatement;
4647
}
@@ -90,6 +91,15 @@ private static void AddUniqueConstraintIfNecessary(EdmProperty property, ColumnS
9091
}
9192
}
9293

94+
private static void AddDefaultValueConstraintIfNecessary(EdmProperty property, ColumnStatement columnStatement)
95+
{
96+
var value = property.GetCustomAnnotation<SqlDefaultValueAttribute>();
97+
if (value != null)
98+
{
99+
columnStatement.ColumnConstraints.Add(new DefaultValueConstraint { DefaultValue = value.DefaultValue });
100+
}
101+
}
102+
93103
private void AddPrimaryKeyConstraintAndAdjustTypeIfNecessary(EdmProperty property, ColumnStatement columnStatement)
94104
{
95105
// Only handle a single primary key this way.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Text;
2+
3+
namespace SQLite.CodeFirst.Statement.ColumnConstraint
4+
{
5+
internal class DefaultValueConstraint : IColumnConstraint
6+
{
7+
private const string Template = "DEFAULT ({defaultValue})";
8+
9+
public string DefaultValue { get; set; }
10+
11+
public string CreateStatement()
12+
{
13+
var sb = new StringBuilder(Template);
14+
15+
sb.Replace("{defaultValue}", DefaultValue);
16+
17+
return sb.ToString().Trim();
18+
}
19+
}
20+
}

SQLite.CodeFirst/Internal/Utility/ConnectionStringParser.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,20 @@ internal static class ConnectionStringParser
1717

1818
public static string GetDataSource(string connectionString)
1919
{
20-
var path = ExpandDataDirectory(ParseConnectionString(connectionString)[DataSourceToken]);
21-
// remove quotation mark if exists
22-
path = path.Trim('"');
23-
return path;
20+
// If the datasource token does not exists this is a FullUri connection string.
21+
IDictionary<string, string> strings = ParseConnectionString(connectionString);
22+
if (strings.ContainsKey(DataSourceToken))
23+
{
24+
var path = ExpandDataDirectory(ParseConnectionString(connectionString)[DataSourceToken]);
25+
// remove quotation mark if exists
26+
return path.Trim('"');
27+
}
28+
// TODO: Implement FullUri parsing.
29+
if (connectionString.Contains(":memory:"))
30+
{
31+
return ":memory:";
32+
}
33+
throw new NotSupportedException("FullUri format is currently only supported for :memory:.");
2434
}
2535

2636
[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "ToUppercase makes no sense.")]

SQLite.CodeFirst/Internal/Utility/InMemoryAwareFile.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ public static void CreateDirectory(string path)
5252

5353
private static bool IsInMemoryPath(string path)
5454
{
55-
return string.Equals(path, ":memory:", StringComparison.OrdinalIgnoreCase);
55+
// If the path doesn't exists then the datasource was empty as probably a FullUri was specified instead.
56+
return string.IsNullOrEmpty(path)
57+
|| string.Equals(path, ":memory:", StringComparison.OrdinalIgnoreCase);
5658
}
5759
}
5860
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
3+
namespace SQLite.CodeFirst
4+
{
5+
/// <summary>
6+
/// Decorate an column with this attribute to create a "DEFAULT {defaultvalue}".
7+
/// <remarks>
8+
/// https://www.sqlite.org/lang_createtable.html [05.10.2017]
9+
/// </remarks>
10+
/// </summary>
11+
[AttributeUsage(AttributeTargets.Property)]
12+
public sealed class SqlDefaultValueAttribute : Attribute
13+
{
14+
public string DefaultValue { get; set; }
15+
}
16+
}

0 commit comments

Comments
 (0)