Skip to content

Commit 674ea57

Browse files
Implements DbfDbConnection. (#258)
* Implements DbfDbConnection. Thanks to @TonyValenti for the contributions. * Simplifies QueryParser and adds unit tests * Simplifies DbfDbCommand.ExecuteDbDataReader * Code tidy * Updates README.md
1 parent c4dda7f commit 674ea57

13 files changed

Lines changed: 1035 additions & 0 deletions

DbfDataReader.sln

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{02A96866-FEA4-483E-A6FD-CB8660F51FD3}"
77
EndProject
88
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8C65E3B7-6E4F-470A-9422-7B273FE6EBF6}"
9+
ProjectSection(SolutionItems) = preProject
10+
README.md = README.md
11+
EndProjectSection
912
EndProject
1013
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{6E1D36E2-2D05-4ACF-80B7-1AFB75A20839}"
1114
EndProject

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,48 @@ using (var dbfDataReader = new DbfDataReader(dbfPath, options))
105105
}
106106
```
107107

108+
There is also an implementation of DbConnection so you can query a folder of files e.g.
109+
110+
```csharp
111+
var dbConnection = new DbfDbConnection(string.Empty, string.Empty);
112+
dbConnection.ConnectionString = $"Folder=./test/fixtures;SkipDeletedRecords=false";
113+
dbConnection.Open();
114+
115+
var dbCommand = dbConnection.CreateCommand();
116+
dbCommand.CommandText = "select * from dbase_03.dbf;";
117+
118+
var reader = await dbCommand.ExecuteReaderAsync();
119+
while (await reader.ReadAsync())
120+
{
121+
var valueCol1 = reader.GetString(0);
122+
var valueCol11 = reader.GetDecimal(10);
123+
}
124+
```
125+
126+
The connection string supports the options available in `DbfDataReaderOptions`:
127+
128+
- Folder - the folder containing the files to be queried
129+
- required
130+
- string
131+
- Encoding - the encoding to be used
132+
- optional
133+
- string
134+
- valid Encoding name from [Encoding](https://learn.microsoft.com/en-us/dotnet/api/System.Text.Encoding)
135+
- ReadFloatsAsDecimals - whether to read floats as decimals
136+
- optional
137+
- boolean
138+
- defaults to false
139+
- SkipDeletedRecords - whether to skip deleted records
140+
- optional
141+
- boolean
142+
- defaults to true
143+
- StringTrimming - string timming behaviour
144+
- optional
145+
- string
146+
- defaults to 'None'
147+
- one of 'None', 'Trim', 'TrimStart', 'TrimEnd'
148+
149+
108150
Used by
109151

110152
- DbfBulkCopy

src/DbfDataReader/DbfDataReader.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
<MinVerTagPrefix>v</MinVerTagPrefix>
2121
</PropertyGroup>
2222

23+
<ItemGroup>
24+
<InternalsVisibleTo Include="DbfDataReader.Tests" />
25+
</ItemGroup>
26+
2327
<ItemGroup>
2428
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.103" PrivateAssets="All" />
2529
<PackageReference Include="MinVer" Version="7.0.0" PrivateAssets="All" />

src/DbfDataReader/DbfDbCommand.cs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using System.Data;
3+
using System.Data.Common;
4+
using System.IO;
5+
6+
namespace DbfDataReader
7+
{
8+
public class DbfDbCommand : DbCommand
9+
{
10+
public override string CommandText { get; set; }
11+
public override int CommandTimeout { get; set; }
12+
public override CommandType CommandType { get; set; }
13+
public override bool DesignTimeVisible { get; set; }
14+
public override UpdateRowSource UpdatedRowSource { get; set; }
15+
protected override DbConnection DbConnection { get; set; }
16+
protected override DbParameterCollection DbParameterCollection { get; }
17+
protected override DbTransaction DbTransaction { get; set; }
18+
19+
public override void Cancel()
20+
{
21+
throw new NotImplementedException();
22+
}
23+
24+
public override int ExecuteNonQuery()
25+
{
26+
throw new NotImplementedException();
27+
}
28+
29+
public override object ExecuteScalar()
30+
{
31+
throw new NotImplementedException();
32+
}
33+
34+
public override void Prepare()
35+
{
36+
throw new NotImplementedException();
37+
}
38+
39+
protected override DbParameter CreateDbParameter()
40+
{
41+
throw new NotImplementedException();
42+
}
43+
44+
protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
45+
{
46+
var dbfDbConnection = Connection as DbfDbConnection;
47+
if (dbfDbConnection is null)
48+
{
49+
throw new InvalidOperationException($"{nameof(DbfDbConnection)} is not available");
50+
}
51+
52+
var folder = dbfDbConnection.Database;
53+
if (string.IsNullOrWhiteSpace(folder))
54+
{
55+
throw new DirectoryNotFoundException("No folder was specified for the Dbf files.");
56+
}
57+
58+
if (!Directory.Exists(folder))
59+
{
60+
throw new DirectoryNotFoundException($"The specified folder does not exist: {folder}");
61+
}
62+
63+
var fileName = QueryParser.Parse(CommandText);
64+
var filePath = Path.Combine(folder, $"{fileName}");
65+
if (!File.Exists(filePath))
66+
{
67+
throw new FileNotFoundException(filePath);
68+
}
69+
70+
var options = dbfDbConnection.Options;
71+
return new DbfDataReader(filePath, options);
72+
}
73+
}
74+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System;
2+
using System.Data;
3+
using System.Data.Common;
4+
using System.IO;
5+
6+
namespace DbfDataReader
7+
{
8+
public class DbfDbConnection : DbConnection
9+
{
10+
private string _database = string.Empty;
11+
private ConnectionState _state = ConnectionState.Closed;
12+
13+
public DbfDbConnection(string dataSource, string serverVersion)
14+
{
15+
DataSource = dataSource;
16+
ServerVersion = serverVersion;
17+
}
18+
19+
public DbfDataReaderOptions Options { get; private set; } = new DbfDataReaderOptions();
20+
21+
public override string ConnectionString { get; set; }
22+
public override string DataSource { get; }
23+
public override string ServerVersion { get; }
24+
25+
public override ConnectionState State => _state;
26+
public override string Database => _database;
27+
28+
public override void ChangeDatabase(string databaseName)
29+
{
30+
if (!Directory.Exists(databaseName))
31+
{
32+
throw new DirectoryNotFoundException(databaseName);
33+
}
34+
35+
_database = databaseName;
36+
}
37+
38+
public override void Close()
39+
{
40+
_state = ConnectionState.Closed;
41+
}
42+
43+
public override void Open()
44+
{
45+
var builder = new DbfDbConnectionStringBuilder(ConnectionString);
46+
47+
ChangeDatabase(builder.Folder);
48+
49+
var options = new DbfDataReaderOptions();
50+
51+
if (builder.Encoding is var encoding)
52+
{
53+
options.Encoding = encoding;
54+
}
55+
56+
if (builder.ReadFloatsAsDecimals is var readFloatsAsDecimals)
57+
{
58+
options.ReadFloatsAsDecimals = readFloatsAsDecimals;
59+
}
60+
61+
if (builder.SkipDeletedRecords is var skipDeletedRecords)
62+
{
63+
options.SkipDeletedRecords = skipDeletedRecords;
64+
}
65+
66+
if (builder.StringTrimming is var stringTrimming)
67+
{
68+
options.StringTrimming = stringTrimming;
69+
}
70+
71+
Options = options;
72+
_state = ConnectionState.Open;
73+
}
74+
75+
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
76+
{
77+
throw new NotImplementedException();
78+
}
79+
80+
protected override DbCommand CreateDbCommand()
81+
{
82+
return new DbfDbCommand
83+
{
84+
Connection = this,
85+
};
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)