Fluent SQL builder library.
- Just start build
SQLquery fromSqlorPgSqlclasses. - Use
Sqlify.Dapperlibrary allowingSqlifyandDapperto be used together.
SELECT,DELETE,INSERT,UPDATEqueriesWHERE,JOIN,ORDER BY,GROUP BY,HAVING BYclausesLIKE,EXISTS,IN,BETWEENpredicatesCOUNT,SUM,MAX,MIN,AVG,CAST,COALESCE,NULLIFfunctionsUNIONqueries- Multiple queries
- Table and Column aliases
- SQL injections free
- Partial
PostgreSQLdialect support - Strongly typed (checked at compile time)
- GC friendly
// Create model for table Books with columns: Id, AuthorId, Rating
public interface IBooks : ITable
{
public Column<int> Id { get; }
public Column<int> AuthorId { get; }
public Column<double> Rating { get; }
}
// Create model for table Authors with columns: Id, Name
public interface IAuthors : ITable
{
public Column<int> Id { get; }
public Column<int> Name { get; }
}
var a = Sql.Table<IAuthors>("a");
var b = Sql.Table<IBooks>("b");
var selectQuery = Sql
.Select(a.Id, Sql.Count().As("Count"))
.From(a)
.Join(b, b.AuthorId == a.Id)
.Where(b.Rating > 2.0)
.Having(Sql.Count() >= 3)
.OrderByDesc(Sql.Count());
// SELECT a.Id, COUNT(*) AS Count
// FROM Authors a
// JOIN Books b ON b.AuthorId = a.Id
// WHERE b.Rating > @p1
// HAVING COUNT(*) >= @p2
// ORDER BY COUNT(*) DESC-
SELECTquery -
DELETEquery -
INSERTquery -
UPDATEquery -
PostreSQLdialectOFFSETandLIMITclausesUPDATE RETURNINGclauseINSERT RETURNINGclauseDELETE RETURNINGclauseINSERT ON CONFLICT DOclauseSELECT FORclause
As an example, consider the following database schema (authors and books tables with one-to-many relationship):
CREATE TABLE authors (
id integer PRIMARY KEY,
name varchar(64)
)
CREATE TABLE books (
id integer PRIMARY KEY,
name varchar(512),
author_id integer REFERENCES authors (id), -- one-to-many relationship
rating real,
qty integer
)For these tables create corresponding interfaces:
[Table("authors")]
public interface IAuthorsTable : ITable
{
[Column("id")]
Column<int> Id { get; }
[Column("name")]
Column<string> Name { get; }
}
[Table("books")]
public interface IBooksTable : ITable
{
[Column("id")]
Column<int> Id { get; }
[Column("name")]
Column<string> Name { get; }
[Column("author_id")]
Column<int> AuthorId { get; }
[Column("rating")]
Column<double> Rating { get; }
[Column("qty")]
Column<int> Quantity { get; }
}If the names of the columns in the database are the same as the names of the properties in models, then using TableAttribute and ColumnAttrubute are optional.
For example, for schema:
CREATE TABLE Authors (
Id integer PRIMARY KEY,
Name varchar(64),
BooksCount integer
)you can define table like:
public interface IAuthorsTable : ITable
{
Column<int> Id { get; }
Column<int> Name { get; }
Column<int> BooksCount { get; }
}var b = Sql.Table<IBooksTable>();
var query = Sql
.Select(b.Id, b.Name)
.From(b);
// SELECT books.id, books.name FROM booksvar b = Sql.Table<IBooksTable>("t"); // table alias
var query = Sql
.Select(b.Id, b.Name)
.From(b);
// SELECT t.id, t.name FROM books tvar b = Sql.Table<IBooksTable>("t");
var query = Sql
.Select(b.Id, b.Name.As("author_name")) // column alias
.From(b);
// SELECT t.id, t.name AS author_name FROM books tvar b = Sql.Table<IBooksTable>();
var query = Sql
.Select(Sql.Count())
.From(b);
// SELECT COUNT(*) FROM booksvar b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select(Sql.Avg(b.Rating))
.From(b);
// SELECT AVG(b.rating) FROM books bvar b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select(b.Rating.Cast<int>("INTEGER"))
.From(b);
// SELECT CAST(b.rating AS INTEGER) FROM books bvar b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select(Sql.Coalesce(b.Name, "n/a"))
.From(b);
// SELECT COALESCE(b.name, @p1) FROM books bvar b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select(Sql.NullIf(b.Name, "n/a"))
.From(b);
// SELECT NULLIF(b.name, @p1) FROM books bDefine a table orders with computed column total = qty * price:
[Table("orders")]
public interface IOrder : ITable
{
[Column("id")]
Column<int> Id { get; }
[Column("qty")]
Column<int> Qty { get; }
[Column("price")]
Column<int> Price { get; }
[Column("total")]
Expression<int> Total => Qty * Price; // <- computed column
}var o = Sql.Table<IOrder>("o");
var query = Sql
.Select(o.Id, o.Total)
.From(o);
// SELECT o.id, o.qty * o.price AS total FROM orders ovar a = Sql.Table<IAuthorsTable>("a");
var query = Sql
.Select(a.Name)
.Distinct()
.From(a);
// SELECT DISTINCT a.name FROM authors avar b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select()
.From(b)
.Where(b.Name.IsNull.And(b.Rating <= 0));
// SELECT * FROM books b WHERE b.name IS NULL AND b.rating <= @p1var b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select()
.From(b)
.Where(
b.Name.IsNull,
b.Rating <= 0
);
// SELECT * FROM books b WHERE b.name IS NULL AND b.rating <= @p1var a = Sql.Table<IAuthorsTable>("a");
var query = Sql
.Select()
.From(a)
.Where(a.Name.Like("A%")); // started with 'A'
// SELECT * FROM authors a WHERE a.name LIKE @p1var a = Sql.Table<IAuthorsTable>("a");
var query = Sql
.Select()
.From(a)
.Where(a.Id.In(new[] {1, 2})); // where id==1 OR id==2
// SELECT * FROM authors a WHERE a.id IN @p1var a = Sql.Table<IAuthorsTable>("a");
var b = Sql.Table<IBooksTable>("b");
var subQuery = Sql
.Select(b.AuthorId)
.From(b)
.Where(b.Rating > 3);
var query = Sql
.Select()
.From(a)
.Where(a.Id.In(subQuery)); // IN sub-query
// SELECT * FROM authors a WHERE a.id IN (SELECT b.author_id FROM books b WHERE b.rating > @p1)");var a = Sql.Table<IAuthorsTable>("a");
var b = Sql.Table<IBooksTable>("b");
var subQuery = Sql
.Select()
.From(b)
.Where((a.Id == b.AuthorId).And(b.Rating > 3));
var query = Sql
.Select()
.From(a)
.WhereExists(subQuery);
// SELECT * FROM authors a WHERE EXISTS (SELECT * FROM books b WHERE a.id = b.author_id AND b.rating > @p1var b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select()
.From(b)
.Where(b.Rating.Between(2, 4));
// SELECT * FROM books b WHERE b.rating BETWEEN @p1 AND @p2var a = Sql.Table<IAuthorsTable>("a");
var b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select()
.Join(b, a.Id == b.AuthorId) // also LEFT, RIGHT, FULL JOIN
.From(a);
// SELECT * FROM authors a JOIN books b ON a.id = b.author_idvar b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select()
.OrderByDesc(b.Rating)
.From(b);
// SELECT * FROM books b ORDER BY b.rating DESCvar b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select(b.AuthorId, Sql.Count())
.GroupBy(b.AuthorId)
.From(b);
// SELECT b.author_id, COUNT(*) FROM books b GROUP BY b.author_idvar a = Sql.Table<IAuthorsTable>();
var b = Sql.Table<IBooksTable>();
MultipleQuery query = Sql
.Multiple(
Sql.Select().From(a),
Sql.Select().From(b)
);
// SELECT * FROM authors; SELECT * FROM books var b = Sql.Table<IBooksTable>("b");
var query = Sql
.Select(b.AuthorId, Sql.Count())
.GroupBy(b.AuthorId)
.Having(Sql.Count() > 3)
.From(b);
// SELECT b.author_id, COUNT(*) FROM books b GROUP BY b.author_id HAVING COUNT(*) > @p1var b = Sql.Table<IBooksTable>();
var query = Sql
.Delete(b)
.Where(b.Id == 1);
// DELETE FROM books WHERE books.id = @p1var a = Sql.Table<IAuthorsTable>();
var query = Sql
.Insert(a)
.Values(a.Id, 1)
.Values(a.Name, "Adam");
// INSERT INTO authors (id, name) VALUES (@p1, @p2)var b = Sql.Table<IBooksTable>();
var query = Sql
.Update(b)
.Set(b.Rating, b.Rating + 1)
.Where(b.AuthorId == 1);
// UPDATE books SET rating = books.rating + @p1 WHERE books.author_id = @p2var a = Sql.Table<IAuthorsTable>("a");
PgSelectQuery query = PgSql
.Select()
.From(a)
.OrderBy(a.Name)
.Offset(5)
.Limit(10)
// SELECT * FROM authors a ORDER BY a.name OFFSET @p1 LIMIT @p2var b = Sql.Table<IBooksTable>();
PgUpdateQuery query = PgSql
.Update(b)
.Set(b.Rating, b.Rating + 1)
.Returning(b.Id, b.Rating);
// UPDATE books SET rating = books.rating + @p1 RETURNING books.id, books.ratingvar b = Sql.Table<IBooksTable>();
PgInsertQuery query = PgSql
.Insert(b)
.Values(b.Name, "name")
.Returning();
// INSERT INTO books (name) VALUES (@p1) RETURNING *var b = Sql.Table<IBooksTable>();
PgInsertQuery query = PgSql
.Delete(b)
.Returning();
// DELETE FROM books RETURNING *var b = Sql.Table<IBooksTable>("b");
PgInsertQuery query = PgSql
.Insert(b)
.Values(b.Id, 1)
.Values(b.Name, "foo bar")
.Values(b.Quantity, 5)
.OnConflict(
PgConflict.Columns(b.Name),
PgConflict
.DoUpdate()
.Set(b.Quantity, b.Quantity + 5)
);
// INSERT INTO books AS b (id, name, qty) VALUES (@p1, @p2, @p3)
// ON CONFLICT (b.name)
// DO UPDATE SET qty = b.qty + @p4"var b = Sql.Table<IBooksTable>("b");
PgSelectQuery query = PgSql
.Select()
.From(b)
.Where(b.Id == 3)
.For(PgLockMode.Update); // mode: UPDATE, NO KEY UPDATE, SHARE, KEY SHARE
// SELECT * FROM books b WHERE b.id = @p1 FOR UPDATE# build
dotnet build ./src
# running tests
dotnet test ./src
# pack
dotnet pack ./src -c=release