Raw SQL
Execute raw PostgreSQL queries when you need the full escape hatch.
The raw SQL API lives on kura.db.raw.
Use raw SQL when you need:
- complex joins or CTEs
COPY,LISTEN,NOTIFY, or other PostgreSQL-specific features- advanced update expressions that the builder does not model yet
- framework-specific SQL that does not map cleanly to the chainable builder
For normal gameplay scripts, prefer the builder and generated schema refs first.
Builder strings are not raw SQL
Plain string table and column names in kura.db.select(), insert(), update(), delete(), and op.* are treated as quoted SQL identifiers for compatibility. They are not interpreted as raw SQL fragments, expressions, or aliases.
PostgreSQL uses $1, $2, $3 placeholders, not ?.
Result shape
Raw SQL results come back with PostgreSQL column names unless you alias them yourself in SQL. If you want Lua field-name remapping from created_at to createdAt, use the schema-aware builder instead.
query
Returns all matching rows as a table.
local rows = kura.db.raw.query.await(
'SELECT * FROM "public"."users" WHERE job = $1',
{ 'police' }
)single
Returns the first row, or nil if no rows match.
local user = kura.db.raw.single.await(
'SELECT * FROM "public"."users" WHERE id = $1',
{ userId }
)scalar
Returns a single value from the first row.
local count = kura.db.raw.scalar.await('SELECT COUNT(*) FROM "public"."users"')update
Executes an update and returns the number of affected rows.
local changed = kura.db.raw.update.await(
'UPDATE "public"."users" SET last_seen_at = NOW() WHERE id = $1',
{ userId }
)insert
Executes an insert and returns the inserted id. KuraDB automatically appends RETURNING id for simple inserts without an existing RETURNING clause.
local id = kura.db.raw.insert.await(
'INSERT INTO "public"."users" (license) VALUES ($1)',
{ license }
)execute
Execute the same statement with multiple parameter sets:
local results = kura.db.raw.execute.await(
'UPDATE "public"."users" SET cash = cash + $1 WHERE id = $2',
{
{ 100, 1 },
{ 250, 2 },
}
)batch
The fast path for repeated prepared statements. Uses PostgreSQL pipeline mode for high throughput.
local rows = kura.db.raw.batch.await(
'SELECT id FROM "public"."users" WHERE license = $1 LIMIT 1',
{
{ 'license:1' },
{ 'license:2' },
},
{ prepare = true }
)insertMany
Multi-row insert optimized for bulk operations:
local ids = kura.db.raw.insertMany.await('users', {
{ license = 'license:1', cash = 500 },
{ license = 'license:2', cash = 750 },
}, {
returning = 'id',
})insertMany is the recommended bulk-insert API today. There is not yet a builder-native valuesMany() helper.
Pub/Sub
PostgreSQL LISTEN / NOTIFY is exposed directly.
listen
local subscription = kura.db.raw.listen.await('player_banned', function(payload)
local data = json.decode(payload)
DropPlayer(data.serverId, 'Banned by admin panel')
end)notify
kura.db.raw.notify.await('player_banned', json.encode({ serverId = 1 }))unlisten
kura.db.raw.unlisten.await(subscription.id)COPY
Bulk ingest and export using PostgreSQL's COPY protocol.
copyFrom
kura.db.raw.copyFrom.await(
'COPY users (license, cash) FROM STDIN WITH (FORMAT csv)',
{
'license:1,500\n',
'license:2,750\n',
}
)copyTo
local csv = kura.db.raw.copyTo.await(
'COPY users (license, cash) TO STDOUT WITH (FORMAT csv)'
)