Skip to content

Commit

Permalink
Imported sources
Browse files Browse the repository at this point in the history
  • Loading branch information
maroontress-tomohisa committed Apr 3, 2024
0 parents commit 18ca90a
Show file tree
Hide file tree
Showing 80 changed files with 3,945 additions and 0 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: .NET 6 and 7 CI

on: [push]

jobs:
build:

runs-on: ubuntu-latest
strategy:
matrix:
dotnet: [ '6.0.x', '7.0.x' ]
steps:
- uses: actions/checkout@v3
- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
3.1.x
${{ matrix.dotnet }}
- name: Check BOM
run: |
dotnet tool install -g BomSweeper.GlobalTool
$HOME/.dotnet/tools/bomsweeper '**/*.cs' '**/*.csproj' '**/*.sln'
- name: Build
run: dotnet build --configuration Release
- name: Install
run: dotnet tool install -g dotnet-reportgenerator-globaltool
- name: Test
run: |
rm -rf MsTestResults
dotnet test --configuration Release --no-build --logger "console;verbosity=detailed" --collect:"XPlat Code Coverage" --results-directory MsTestResults
reportgenerator -reports:MsTestResults/*/coverage.cobertura.xml -targetdir:Coverlet-html
- name: Archive artifacts (code coverage)
uses: actions/upload-artifact@v3
with:
name: code-coverage-report-${{ matrix.dotnet }}
path: Coverlet-html
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/.vs/
/*/bin/
/*/obj/
/SqlBind/dcx/
/SqlBind.Test/TestResults/
/Coverlet-Html/
/SqlBind/html/
/SqlBind/Properties/
/SqlBind.Test/Properties/
*.csproj.user
23 changes: 23 additions & 0 deletions COPYRIGHT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Copyright (c) 2023 Maroontress Fast Software. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS *AS IS* AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
304 changes: 304 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
# SqlBind

SqlBind.CSharp is a C# class library that is a wrapper for SQLite.

## How to create a table and insert rows

Let's consider creating the Actors table as follows:

> ### _Actors_
>
> | <u>id</u> | name |
> | ---: | :--- |
> | 1 | Chloë Grace Moretz |
> | 2 | Gary Carr |
> | 3 | Jack Reynor |
Create the following class to represent this table:

```csharp
[Table("Actors")]
public record class Actor(
[Column("id")][PrimaryKey][AutoIncrement] long Id,
[Column("name")] string Name)
{
}
```

Each parameter in the constructor of the `Actor` class corresponds to each column in the Actors table in the same order. The type of each parameter must be either `long` or `string`.

Note that you can implement the `Actor` class without a `record` class. However, the parameter names of the constructor must start with an _uppercase_ letter if you create a regular one according to the naming conventions of the `record` class. This is inconsistent with general naming conventions. Therefore, we recommend that you use `record` classes.

The following code from the `Example` class uses the `Actor` class to create the Actors table and add three rows of data to the table:

```csharp
public sealed class Example
{
private TransactionKit Kit { get; } = new TransactionKit(
"example.db",
m => Console.WriteLine(m()));

public void CreateTableAndInsertRows()
{
Kit.Execute(q =>
{
q.NewTables(typeof(Actor));
q.Insert(new Actor(0, "Chloë Grace Moretz"));
q.Insert(new Actor(0, "Gary Carr"));
q.Insert(new Actor(0, "Jack Reynor"));
});
}
...
```

The `Kit` property has the `TransactionKit` instance, which uses the `example.db` file as a database backend and writes log messages to the console. The `Execute` method executes the queries that the lambda expression of its parameter performs atomically (as a single transaction).

Note that calling the `Insert(object)` method with the `Actor` instance ignores its `Id` property, which is specified with the first parameter of the constructor of the `Actor` class, because it is qualified with the `AutoIncrement` attribute.

The log messages that the `CreateTableAndInsertRows()` method prints to the console are as follows:

```plaintext
DROP TABLE IF EXISTS Actors
CREATE TABLE Actors (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)
INSERT INTO Actors (name) VALUES ($name)
($name, Chloë Grace Moretz)
INSERT INTO Actors (name) VALUES ($name)
($name, Gary Carr)
INSERT INTO Actors (name) VALUES ($name)
($name, Jack Reynor)
```

The non-indented lines are actual SQL statements that were automatically generated and executed.

## How to select a table and get rows

Then run the `SelectAllRows()` method as follows:

```csharp
public sealed class Example
{
...
public void SelectAllRows()
{
Kit.Execute(q =>
{
var all = q.SelectAll<Actor>();
foreach (var i in all)
{
Console.WriteLine(i);
}
});
}
...
```

The `SelectAllRows()` method outputs:

```plaintext
SELECT id, name FROM Actors
Actor { Id = 1, Name = Chloë Grace Moretz }
Actor { Id = 2, Name = Gary Carr }
Actor { Id = 3, Name = Jack Reynor }
```

The first line is the log message that the `TransactionKit` instance prints. The `SelectAll<T>()` method generates this statement.

The next three lines are the messages that the `WriteLine(object)` method outputs within the `foreach` block.

## Inner join with two or more tables

Consider the following Titles table:

> ### _Titles_
>
> | id | name |
> | ---: | :--- |
> | 1 | Peripheral |

And the following Casts table:

> ### _Casts_
>
> | id | titleId | actorId | role |
> | ---: | ---: | ---: | :--- |
> | 1 | 1 | 1 | Flynne Fisher |
> | 2 | 1 | 2 | Wilf Netherton |
> | 3 | 1 | 3 | Burton Fisher |

The classes that correspond to these tables are:

```csharp
[Table("Titles")]
public record class Title(
[Column("id")][PrimaryKey][AutoIncrement] long Id,
[Column("name")] string Name)
{
}

[Table("Casts")]
public record class Cast(
[Column("id")][PrimaryKey][AutoIncrement] long Id,
[Column("titleId")] long TitleId,
[Column("actorId")] long ActorId,
[Column("role")] string Role)
{
}
```

The following code creates the tables and inserts the rows:

```csharp
public sealed class Example
{
...
public void CreateTables()
{
Kit.Execute(q =>
{
q.NewTables(typeof(Title));
q.NewTables(typeof(Actor));
q.NewTables(typeof(Cast));
var titleId = q.InsertAndGetRowId(new Title(0, "Peripheral"));
var allCasts = new (string Name, string Role)[]
{
("Chloë Grace Moretz", "Flynne Fisher"),
("Gary Carr", "Wilf Netherton"),
("Jack Reynor", "Burton Fisher"),
};
foreach (var (name, role) in allCasts)
{
var actorId = q.InsertAndGetRowId(new Actor(0, name));
q.Insert(new Cast(0, titleId, actorId, role));
}
});
}
...
```

The log messages that the `CreateTables()` method prints to the console are as follows:

```
DROP TABLE IF EXISTS Titles
CREATE TABLE Titles (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)
DROP TABLE IF EXISTS Actors
CREATE TABLE Actors (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)
DROP TABLE IF EXISTS Casts
CREATE TABLE Casts (id INTEGER PRIMARY KEY AUTOINCREMENT, titleId INTEGER, actorId INTEGER, role TEXT)
INSERT INTO Titles (name) VALUES ($name)
($name, Peripheral)
select last_insert_rowid()
INSERT INTO Actors (name) VALUES ($name)
($name, Chloë Grace Moretz)
select last_insert_rowid()
INSERT INTO Casts (titleId, actorId, role) VALUES ($titleId, $actorId, $role)
($titleId, 1)
($role, Flynne Fisher)
($actorId, 1)
INSERT INTO Actors (name) VALUES ($name)
($name, Gary Carr)
select last_insert_rowid()
INSERT INTO Casts (titleId, actorId, role) VALUES ($titleId, $actorId, $role)
($titleId, 1)
($role, Wilf Netherton)
($actorId, 2)
INSERT INTO Actors (name) VALUES ($name)
($name, Jack Reynor)
select last_insert_rowid()
INSERT INTO Casts (titleId, actorId, role) VALUES ($titleId, $actorId, $role)
($titleId, 1)
($role, Burton Fisher)
($actorId, 3)
```

Let's suppose that you would like to get a list of the names of the actors who performed in the specified title. To do this, use the APIs as follows:

```csharp
public sealed class Example
{
...
public void ListActorNames(string title)
{
Kit.Execute(q =>
{
var map = new Dictionary<string, object>
{
["$name"] = title,
};
var all = q.SelectAllFrom<Actor>("a")
.InnerJoin<Cast>("c", "a.id = c.actorId")
.InnerJoin<Title>("t", "t.id = c.titleId")
.Where("t.name = $name", map)
.Execute();
foreach (var i in all)
{
Console.WriteLine(i.Name);
}
});
}
...

```

Calling `ListActorNames("Peripheral");` results in the following output:

```
SELECT a.id, a.name FROM Actors a INNER JOIN Casts c ON a.id = c.actorId INNER JOIN Titles t ON t.id = c.titleId WHERE t.name = $name
($name, Peripheral)
Chloë Grace Moretz
Gary Carr
Jack Reynor
```

<!--
## Get started

SqlBind.CSharp is available as
[the ![NuGet-logo][nuget-logo] NuGet package][nuget-maroontress.sqlbind].
-->

## API Reference

- [Maroontress.SqlBind][apiref-maroontress.sqlbind] namespace

## How to build

### Requirements for build

- Visual Studio 2022 (Version 17.5)
or [.NET 7.0 SDK (SDK 7.0.203)][dotnet-sdk]

### Build

```plaintext
git clone URL
cd SqlBind.CSharp
dotnet build
```

### Get the test coverage report with Coverlet

Install [ReportGenerator][report-generator] as follows:

```plaintext
dotnet tool install -g dotnet-reportgenerator-globaltool
```

Run all tests and get the report in the file `Coverlet-html/index.html`:

```plaintext
rm -rf MsTestResults
dotnet test --collect:"XPlat Code Coverage" --results-directory MsTestResults \
&& reportgenerator -reports:MsTestResults/*/coverage.cobertura.xml \
-targetdir:Coverlet-html
```
[report-generator]:
https://github.com/danielpalme/ReportGenerator
[dotnet-sdk]:
https://dotnet.microsoft.com/en-us/download
[apiref-maroontress.sqlbind]:
https://maroontress.github.io/SqlBind-CSharp/api/latest/html/Maroontress.SqlBind.html
[nuget-maroontress.sqlbind]:
https://www.nuget.org/packages/Maroontress.SqlBind/
[nuget-logo]:
https://maroontress.github.io/images/NuGet-logo.png
Loading

0 comments on commit 18ca90a

Please sign in to comment.