Skip to content

Commit

Permalink
Merge pull request #6 from tvandinther/xmldoc
Browse files Browse the repository at this point in the history
Add XML Documentation to public members
  • Loading branch information
tvandinther authored Oct 22, 2023
2 parents 4e5a02c + c91bce8 commit 05cc60c
Show file tree
Hide file tree
Showing 18 changed files with 275 additions and 115 deletions.
20 changes: 13 additions & 7 deletions Demo/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Libsql.Client;

var dbClient = DatabaseClient.Create();
var dbClient = DatabaseClient.Create(opts => {
opts.Url = ":memory:";
});

var rs = await dbClient.Execute("CREATE TABLE IF NOT EXISTS `users` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `height` REAL, `data` BLOB)");

Expand All @@ -12,16 +14,20 @@
Console.WriteLine(string.Join("\n", rs2.Rows.Select(row => string.Join(", ", row.Select(x => x.ToString())))));
Console.WriteLine(string.Join("\n", rs2.Rows.Select(row => string.Join(", ", row.Select(x => x.ToString())))));

var user = ToUser(rs2.Rows.First().ToArray());
var user = ToUser(rs2.Rows.First());
Console.WriteLine(user);

User ToUser(Value[] row)
var users = rs2.Rows.Select(ToUser);

User ToUser(IEnumerable<Value> row)
{
var rowArray = row.ToArray();

if (
row[0] is Integer { Value: var id } &&
row[1] is Text { Value: var name } &&
row[2] is Real { Value: var height } &&
row[3] is Blob { Value: var data })
rowArray[0] is Integer { Value: var id } &&
rowArray[1] is Text { Value: var name } &&
rowArray[2] is Real { Value: var height } &&
rowArray[3] is Blob { Value: var data })
{
return new User(id, name, height, data);
}
Expand Down
29 changes: 12 additions & 17 deletions Libsql.Client/DatabaseClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,26 @@

namespace Libsql.Client
{
/// <summary>
/// Provides a static method to create an instance of <see cref="IDatabaseClient"/>.
/// </summary>
public static class DatabaseClient
{
/// <summary>
/// Creates a new instance of the <see cref="IDatabaseClient"/> interface.
/// </summary>
/// <param name="configure">An optional action to configure the <see cref="DatabaseClientOptions"/>.</param>
/// <returns>A new instance of the <see cref="IDatabaseClient"/> interface.</returns>
/// <remarks>A client constitutes a connection to the database.</remarks>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="configure"/> is null.</exception>
/// <exception cref="LibsqlException">Thrown when the database fails to open and/or connect.</exception>
public static IDatabaseClient Create(Action<DatabaseClientOptions> configure = default)
{
var options = DatabaseClientOptions.Default;
configure?.Invoke(options);
if (options.Url is null) throw new ArgumentNullException(nameof(options.Url));

return new DatabaseWrapper(options.Url);

// if (IsInMemory(options.Url))
// {
// return new DatabaseWrapper(":memory:");
// }
//
// var uri = new Uri(options.Url);
// return uri.Scheme switch
// {
// "http" or "https" => throw new ArgumentException($"{uri.Scheme}:// is not yet supported"),
// "ws" or "wss" => throw new ArgumentException($"{uri.Scheme}:// is not yet supported"),
// "file" => throw new ArgumentException(options.Url),
// _ => throw new ArgumentException("Invalid scheme")
// };
return new DatabaseWrapper(options);
}

private static bool IsInMemory(string url) => url is "" || url is ":memory:";
}
}
24 changes: 16 additions & 8 deletions Libsql.Client/DatabaseClientOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace Libsql.Client
{
/// <summary>
/// Represents the options for configuring <see cref="IDatabaseClient"/>.
/// </summary>
public class DatabaseClientOptions
{
private DatabaseClientOptions(string url, string authToken = null, bool useHttps = false)
Expand All @@ -10,16 +13,21 @@ private DatabaseClientOptions(string url, string authToken = null, bool useHttps
}

internal static DatabaseClientOptions Default => new DatabaseClientOptions("");

/// <summary>
/// Gets or sets the URL of the database server.
/// </summary>
/// <remarks>Default: <c>""</c>. <c>""</c> or <c>":memory:"</c> will create an in-memory database.</remarks>
public string Url { get; set; }

/// <summary>
/// Gets or sets the authentication token used to connect to the database.
/// </summary>
public string AuthToken { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to use HTTPS protocol for database connections.
/// </summary>
public bool UseHttps { get; set; }

public void Deconstruct(out string url, out string token, out bool useHttps)
{
url = Url;
token = AuthToken;
useHttps = UseHttps;
}
}
}

65 changes: 43 additions & 22 deletions Libsql.Client/DatabaseWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,33 @@ internal class DatabaseWrapper : IDatabaseClient, IDisposable
private libsql_database_t _db;
private libsql_connection_t _connection;

public unsafe DatabaseWrapper(string url)
public unsafe DatabaseWrapper(DatabaseClientOptions options)
{
Debug.Assert(url != null, "url is null");
Debug.Assert(options.Url != null, "url is null");

if (!(options.Url == "" || options.Url == ":memory:"))
{
try
{
var uri = new Uri(options.Url);
switch (uri.Scheme)
{
case "http":
case "https":
case "ws":
case "wss":
throw new LibsqlException($"{uri.Scheme}:// is not yet supported");
}
}
catch (UriFormatException) { }
}

// C# empty strings have null pointers, so we need to give the url some meat.
var url = options.Url is "" ? "\0" : options.Url;

var error = new Error();
int exitCode;

// C# empty strings have null pointers, so we need to give the urln it some meat.
if (url is "") url = "\0";

fixed (libsql_database_t* dbPtr = &_db)
{
fixed (byte* urlPtr = Encoding.UTF8.GetBytes(url))
Expand All @@ -46,31 +64,34 @@ private unsafe void Connect()
error.ThrowIfNonZero(exitCode, "Failed to connect to database");
}

public unsafe Task<ResultSet> Execute(string sql)
public async Task<IResultSet> Execute(string sql)
{
return Task.Run(() =>
return await Task.Run(() =>
{
var error = new Error();
var rows = new libsql_rows_t();
int exitCode;

fixed (byte* sqlPtr = Encoding.UTF8.GetBytes(sql))
unsafe
{
exitCode = Bindings.libsql_execute(_connection, sqlPtr, &rows, &error.Ptr);
}
var error = new Error();
var rows = new libsql_rows_t();
int exitCode;

fixed (byte* sqlPtr = Encoding.UTF8.GetBytes(sql))
{
exitCode = Bindings.libsql_execute(_connection, sqlPtr, &rows, &error.Ptr);
}

error.ThrowIfNonZero(exitCode, "Failed to execute query");
error.ThrowIfNonZero(exitCode, "Failed to execute query");

return new ResultSet(
0,
0,
rows.GetColumnNames(),
new Rows(rows)
);
return new ResultSet(
0,
0,
rows.GetColumnNames(),
new Rows(rows)
);
}
});
}

public Task<ResultSet> Execute(string sql, params object[] args)
public Task<IResultSet> Execute(string sql, params object[] args)
{
throw new NotImplementedException();
}
Expand Down
2 changes: 1 addition & 1 deletion Libsql.Client/Error.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public unsafe void ThrowIfNonZero(int exitCode, string message)

var text = Marshal.PtrToStringAuto((IntPtr)Ptr);

throw new Exception($"{message}: {text}");
throw new LibsqlException($"{message}: {text}");
}
}
}
21 changes: 19 additions & 2 deletions Libsql.Client/IDatabaseClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,26 @@

namespace Libsql.Client
{
/// <summary>
/// Interface for a Libsql database client.
/// </summary>
public interface IDatabaseClient
{
Task<ResultSet> Execute(string sql);
Task<ResultSet> Execute(string sql, params object[] args);
/// <summary>
/// Executes the given SQL query and returns the result set.
/// </summary>
/// <param name="sql">The SQL query to execute.</param>
/// <returns>The result set returned by the query.</returns>
/// <exception cref="LibsqlException">Thrown when the query fails to execute.</exception>
Task<IResultSet> Execute(string sql);

/// <summary>
/// Executes the given SQL query with the specified parameters and returns the result set.
/// </summary>
/// <param name="sql">The SQL query to execute.</param>
/// <param name="args">The parameters to use in the query.</param>
/// <returns>The result set returned by the query.</returns>
/// <exception cref="LibsqlException">Thrown when the query fails to execute.</exception>
Task<IResultSet> Execute(string sql, params object[] args);
}
}
34 changes: 34 additions & 0 deletions Libsql.Client/IResultSet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Collections.Generic;

namespace Libsql.Client
{
/// <summary>
/// Represents the result set of a SQL query.
/// </summary>
public interface IResultSet
{
/// <summary>
/// The ID of the last row inserted by the connection.
/// </summary>
/// <returns>The ID of the last row inserted.</returns>
long LastInsertRowId { get; }

/// <summary>
/// The number of rows affected by the last query executed by the connection.
/// </summary>
/// <returns>The number of rows affected.</returns>
ulong RowsAffected { get; }

/// <summary>
/// The names of the columns in the result set.
/// </summary>
/// <returns>An enumerable of column names.</returns>
IEnumerable<string> Columns { get; }

/// <summary>
/// The rows in the result set.
/// </summary>
/// <returns>An enumerable of enumerable rows. Rows are enumerated by column.</returns>
IEnumerable<IEnumerable<Value>> Rows { get; }
}
}
9 changes: 1 addition & 8 deletions Libsql.Client/Libsql.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Title>Libsql.Client</Title>
<Authors>Tom van Dinther</Authors>
<Description>A client library for Libsql</Description>
<PackageVersion>0.2.0</PackageVersion>
<PackageVersion>0.2.1</PackageVersion>
<Copyright>Copyright (c) Tom van Dinther 2023</Copyright>
<PackageProjectUrl>https://github.com/tvandinther/libsql-client-dotnet</PackageProjectUrl>
<PackageLicense>https://raw.githubusercontent.com/tvandinther/libsql-client-dotnet/master/LICENSE</PackageLicense>
Expand Down Expand Up @@ -50,13 +50,6 @@
<Compile Include="..\rust-bindings\csharp-bindings\bindings\Libsql.g.cs" Link="Libsql.g.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="csbindgen" Version="1.8.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>$(AssemblyName).Tests</_Parameter1>
Expand Down
24 changes: 24 additions & 0 deletions Libsql.Client/LibsqlException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace Libsql.Client
{
/// <summary>
/// Represents an exception that is thrown when an error occurs in the Libsql.Client library.
/// </summary>
public class LibsqlException : ApplicationException
{
internal LibsqlException()
{
}

internal LibsqlException(string message)
: base(message)
{
}

internal LibsqlException(string message, Exception inner)
: base(message, inner)
{
}
}
}
38 changes: 6 additions & 32 deletions Libsql.Client/ResultSet.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;

namespace Libsql.Client
{
public class ResultSet : IEquatable<ResultSet>
internal class ResultSet : IResultSet
{
public long LastInsertRowId { get; }

public ulong RowsAffected { get; }

public IEnumerable<string> Columns { get; }

public IEnumerable<IEnumerable<Value>> Rows { get; }

public ResultSet(long lastInsertRowId, ulong rowsAffected, IEnumerable<string> columns, IEnumerable<IEnumerable<Value>> rows)
Expand All @@ -17,33 +19,5 @@ public ResultSet(long lastInsertRowId, ulong rowsAffected, IEnumerable<string> c
Columns = columns;
Rows = rows;
}

public bool Equals(ResultSet other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return LastInsertRowId == other.LastInsertRowId && RowsAffected == other.RowsAffected &&
Equals(Columns, other.Columns) && Equals(Rows, other.Rows);
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ResultSet)obj);
}

public override int GetHashCode()
{
unchecked
{
var hashCode = LastInsertRowId.GetHashCode();
hashCode = (hashCode * 397) ^ RowsAffected.GetHashCode();
hashCode = (hashCode * 397) ^ (Columns != null ? Columns.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (Rows != null ? Rows.GetHashCode() : 0);
return hashCode;
}
}
}
}
}
Loading

0 comments on commit 05cc60c

Please sign in to comment.