Skip to content

Commit 37fc7ac

Browse files
committed
ci and package
1 parent 4fe0f3e commit 37fc7ac

15 files changed

Lines changed: 263 additions & 79 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: CI
2+
3+
# The .NET suite runs everywhere and carries the shared smoke tests, the query
4+
# renderers for every vendor, and the code generator's golden file -- so it
5+
# guards all targets' logic even though only .NET executes here. The Fable
6+
# target legs (Rust needs an unmerged Fable fix, and cargo/node runs) stay
7+
# local for now; see README "Running the tests".
8+
9+
on:
10+
push:
11+
branches: [main]
12+
tags: ["v*"]
13+
pull_request:
14+
15+
jobs:
16+
test:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- uses: actions/setup-dotnet@v4
22+
with:
23+
dotnet-version: 8.0.x
24+
25+
- name: Test
26+
run: dotnet test tests/SQLProvider.Fable.Tests.Net/SQLProvider.Fable.Tests.Net.fsproj
27+
28+
- name: README samples compile
29+
run: dotnet build tests/SQLProvider.Fable.Tests.Readme/SQLProvider.Fable.Tests.Readme.fsproj
30+
31+
- name: Pack
32+
run: |
33+
dotnet pack src/SQLProvider.Fable.Core/SQLProvider.Fable.Core.fsproj -c Release -o packages
34+
dotnet pack src/SQLProvider.Fable.Ado/SQLProvider.Fable.Ado.fsproj -c Release -o packages
35+
dotnet pack src/SQLProvider.Fable.Rust/SQLProvider.Fable.Rust.fsproj -c Release -o packages
36+
dotnet pack src/SQLProvider.Fable.Js/SQLProvider.Fable.Js.fsproj -c Release -o packages
37+
dotnet pack tools/SQLProvider.Fable.Generator/SQLProvider.Fable.Generator.fsproj -c Release -o packages
38+
39+
- uses: actions/upload-artifact@v4
40+
with:
41+
name: packages
42+
path: packages/*.nupkg
43+
44+
# Publishes on a version tag (v0.1.0). Needs the NUGET_API_KEY repository
45+
# secret; the push is what makes a release, so nothing publishes by accident.
46+
publish:
47+
if: startsWith(github.ref, 'refs/tags/v')
48+
needs: test
49+
runs-on: ubuntu-latest
50+
steps:
51+
- uses: actions/checkout@v4
52+
53+
- uses: actions/setup-dotnet@v4
54+
with:
55+
dotnet-version: 8.0.x
56+
57+
- name: Pack
58+
run: |
59+
dotnet pack src/SQLProvider.Fable.Core/SQLProvider.Fable.Core.fsproj -c Release -o packages
60+
dotnet pack src/SQLProvider.Fable.Ado/SQLProvider.Fable.Ado.fsproj -c Release -o packages
61+
dotnet pack src/SQLProvider.Fable.Rust/SQLProvider.Fable.Rust.fsproj -c Release -o packages
62+
dotnet pack src/SQLProvider.Fable.Js/SQLProvider.Fable.Js.fsproj -c Release -o packages
63+
dotnet pack tools/SQLProvider.Fable.Generator/SQLProvider.Fable.Generator.fsproj -c Release -o packages
64+
65+
- name: Push to nuget.org
66+
run: dotnet nuget push "packages/*.nupkg" --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json --skip-duplicate
67+
env:
68+
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ Cargo.lock
1212
.fable/
1313
fable_modules/
1414
build/
15+
16+
# NuGet pack output
17+
packages/

‎README.md‎

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
Typed SQL for F#, from one source, on .NET **and** through Fable to **Rust**,
44
**JavaScript NodeJs** and **Erlang/BEAM**.
5-
6-
NOTE: Rust is "comming soon" as it needs some Fable side PRs merged first.
5+
6+
NOTE: Rust is "coming soon" as it needs some Fable side PRs merged first.
77

88
Point the generator at your database, get a module per table with typed columns
99
and row mappers, and write queries against them:
@@ -86,37 +86,62 @@ BEAM runs the whole portable half (query building, SQL generation, value
8686
encoding, row readers, the async layer) but has no connector yet. `epgsql` and
8787
`mysql-otp` are pure Erlang and so the easiest ones to add.
8888

89-
Not on NuGet yet: reference the projects directly.
89+
Packages: `SQLProvider.Fable.Core`, `.Ado`, `.Rust`, `.Js`, and the generator
90+
as the dotnet tool `SQLProvider.Fable.Generator`. CI packs them on every build
91+
and publishes to nuget.org on a `v*` tag.
9092

9193
---
9294

9395
## Getting started
9496

95-
Reference the runtime, plus the backend for your target:
97+
Reference `SQLProvider.Fable.Core` plus the connector for your target — only
98+
one connector ends up in a given build:
9699

97100
```xml
98-
<ProjectReference Include="path/to/src/SQLProvider.Fable.Core/SQLProvider.Fable.Core.fsproj" />
99-
<ProjectReference Include="path/to/src/SQLProvider.Fable.Ado/SQLProvider.Fable.Ado.fsproj" />
101+
<PackageReference Include="SQLProvider.Fable.Core" Version="0.1.0" />
102+
<PackageReference Include="SQLProvider.Fable.Ado" Version="0.1.0" /> <!-- .NET -->
103+
<!-- or SQLProvider.Fable.Rust / SQLProvider.Fable.Js for a Fable target -->
100104
```
101105

102-
`Core` is where everything portable lives. Add `SQLProvider.Fable.Ado` for .NET,
103-
`SQLProvider.Fable.Rust` for Fable/Rust, or `SQLProvider.Fable.Js` for
104-
Fable/JavaScript — only one of them ends up in a given build.
106+
(Working from a clone instead, `ProjectReference` the same projects under
107+
`src/`.)
108+
109+
The packages carry their F# sources under `fable/`, the way Fable libraries do,
110+
so a Fable project compiles the library to its own target while .NET uses the
111+
compiled assembly from the same package.
105112

106113
JavaScript and BEAM need nothing beyond released Fable. Rust additionally needs
107-
the unmerged fix described under [Status](#status).
114+
the unmerged fix described under [Status](#status), and the consuming crate's
115+
`Cargo.toml` needs the driver stack the connector calls into:
116+
117+
```toml
118+
[dependencies]
119+
sqlx = { version = "0.8", default-features = false, features = [
120+
"runtime-tokio", "any", "sqlite", "postgres", "mysql",
121+
] }
122+
tokio = { version = "1", features = ["rt-multi-thread"] }
123+
futures = "0.3"
124+
```
108125

109126
---
110127

111128
## Generating from your schema
112129

113130
Hand-writing `Col.text "Customer" "Name"` per column is the work a provider is
114-
supposed to remove, so generate it:
131+
supposed to remove, so generate it. The generator is a dotnet tool:
115132

116133
```bash
117-
dotnet run --project tools/SQLProvider.Fable.Generator -- --sqlite ./app.db --module Northwind --out ./src/Schema.fs
134+
dotnet tool install --global SQLProvider.Fable.Generator
118135
```
119136

137+
```bash
138+
sqlprovider-fable-gen --sqlite ./app.db --module Northwind --out ./src/Schema.fs
139+
```
140+
141+
`--postgres "Host=...;Username=...;Password=...;Database=..."` reads a live
142+
PostgreSQL schema the same way. (From a clone,
143+
`dotnet run --project tools/SQLProvider.Fable.Generator -- ...` does the same.)
144+
120145
Add `Schema.fs` to your project and check it in. Regenerate when the schema
121146
changes rather than editing it — the names in it have to keep matching the
122147
database.
@@ -318,6 +343,12 @@ germanCustomers
318343

319344
MySQL accepts `INTERSECT` and `EXCEPT` from 8.0.31.
320345

346+
Only ordering and paging apply to the combined result. Every other clause —
347+
`where`, `groupBy`, `select` — still describes the **first** SELECT, whether
348+
written before or after the `union`: SQL cannot filter a combined result
349+
without nesting it in a FROM, which this library does not do. Filter the arms,
350+
not the union.
351+
321352
```fsharp
322353
|> Query.where (Expr.contains Customer.Name.E searchBox)
323354
|> Query.selectExpr "band" (Expr.ifThenElse (Customer.Balance >. 100.0) high low)

‎UNLICENSE‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or
4+
distribute this software, either in source code form or as a compiled
5+
binary, for any purpose, commercial or non-commercial, and by any
6+
means.
7+
8+
In jurisdictions that recognize copyright laws, the author or authors
9+
of this software dedicate any and all copyright interest in the
10+
software to the public domain. We make this dedication for the benefit
11+
of the public at large and to the detriment of our heirs and
12+
successors. We intend this dedication to be an overt act of
13+
relinquishment in perpetuity of all present and future rights to this
14+
software under copyright law.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
24+
For more information, please refer to <https://unlicense.org>

‎src/Directory.Build.props‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<Project>
2+
3+
<!-- Shared NuGet metadata for every package under src/. Each project adds
4+
its own Description; everything identity-shaped lives here once. -->
5+
<PropertyGroup>
6+
<Version>0.1.0</Version>
7+
<Authors>Tuomas Hietanen</Authors>
8+
<PackageLicenseExpression>Unlicense</PackageLicenseExpression>
9+
<PackageProjectUrl>https://github.com/Thorium/SQLProvider.Fable</PackageProjectUrl>
10+
<RepositoryUrl>https://github.com/Thorium/SQLProvider.Fable</RepositoryUrl>
11+
<RepositoryType>git</RepositoryType>
12+
<PackageReadmeFile>README.md</PackageReadmeFile>
13+
<PackageTags>fsharp;fable;sql;sqlite;postgresql;mysql;rust;sqlprovider;database</PackageTags>
14+
</PropertyGroup>
15+
16+
<ItemGroup>
17+
<None Include="$(MSBuildThisFileDirectory)..\README.md" Pack="true" PackagePath="\" />
18+
</ItemGroup>
19+
20+
<!-- Without this the packages inherit the compiling SDK's FSharp.Core as
21+
their floor, which would force every consumer to its very newest.
22+
8.0 is comfortably old enough for everything this code uses. -->
23+
<ItemGroup>
24+
<PackageReference Update="FSharp.Core" Version="8.0.301" />
25+
</ItemGroup>
26+
27+
</Project>

‎src/SQLProvider.Fable.Ado/SQLProvider.Fable.Ado.fsproj‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFramework>net8.0</TargetFramework>
5+
<Description>.NET connector for SQLProvider.Fable: wraps any ADO.NET DbConnection (Microsoft.Data.Sqlite, Npgsql, MySqlConnector, ...).</Description>
56
</PropertyGroup>
67

78
<ItemGroup>

‎src/SQLProvider.Fable.Core/Execute.fs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ module Db =
9090
/// Whether the query matches anything, without dragging the rows back.
9191
let exists (conn: ISqlConnector) (q: Query) : Async<bool> =
9292
async {
93-
let! n = count conn q
93+
// Deduplication cannot change whether anything exists, so DISTINCT
94+
// is dropped here rather than refused the way a bare count of it is.
95+
let! n = count conn { q with Distinct = false }
9496
return n > 0L
9597
}
9698

‎src/SQLProvider.Fable.Core/Query.fs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,11 @@ module Query =
582582
/// project the same number of columns; the result's column names come from
583583
/// this query, and any `orderBy`/`skip`/`take` on this query order and page
584584
/// the combined result.
585+
///
586+
/// Every *other* clause -- `where`, `groupBy`, `select` and the rest --
587+
/// still describes the first SELECT, whether written before or after this
588+
/// call: SQL has no way to filter a combined result without nesting it in
589+
/// a FROM, which this library does not do. Filter the arms, not the union.
585590
let union (other: Query) (q: Query) = addCompound Union other q
586591

587592
/// `UNION ALL` -- `.Concat()`: everything from both, duplicates kept.

‎src/SQLProvider.Fable.Core/SQLProvider.Fable.Core.fsproj‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<!-- Portable F# only: no System.Data, no System.Linq.Expressions, no
66
reflection. Everything here must survive Fable's Rust backend. -->
77
<GenerateDocumentationFile>true</GenerateDocumentationFile>
8+
<Description>Typed SQL for F#, from one source, on .NET and through Fable on Rust, JavaScript and BEAM. The portable core: schema-typed columns, composable queries, vendor-aware SQL generation, row readers. Pair with one connector package per target.</Description>
89
</PropertyGroup>
910

1011
<ItemGroup>

‎src/SQLProvider.Fable.Design/SQLProvider.Fable.Design.fsproj‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
<PropertyGroup>
44
<TargetFramework>net8.0</TargetFramework>
55
<!-- Design-time only: this reads a schema and writes F# source, and never
6-
reaches a Fable target. It is free to use whatever .NET it likes. -->
6+
reaches a Fable target. It is free to use whatever .NET it likes.
7+
Not packaged: it ships inside the generator tool instead. -->
8+
<IsPackable>false</IsPackable>
79
</PropertyGroup>
810

911
<ItemGroup>

0 commit comments

Comments
 (0)