Skip to content

Commit

Permalink
Merge pull request #62 from marcominerva/develop
Browse files Browse the repository at this point in the history
Add support for SQLite
  • Loading branch information
marcominerva authored Feb 13, 2024
2 parents 427a9b0 + 415547f commit 7ac33fe
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 3 deletions.
6 changes: 6 additions & 0 deletions DatabaseGpt.sln
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseGpt.Npgsql", "src\D
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseGpt.Web", "samples\DatabaseGpt.Web\DatabaseGpt.Web.csproj", "{C2769772-57CA-41EB-86EB-54DA07F560AE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseGpt.Sqlite", "src\DatabaseGpt.Sqlite\DatabaseGpt.Sqlite.csproj", "{6676EE8F-7B09-43CB-832E-AC6E432D7D29}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -53,6 +55,10 @@ Global
{C2769772-57CA-41EB-86EB-54DA07F560AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2769772-57CA-41EB-86EB-54DA07F560AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2769772-57CA-41EB-86EB-54DA07F560AE}.Release|Any CPU.Build.0 = Release|Any CPU
{6676EE8F-7B09-43CB-832E-AC6E432D7D29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6676EE8F-7B09-43CB-832E-AC6E432D7D29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6676EE8F-7B09-43CB-832E-AC6E432D7D29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6676EE8F-7B09-43CB-832E-AC6E432D7D29}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Thanks to [Adam Buckley](https://github.com/happyadam73/tsql-chatgpt) for the [o

### Usage

Currently, SQL Server and PostgreSQL databases are supported.
Currently, SQL Server, PostgreSQL and SQLite databases are supported.

#### Using DatabaseGpt in your project

Expand All @@ -22,6 +22,7 @@ Database|Project to include
-|-
SQL Server|src/DatabaseGpt.SqlServer/DatabaseGpt.SqlServer.csproj
PostgreSQL|src/DatabaseGpt.Npgsql/DatabaseGpt.Npgsql.csproj
SQLite|src/DatabaseGpt.Sqlite/DatabaseGpt.Sqlite.csproj

After referencing the proper projects, you can easily initialize **DatabaseGpt** at the startup of your application.

Expand All @@ -37,6 +38,10 @@ builder.Services.AddDatabaseGpt(database =>
// For PostgreSQL.
//database.UseConfiguration(context.Configuration)
// .UseNpgsql(context.Configuration.GetConnectionString("NpgsqlConnection"));
// For SQLite.
//database.UseConfiguration(context.Configuration)
// .UseSqlite(context.Configuration.GetConnectionString("SqliteConnection"));
},
chatGpt =>
{
Expand All @@ -50,6 +55,7 @@ You need to set the required values in the **appsettings.json** file:
"ConnectionStrings": {
"SqlConnection": "" // The SQL Server connection string
//"NpgsqlConnection": "" // The PostgreSQL connection string
//"SqliteConnection": "" // The SQLite connection string
},
"ChatGPT": {
"Provider": "OpenAI", // Optional. Allowed values: OpenAI (default) or Azure
Expand Down
4 changes: 4 additions & 0 deletions samples/DatabaseGpt.Web/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
// For PostgreSQL.
//database.UseConfiguration(context.Configuration)
// .UseNpgsql(context.Configuration.GetConnectionString("NpgsqlConnection"));
// For SQLite.
//database.UseConfiguration(context.Configuration)
// .UseSqlite(context.Configuration.GetConnectionString("SqliteConnection"));
},
chatGpt =>
{
Expand Down
1 change: 1 addition & 0 deletions samples/DatabaseGptConsole/DatabaseGptConsole.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

<ItemGroup>
<ProjectReference Include="..\..\src\DatabaseGpt.Npgsql\DatabaseGpt.Npgsql.csproj" />
<ProjectReference Include="..\..\src\DatabaseGpt.SQLite\DatabaseGpt.Sqlite.csproj" />
<ProjectReference Include="..\..\src\DatabaseGpt.SqlServer\DatabaseGpt.SqlServer.csproj" />
<ProjectReference Include="..\..\src\DatabaseGpt\DatabaseGpt.csproj" />
</ItemGroup>
Expand Down
4 changes: 4 additions & 0 deletions samples/DatabaseGptConsole/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ static void ConfigureServices(HostBuilderContext context, IServiceCollection ser
// For PostgreSQL.
//database.UseConfiguration(context.Configuration)
// .UseNpgsql(context.Configuration.GetConnectionString("NpgsqlConnection"));
// For SQLite.
//database.UseConfiguration(context.Configuration)
// .UseSqlite(context.Configuration.GetConnectionString("SqliteConnection"));
},
chatGpt =>
{
Expand Down
7 changes: 5 additions & 2 deletions src/DatabaseGpt.Npgsql/NpgsqlDatabaseGptProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,13 @@ public async Task<string> GetCreateTablesScriptAsync(IEnumerable<string> tables,
CASE WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN 'MAX' ELSE CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR(10)) END || ')','') || ' ' ||
CASE WHEN IS_NULLABLE = 'YES' THEN 'NULL' ELSE 'NOT NULL' END
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND COLUMN_NAME NOT IN (SELECT UNNEST(@excludedColumns));
WHERE TABLE_SCHEMA = @schema
AND TABLE_NAME = @table
AND COLUMN_NAME NOT IN (SELECT UNNEST(@excludedColumns))
AND TABLE_SCHEMA || '.' || TABLE_NAME || '.' || COLUMN_NAME NOT IN (SELECT UNNEST(@excludedColumns));
""";

var columns = await connection.QueryAsync<string>(query, new { schema = table.Schema, table = table.Name, ExcludedColumns = excludedColumns });
var columns = await connection.QueryAsync<string>(query, new { schema = table.Schema, table = table.Name, excludedColumns });
result.AppendLine($"CREATE TABLE [{table.Schema}].[{table.Name}] ({string.Join(", ", columns)});");
}

Expand Down
18 changes: 18 additions & 0 deletions src/DatabaseGpt.Sqlite/DatabaseGpt.Sqlite.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.28" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\DatabaseGpt.Abstractions\DatabaseGpt.Abstractions.csproj" />
</ItemGroup>

</Project>
15 changes: 15 additions & 0 deletions src/DatabaseGpt.Sqlite/SqliteDatabaseGptExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using DatabaseGpt.Abstractions;
using DatabaseGpt.Sqlite;

namespace DatabaseGpt;

public static class SqliteDatabaseGptExtensions
{
public static void UseSqlite(this IDatabaseGptSettings databaseGptSettings, string? connectionString)
{
databaseGptSettings.SetDatabaseGptProviderFactory(() => new SqliteDatabaseGptProvider(new()
{
ConnectionString = connectionString
}));
}
}
116 changes: 116 additions & 0 deletions src/DatabaseGpt.Sqlite/SqliteDatabaseGptProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using System.Data;
using System.Data.Common;
using System.Text;
using Dapper;
using DatabaseGpt.Abstractions;
using DatabaseGpt.Abstractions.Exceptions;
using Microsoft.Data.Sqlite;

namespace DatabaseGpt.Sqlite;

public class SqliteDatabaseGptProvider(SqliteDatabaseGptProviderConfiguration settings) : IDatabaseGptProvider
{
private readonly SqliteConnection connection = new(settings.ConnectionString);

private bool disposedValue;

public string Name => "SQLite";

public string Language => "SQLite";

public async Task<IEnumerable<string>> GetTablesAsync(IEnumerable<string> includedTables, IEnumerable<string> excludedTables, CancellationToken cancellationToken = default)
{
ThrowIfDisposed();

var tables = await connection.QueryAsync<string>("""
SELECT TBL_NAME AS Tables
FROM sqlite_schema
WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'
""");

if (includedTables?.Any() ?? false)
{
tables = tables.Where(t => includedTables.Contains(t, StringComparer.InvariantCultureIgnoreCase));
}
else if (excludedTables?.Any() ?? false)
{
tables = tables.Where(t => !excludedTables.Contains(t, StringComparer.InvariantCultureIgnoreCase));
}

return tables;
}

public async Task<string> GetCreateTablesScriptAsync(IEnumerable<string> tables, IEnumerable<string> excludedColumns, CancellationToken cancellationToken = default)
{
ThrowIfDisposed();

var result = new StringBuilder();

foreach (var table in tables)
{
var query = $"""
SELECT '[' || NAME || '] ' ||
UPPER(TYPE) || ' ' ||
CASE WHEN [NOTNULL] = 0 THEN 'NULL' ELSE 'NOT NULL' END
FROM PRAGMA_TABLE_INFO(@table)
WHERE NAME NOT IN (@excludedColumns)
AND @table || '.' || NAME NOT IN (@excludedColumns);
""";

var columns = await connection.QueryAsync<string>(query, new { table, excludedColumns });
result.AppendLine($"CREATE TABLE [{table}] ({string.Join(", ", columns)});");
}

return result.ToString();
}

public Task<string?> GetQueryHintsAsync(CancellationToken cancellationToken = default)
{
ThrowIfDisposed();

return Task.FromResult<string?>(null);
}

public Task<string> NormalizeQueryAsync(string query, CancellationToken cancellationToken = default)
{
ThrowIfDisposed();

return Task.FromResult(query);
}

public async Task<DbDataReader> ExecuteQueryAsync(string query, CancellationToken cancellationToken = default)
{
ThrowIfDisposed();

try
{
return await connection.ExecuteReaderAsync(query);
}
catch (SqliteException ex)
{
throw new DatabaseGptException("An error occurred while executing the query. See the inner exception for details.", ex);
}
}

protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
connection.Dispose();
}

disposedValue = true;
}
}

public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}

private void ThrowIfDisposed()
=> ObjectDisposedException.ThrowIf(disposedValue, this);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace DatabaseGpt.Sqlite;

public class SqliteDatabaseGptProviderConfiguration
{
public string? ConnectionString { get; set; }
}

0 comments on commit 7ac33fe

Please sign in to comment.