Skip to content

Commit a9d6e4d

Browse files
committed
Finished the first implementation of the DB layer, that is now covered with integration tests using the in-memory SQLite database.
1 parent 87ec806 commit a9d6e4d

File tree

8 files changed

+117
-65
lines changed

8 files changed

+117
-65
lines changed

Database/SqlSchema.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,21 @@ public static void Init(SqlKataDatabase db)
99
db.Get().Statement(@"
1010
1111
CREATE TABLE IF NOT EXISTS portfolios (
12-
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
13-
name TEXT NOT NULL,
14-
description TEXT NOT NULL
12+
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
13+
name TEXT NOT NULL,
14+
description TEXT NOT NULL,
15+
currency_code INTEGER NOT NULL
1516
);
1617
1718
CREATE TABLE IF NOT EXISTS portfolio_entries (
18-
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
19-
symbol TEXT NOT NULL,
20-
portfolio_id INTEGER NOT NULL,
21-
FOREIGN KEY(portfolio_id) REFERENCES portfolios(id)
19+
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
20+
symbol TEXT NOT NULL,
21+
portfolio_id INTEGER NOT NULL,
22+
FOREIGN KEY(portfolio_id) REFERENCES portfolios(id)
2223
);
2324
2425
CREATE TABLE IF NOT EXISTS market_orders (
2526
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
26-
currency TEXT NOT NULL,
2727
filled_price INTEGER NOT NULL,
2828
fee INTEGER NOT NULL,
2929
size INTEGER NOT NULL,

Model/Model.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
using System;
22

3-
public record PortfolioEntry(string Symbol, int PortfolioId = -1, int Id = -1);
43

54
namespace Model
65
{
7-
public record MarketOrder(Currency Currency, decimal FilledPrice, decimal Fee, decimal Size,
8-
DateTime Date, bool Buy, int Id = -1, int PortfolioEntryId = -1);
6+
public record Portfolio(string Name, string Description, int CurrencyCode, int Id = -1);
7+
8+
public record PortfolioEntry(string Symbol, int PortfolioId = -1, int Id = -1);
9+
10+
public record MarketOrder(decimal FilledPrice, decimal Fee, decimal Size,
11+
DateTime Date, bool Buy, int Id = -1, int PortfolioEntryId = -1)
12+
{
13+
public virtual bool Equals(MarketOrder? other)
14+
{
15+
// override the Equals operator so Dates are compared in a more intuitive way
16+
if (other == null) return false;
17+
18+
return FilledPrice == other.FilledPrice && Fee == other.Fee && Size == other.Size &&
19+
Date.ToString() == other.Date.ToString() && Buy == other.Buy && Id == other.Id &&
20+
PortfolioEntryId == other.PortfolioEntryId;
21+
}
22+
}
923

10-
public record Portfolio(string Name, string Description, int Id = -1);
1124

1225
public enum Currency
1326
{

Repository/SqlKataMarketOrderRepository.cs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,22 @@ public SqlKataMarketOrderRepository(SqlKataDatabase db) : base(db, "market_order
1212

1313
protected override int _getEntryId(MarketOrder entry) => entry.Id;
1414

15-
public override object ToRow(MarketOrder entry) => new
15+
public override object ToRow(MarketOrder entry)
1616
{
17-
currency = entry.Currency.ToString(),
18-
filled_price = (int) (entry.FilledPrice * 100),
19-
fee = (int) (entry.Fee * 100),
20-
size = (int) (entry.Size * 100),
21-
date = entry.Date.ToBinary(),
22-
buy = ((DateTimeOffset) entry.Date).ToUnixTimeSeconds(),
23-
portfolio_entrY_id = entry.PortfolioEntryId,
24-
};
25-
26-
public override MarketOrder FromRow(dynamic d)
27-
{
28-
bool parsed = Enum.TryParse(d.currency, out Currency currency);
29-
if (!parsed)
17+
return new
3018
{
31-
throw new SqlKataRepositoryException($"Failed to parse currency {d.currency}");
32-
}
33-
34-
return new(currency, d.filled_price, d.fee, d.size, Utils.DateUtils.UnixTimeStampToDateTime(d.date), d.buy > 0,
35-
0, 0);
19+
filled_price = (int) (entry.FilledPrice * 100),
20+
fee = (int) (entry.Fee * 100),
21+
size = (int) (entry.Size * 100),
22+
date = ((DateTimeOffset) entry.Date).ToUnixTimeSeconds(),
23+
buy = entry.Buy ? 1 : 0,
24+
portfolio_entry_id = entry.PortfolioEntryId,
25+
};
3626
}
27+
28+
public override MarketOrder FromRow(dynamic d) =>
29+
new(Decimal.Divide(d.filled_price, 100), Decimal.Divide(d.fee, 100), Decimal.Divide(d.size, 100),
30+
DateTimeOffset.FromUnixTimeSeconds((int) d.date).DateTime.ToLocalTime(), d.buy > 0,
31+
(int) d.id, (int) d.portfolio_entry_id);
3732
}
3833
}

Repository/SqlKataPortfolioRepository.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ public SqlKataPortfolioRepository(SqlKataDatabase db) : base(db, "portfolios")
1414
public override object ToRow(Portfolio entry) => new
1515
{
1616
name = entry.Name,
17-
description = entry.Description
17+
description = entry.Description,
18+
currency_code = entry.CurrencyCode
1819
};
1920

20-
public override Portfolio FromRow(dynamic d) => new((string) d.name, (string) d.description, (int) d.id);
21-
21+
public override Portfolio FromRow(dynamic d) =>
22+
new((string) d.name, (string) d.description, (int) d.currency_code, (int) d.id);
2223
}
2324
}

Tests/Integration/Repository/MarketOrderTest.cs

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,26 @@
55
using Repository;
66
using SqlKata.Compilers;
77
using Xunit;
8-
using Utils;
8+
using Xunit.Abstractions;
99

1010
namespace Tests.Integration.Repository
1111
{
1212
public class SqlKataMarketOrderRepositoryFixture : IDisposable
1313
{
14-
public SqlKataPortfolioRepository PortfolioRepository;
1514
public SqlKataMarketOrderRepository MarketOrderRepository;
1615
private SqliteConnection _dbConnection;
17-
public int DefaultPortfolioId;
16+
public int DefaultPortfolioEntryId;
1817

1918
public SqlKataMarketOrderRepositoryFixture()
2019
{
2120
_dbConnection = new SqliteConnection("Data Source=:memory:");
2221
_dbConnection.Open();
2322
var db = new SqlKataDatabase(_dbConnection, new SqliteCompiler());
24-
this.PortfolioRepository = new(db);
23+
SqlKataPortfolioRepository portfolioRepository = new(db);
24+
SqlKataPortfolioEntryRepository portfolioEntryRepository = new(db);
2525
this.MarketOrderRepository = new(db);
26-
DefaultPortfolioId = PortfolioRepository.Add(new("Foo", "Bar"));
26+
var defaultPortfolioId = portfolioRepository.Add(new("Foo", "Bar", 101));
27+
DefaultPortfolioEntryId = portfolioEntryRepository.Add(new("btc", defaultPortfolioId));
2728
}
2829

2930
public void Dispose()
@@ -35,10 +36,72 @@ public void Dispose()
3536
public class MarketOrderRepositoryTest : IClassFixture<SqlKataMarketOrderRepositoryFixture>
3637
{
3738
private SqlKataMarketOrderRepositoryFixture _marketOrderRepositoryFixture;
39+
private readonly ITestOutputHelper _testOutputHelper;
3840

39-
public MarketOrderRepositoryTest(SqlKataMarketOrderRepositoryFixture marketOrderRepositoryFixture)
41+
public MarketOrderRepositoryTest(SqlKataMarketOrderRepositoryFixture marketOrderRepositoryFixture,
42+
ITestOutputHelper testOutputHelper)
4043
{
4144
this._marketOrderRepositoryFixture = marketOrderRepositoryFixture;
45+
this._testOutputHelper = testOutputHelper;
46+
}
47+
48+
[Fact]
49+
public void Add_ReturnsNonZeroId()
50+
{
51+
// arrange
52+
var marketOrder = new MarketOrder(new Decimal(10000.39), 10, new Decimal(1.1), DateTime.Now, true,
53+
PortfolioEntryId: _marketOrderRepositoryFixture.DefaultPortfolioEntryId);
54+
55+
// act
56+
int id = _marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder);
57+
58+
// assert
59+
Assert.True(id > 0);
60+
}
61+
62+
63+
[Fact]
64+
public void Added_And_Get_AreEqual()
65+
{
66+
// arrange
67+
var marketOrder = new MarketOrder(new Decimal(10000.39), 10, new Decimal(1.1), DateTime.Now, true,
68+
PortfolioEntryId: _marketOrderRepositoryFixture.DefaultPortfolioEntryId);
69+
70+
// act
71+
int id = _marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder);
72+
// update the added order with the generated id
73+
marketOrder = marketOrder with
74+
{
75+
Id = id
76+
};
77+
78+
// assert
79+
Assert.True(id > 0);
80+
var actual = _marketOrderRepositoryFixture.MarketOrderRepository.Get(marketOrder.Id);
81+
Assert.Equal(marketOrder, actual);
82+
}
83+
84+
[Fact]
85+
public void AddUpdate_Updates()
86+
{
87+
// arrange
88+
var marketOrder = new MarketOrder(new Decimal(10000.39), 10, new Decimal(1.1), DateTime.Now, true,
89+
PortfolioEntryId: _marketOrderRepositoryFixture.DefaultPortfolioEntryId);
90+
91+
// act
92+
int id = _marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder);
93+
// update the added order with the generated id and change the filled price, size and buy flag
94+
marketOrder = marketOrder with
95+
{
96+
Id = id,
97+
FilledPrice = 11001,
98+
Size = new decimal(1.3),
99+
Buy = false
100+
};
101+
_marketOrderRepositoryFixture.MarketOrderRepository.Update(marketOrder);
102+
103+
// assert
104+
Assert.Equal(marketOrder, _marketOrderRepositoryFixture.MarketOrderRepository.Get(id));
42105
}
43106
}
44107
}

Tests/Integration/Repository/PortfolioEntryTest.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using Repository;
66
using SqlKata.Compilers;
77
using Xunit;
8-
using Utils;
98

109
namespace Tests.Integration.Repository
1110
{
@@ -23,7 +22,7 @@ public SqlKataPortfolioEntryRepositoryFixture()
2322
var db = new SqlKataDatabase(_dbConnection, new SqliteCompiler());
2423
this.PortfolioRepository = new(db);
2524
this.PortfolioEntryRepository = new(db);
26-
DefaultPortfolioId = PortfolioRepository.Add(new("Foo", "Bar"));
25+
DefaultPortfolioId = PortfolioRepository.Add(new("Foo", "Bar", 101));
2726
}
2827

2928
public void Dispose()

Tests/Integration/Repository/PortfolioTest.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,10 @@ public PortfolioTest(SqlKataPortfolioRepositoryFixture portfolioFixture)
4141
public void Add_ReturnsNonZeroId()
4242
{
4343
// arrange
44-
var portfolio = new Portfolio("My new portfolio", "Lorem ipsum dolor sit amet");
44+
var portfolio = new Portfolio("My new portfolio", "Lorem ipsum dolor sit amet", 101);
4545

4646
// act
47-
int id = _portfolioFixture.PortfolioRepository.Add(new Portfolio("My new portfolio",
48-
"Lorem ipsum dolor sit amet"));
47+
int id = _portfolioFixture.PortfolioRepository.Add(portfolio);
4948

5049
// assert
5150
Assert.True(id > 0);
@@ -55,7 +54,7 @@ public void Add_ReturnsNonZeroId()
5554
public void Added_And_Get_AreEqual()
5655
{
5756
// arrange
58-
var portfolio = new Portfolio("My new portfolio", "Lorem ipsum dolor sit amet");
57+
var portfolio = new Portfolio("My new portfolio", "Lorem ipsum dolor sit amet", 101);
5958

6059
// act
6160
int id = _portfolioFixture.PortfolioRepository.Add(portfolio);
@@ -74,7 +73,7 @@ public void Added_And_Get_AreEqual()
7473
public void AddUpdate_Updates()
7574
{
7675
// arrange
77-
var template = new Portfolio("My new portfolio", "Lorem ipsum dolor sit amet");
76+
var template = new Portfolio("My new portfolio", "Lorem ipsum dolor sit amet", 101);
7877

7978
// act
8079
int firstId = _portfolioFixture.PortfolioRepository.Add(template);

Utils/DateUtils.cs

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)