All Projects → antoyo → Tql

antoyo / Tql

Licence: mit
TQL is a compile-time Rust ORM

Programming Languages

rust
11053 projects

Projects that are alternatives of or similar to Tql

Dotenv Kotlin
🗝️ Dotenv is a module that loads environment variables from a .env file
Stars: ✭ 326 (-0.31%)
Mutual labels:  hacktoberfest
Codeceptjs
Supercharged End 2 End Testing Framework for NodeJS
Stars: ✭ 3,592 (+998.47%)
Mutual labels:  hacktoberfest
Osquery
SQL powered operating system instrumentation, monitoring, and analytics.
Stars: ✭ 18,475 (+5549.85%)
Mutual labels:  hacktoberfest
Django X509
Reusable django app implementing x509 PKI certificates management
Stars: ✭ 326 (-0.31%)
Mutual labels:  hacktoberfest
Devicekit
DeviceKit is a value-type replacement of UIDevice.
Stars: ✭ 3,566 (+990.52%)
Mutual labels:  hacktoberfest
Cds
Enterprise-Grade Continuous Delivery & DevOps Automation Open Source Platform
Stars: ✭ 3,677 (+1024.46%)
Mutual labels:  hacktoberfest
Code
Code editor designed for elementary OS
Stars: ✭ 324 (-0.92%)
Mutual labels:  hacktoberfest
Bulma Admin Dashboard Template
🐝 Free admin dashboard template with bulma css
Stars: ✭ 327 (+0%)
Mutual labels:  hacktoberfest
Macos big sur icons replacements
Replacement icons for popular apps in the style of macOS Big Sur
Stars: ✭ 3,608 (+1003.36%)
Mutual labels:  hacktoberfest
Portainer
Making Docker and Kubernetes management easy.
Stars: ✭ 20,434 (+6148.93%)
Mutual labels:  hacktoberfest
Postgresql
Development repository for the postgresql cookbook
Stars: ✭ 326 (-0.31%)
Mutual labels:  hacktoberfest
J.a.r.v.i.s
python powered Intelligent System
Stars: ✭ 325 (-0.61%)
Mutual labels:  hacktoberfest
Jenkins
Jenkins automation server
Stars: ✭ 18,225 (+5473.39%)
Mutual labels:  hacktoberfest
Pathfinding
Pathfinding library for rust
Stars: ✭ 324 (-0.92%)
Mutual labels:  hacktoberfest
Phpjasper
A PHP report generator
Stars: ✭ 327 (+0%)
Mutual labels:  hacktoberfest
Launchpad
An open-source game launcher for your games
Stars: ✭ 322 (-1.53%)
Mutual labels:  hacktoberfest
Luvit
Lua + libUV + jIT = pure awesomesauce
Stars: ✭ 3,443 (+952.91%)
Mutual labels:  hacktoberfest
Vue Storefront Api
Vue.js storefront for Magento2 (and not only) - data backend
Stars: ✭ 328 (+0.31%)
Mutual labels:  hacktoberfest
Waiter
🕰️ Loading screens for Shiny
Stars: ✭ 325 (-0.61%)
Mutual labels:  hacktoberfest
Validator.js
String validation
Stars: ✭ 18,842 (+5662.08%)
Mutual labels:  hacktoberfest

= TQL :source-highlighter: pygments

Compile-time ORM, inspired by Django ORM, written in Rust. Tql is implemented as a procedural macro and even works on the stable version of Rust (https://github.com/antoyo/tql/tree/master/examples/todo-stable[look at this example to see how to use tql on stable]).

This library is in alpha stage: it has not been thoroughly tested and its API may change at any time.

image:https://img.shields.io/travis/antoyo/tql/master.svg[link="https://travis-ci.org/antoyo/tql"] image:https://img.shields.io/crates/l/tql.svg[link="LICENSE"] image:https://img.shields.io/gitter/room/tql-rs/Lobby.svg[link="https://gitter.im/tql-rs/Lobby"] image:https://img.shields.io/badge/Donate-Patreon-orange.svg[link="https://www.patreon.com/antoyo"]

== Requirements

Currently, tql only supports the PostgreSQL and SQLite databases (more databases will be supported in the future). So, you need to install PostgreSQL (and/or libsqlite3-sys) in order to use this crate.

== Usage

First, add this to you Cargo.toml:

[source,toml]

[dependencies] chrono = "^0.4.0" tql_macros = "0.1"

[dependencies.tql] features = ["chrono", "pg"] version = "0.1"

[dependencies.postgres] features = ["with-chrono"] version = "^0.15.1"

(You can remove the chrono stuff if you don't want to use the date and time types in your model.)

Next, add this to your crate:

[source,rust]

#![feature(proc_macro_hygiene)]

extern crate chrono; extern crate postgres; extern crate tql; #[macro_use] extern crate tql_macros;

use postgres::{Connection, TlsMode}; use tql::PrimaryKey; use tql_macros::sql;

Then, create your model:

[source,rust]

use chrono::DateTime; use chrono::offset::Utc;

#[derive(SqlTable)] struct Model { id: PrimaryKey, text: String, date_added: DateTime, // … }

Next, create an accessor for your connection:

[source,rust]

fn get_connection() -> Connection { Connection::connect("postgres://test:[email protected]/database", TlsMode::None).unwrap() }

Finally, we can use the sql! macro to execute an SQL query:

[source,rust]

fn main() { let connection = get_connection();

// We first create the table.
// (You might not want to execute this query every time.)
let _ = sql!(Model.create());

// Insert a row in the table.
let text = String::new();
let id = sql!(Model.insert(text = text, date_added = Utc::now())).unwrap();

// Update a row.
let result = sql!(Model.get(id).update(text = "new-text"));

// Delete a row.
let result = sql!(Model.get(id).delete());

// Query some rows from the table:
// get the last 10 rows sorted by date_added descending.
let items = sql!(Model.sort(-date_added)[..10]);

}

The sql!() macro uses the identifier connection by default.

Look at the https://github.com/antoyo/tql#syntax-table[following table] to see more examples.

== Usage with SQLite

First, change the postgres dependency to this one:

[source,toml]

rusqlite = "^0.13.0"

Then, change the features of the tql dependency:

[source,toml]

[dependencies.tql] features = ["sqlite"] version = "0.1"

In the Rust code, the connection needs to come from rusqlite now:

[source,rust]

use rusqlite::Connection;

fn get_connection() -> Connection { Connection::open("database.db").unwrap() }

And the rest is the same.

== Using on stable Rust

If you want to use tql on stable, there are a few changes that are required in order to work:

First, remove these lines:

[source,rust]

#![feature(proc_macro_hygiene)]

// …

use tql_macros::sql;

And add the following line before extern crate tql:

[source,rust]

#[macro_use]

This is how the start of the file now looks:

[source,rust]

extern crate chrono; extern crate postgres; #[macro_use] extern crate tql; #[macro_use] extern crate tql_macros;

use postgres::{Connection, TlsMode}; use tql::PrimaryKey;

Finally, disable the unstable feature by updating the tql dependency to:

[source,toml]

[dependencies.tql] default-features = false features = ["chrono", "pg"] version = "0.1"

With this small change, we can use the sql!(), but it now requires you to specify the connection:

[source.rust]

let date_added = Utc::now(); let id = sql!(connection, Model.insert(text = text, date_added = date_added)).unwrap();

Also, because of limitations on the stable compiler, you cannot use an expression for the arguments anymore: that's why we now create a variable date_added. For now, if you use tql on stable, you need to use identifiers or literals for arguments.

=== Why not always using the stable version?

Procedural macros do not currently support emitting errors at specific positions on the stable version, so with this version, you will get errors that are less useful, like in the following output:

[source]

error[E0308]: mismatched types --> src/main.rs:47:18 | 47 | let result = sql!(Model.insert(text = text, date_added = Utc::now(), done = false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &str, found struct std::string::String | = note: expected type &str found type std::string::String = help: try with &sql!(Model.insert(text = text, date_added = Utc::now(), done = false)) = note: this error originates in a macro outside of the current crate

While you will get this nicer error when using the nightly version of Rust:

[source]

error[E0308]: mismatched types --> examples/todo.rs:49:46 | 49 | let result = sql!(Model.insert(text = text, date_added = Utc::now(), done = false)); | ^^^^ | | | expected &str, found struct std::string::String | help: consider borrowing here: &text | = note: expected type &str found type std::string::String

So, a good workflow is to develop on nightly and then ship on stable. This way, you get the best of both worlds: you have nice errors and you can deploy with the stable version of the compiler. This is not an issue at all because you're not supposed to have compiler errors when you're ready to deploy (and you can see the errors anyway).

NOTE: Compile with RUSTFLAGS="--cfg procmacro2_semver_exempt" to get even better error messages.

== Syntax table

The left side shows the generated SQL and the right side shows the syntax you can use with tql.

[cols="1a,1a", options="header"] |=== | SQL | Rust

| [source, sql]

SELECT * FROM Table

| [source, rust]

Table.all()

| [source, sql]

SELECT * FROM Table WHERE field1 = 'value1'

| [source, rust]

Table.filter(field1 == "value1")

| [source, sql]

SELECT * FROM Table WHERE primary_key = 42

| [source, rust]

Table.get(42)

// Shortcut for:

Table.filter(primary_key == 42)[0..1];

| [source, sql]

SELECT * FROM Table WHERE field1 = 'value1'

| [source, rust]

Table.get(field1 == "value1")

// Shortcut for:

Table.filter(field1 == "value1")[0..1];

| [source, sql]

SELECT * FROM Table WHERE field1 = 'value1' AND field2 < 100

| [source, rust]

Table.filter(field1 == "value1" && field2 < 100)

| [source, sql]

SELECT * FROM Table WHERE field1 = 'value1' OR field2 < 100

| [source, rust]

Table.filter(field1 == "value1" || field2 < 100)

| [source, sql]

SELECT * FROM Table ORDER BY field1

| [source, rust]

Table.sort(field1)

| [source, sql]

SELECT * FROM Table ORDER BY field1 DESC

| [source, rust]

Table.sort(-field1)

| [source, sql]

SELECT * FROM Table LIMIT 0, 20

| [source, rust]

Table[0..20]

| [source, sql]

SELECT * FROM Table WHERE field1 = 'value1' AND field2 < 100 ORDER BY field2 DESC LIMIT 10, 20

| [source, rust]

Table.filter(field1 == "value1" && field2 < 100) .sort(-field2)[10..20]

| [source, sql]

INSERT INTO Table(field1, field2) VALUES('value1', 55)

| [source, rust]

Table.insert(field1 = "value1", field2 = 55)

| [source, sql]

UPDATE Table SET field1 = 'value1', field2 = 55 WHERE id = 1

| [source, rust]

Table.get(1).update(field1 = "value1", field2 = 55);

// or

Table.filter(id == 1).update(field1 = "value1", field2 = 55);

| [source, sql]

DELETE FROM Table WHERE id = 1

| [source, rust]

Table.get(1).delete();

// ou

Table.filter(id == 1).delete()

| [source, sql]

SELECT AVG(field2) FROM Table

| [source, rust]

Table.aggregate(avg(field2))

| [source, sql]

SELECT AVG(field1) FROM Table1 GROUP BY field2

| [source, rust]

Table1.values(field2).annotate(avg(field1))

| [source, sql]

SELECT AVG(field1) as average FROM Table1 GROUP BY field2 HAVING average > 5

| [source, rust]

Table1.values(field2).annotate(average = avg(field1)) .filter(average > 5)

| [source, sql]

SELECT AVG(field1) as average FROM Table1 WHERE field1 < 10 GROUP BY field2 HAVING average > 5

| [source, rust]

Table1.filter(field1 < 10).values(field2) .annotate(average = avg(field1)).filter(average > 5)

| [source, sql]

SELECT Table1.field1, Table2.field1 FROM Table1 INNER JOIN Table2 ON Table1.pk = Table2.fk

| [source, rust]

#[derive(SqlTable)] struct Table1 { pk: PrimaryKey, field1: i32, }

#[derive(SqlTable)] struct Table2 { field1: i32, fk: ForeignKey, }

Table1.all().join(Table2)

| [source, sql]

SELECT * FROM Table1 WHERE YEAR(date) = 2015

| [source, rust]

Table1.filter(date.year() == 2015)

| [source, sql]

SELECT * FROM Table1 WHERE INSTR(field1, 'string') > 0

| [source, rust]

Table1.filter(field1.contains("string"))

| [source, sql]

SELECT * FROM Table1 WHERE field1 LIKE 'string%'

| [source, rust]

Table1.filter(field1.starts_with("string"))

| [source, sql]

SELECT * FROM Table1 WHERE field1 LIKE '%string'

| [source, rust]

Table1.filter(field1.ends_with("string"))

| [source, sql]

SELECT * FROM Table1 WHERE field1 IS NULL

| [source, rust]

Table1.filter(field1.is_none())

| [source, sql]

SELECT * FROM Table1 WHERE field1 REGEXP BINARY '^[a-d]'

| [source, rust]

Table1.filter(field1.regex(r"^[a-d]"))

| [source, sql]

SELECT * FROM Table1 WHERE field1 REGEXP '^[a-d]'

| [source, rust]

Table1.filter(field1.iregex(r"^[a-d]"))

| [source, sql]

CREATE TABLE IF NOT EXISTS Table1 ( pk INTEGER NOT NULL AUTO_INCREMENT, field1 INTEGER, PRIMARY KEY (pk) )

| [source, rust]

#[derive(SqlTable)] struct Table1 { pk: PrimaryKey, field1: i32, }

Table1.create()

|===

== Donations

If you appreciate this project and want new features to be implemented, please support me on Patreon.

image:https://c5.patreon.com/external/logo/become_a_patron_button.png[link="https://www.patreon.com/antoyo"]

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].