Skip to content

Database

Jazzy includes a powerful, fluent Query Builder that allows you to interact with your database without writing raw SQL. It allows you to switch underlying databases with minimal code changes (currently optimized for SQLite).

In your app.nim or database.nim module:

import jazzy
connectDB("app.db")
let users = DB.table("users").get()
# Returns a JsonNode (JArray) of objects
let user = DB.table("users").where("email", "test@test.com").first()
# Returns a JsonNode (JObject). Use .isNull() to check if not found

By default, get() returns all columns (SELECT *). You can specify which columns you want:

let user = DB.table("users").select("name", "email").first()
# Only "name" and "email" keys will exist in the result JsonNode

Fluid chaining makes complex queries easy.

DB.table("posts").where("published", 1)

Comparison Operators:

DB.table("users").where("age", ">=", 18)
DB.table("products").where("price", "<", 100)
DB.table("status", "!=", "deleted")

Chaining (AND logic): Multiple calls are treated as AND conditions.

DB.table("users")
.where("active", 1)
.where("role", "admin")
.get()
# SELECT * FROM users WHERE active = 1 AND role = 'admin'

You can sort your results using orderBy.

# Sort users by age in descending order
let users = DB.table("users").orderBy("age", "DESC").get()
# Default direction is ASC (ascending)
let recentPosts = DB.table("posts").orderBy("created_at").get()
let totalUsers = DB.table("users").count()
let activeUsers = DB.table("users").where("active", 1).count()

Limit the number of results returned or skip a certain number of records.

# Get the top 10 recent posts
let posts = DB.table("posts").limit(10).get()
# Pagination: Skip 20 posts and get the next 10
let page3 = DB.table("posts").limit(10).offset(20).get()

To insert data, pass a JsonNode (%*). Returns the ID of the newly inserted row.

let newUserId = DB.table("users").insert(%*{
"username": "caner",
"email": "jcanermastan@gmail.com"
})

Note: If your table has created_at or updated_at columns, Jazzy will automatically populate them with the current UTC timestamp.

Updates affect all rows matching the where clause.

# Deactivate user #5
DB.table("users")
.where("id", 5)
.update(%*{"active": 0})

Note: If your table has an updated_at column, Jazzy will automatically update its value.

Deletes all rows matching the where clause.

DB.table("users").where("id", 5).delete()

Warning: Calling delete() without a where clause will wipe the table!

When a table supports Soft Deletes, records are not actually removed from the database. Instead, a deleted_at timestamp is set.

In your schema definition:

createTable("posts")
.increments("id")
.string("title")
.softDeletes() # Adds deleted_at column
.execute()

By default, soft-deleted records are excluded from all queries.

# Only returns active (non-deleted) posts
let posts = DB.table("posts").get()
# Include deleted records
let allPosts = DB.table("posts").withTrashed().get()
# Only retrieve deleted records
let trash = DB.table("posts").onlyTrashed().get()
# Restore a deleted record
DB.table("posts").where("id", 1).restore()
# Permanently delete a record
DB.table("posts").where("id", 1).forceDelete()

For complex queries (JOINs, subqueries) that the Query Builder doesn’t yet support, you can use the raw() and rawExec() methods.

The raw() method is used for data-returning queries (like SELECT or PRAGMA). It returns a JSON array of rows.

let res = DB.raw("SELECT name, age FROM users WHERE id = ?", 1)

The rawExec() method is used for statements that modify data (INSERT, UPDATE, DELETE). It returns the number of affected rows.

let affected = DB.rawExec("UPDATE users SET age = ? WHERE name = ?", 30, "Alice")