Database Action
The db action executes SQL queries on MySQL, PostgreSQL, and SQLite databases, providing comprehensive result handling and error reporting.
Basic Syntax
steps:
- name: "Database Query"
uses: db
with:
dsn: "mysql://user:password@localhost:3306/database"
query: "SELECT * FROM users WHERE active = ?"
params: [true]
test: res.code == 0 && res.rows_affected > 0Parameters
dsn (required)
Type: String
Description: Database connection string with automatic driver detection
Supports: Template expressions
# MySQL
vars:
db_pass: "{{DB_PASS}}"
with:
dsn: "mysql://user:password@localhost:3306/database"
dsn: "mysql://{{vars.db_user}}:{{vars.db_pass}}@{{vars.db_host}}/{{vars.db_name}}"
# PostgreSQL
vars:
pg_user: "{{PG_USER}}"
pg_pass: "{{PG_PASS}}"
pg_host: "{{PG_HOST}}"
pg_db: "{{PG_DB}}"
with:
dsn: "postgres://user:password@localhost:5432/database?sslmode=disable"
dsn: "postgres://{{vars.pg_user}}:{{vars.pg_pass}}@{{vars.pg_host}}/{{vars.pg_db}}"
# SQLite
with:
dsn: "file:./testdata/sqlite.db"
dsn: "file:/absolute/path/to/database.db"
dsn: "file:{{vars.data_dir}}/app.db"query (required)
Type: String
Description: SQL query to execute
Supports: Template expressions and multi-line strings
with:
query: "SELECT * FROM users"
query: "INSERT INTO logs (message, timestamp) VALUES (?, NOW())"
query: |
SELECT u.name, u.email, p.title
FROM users u
JOIN profiles p ON u.id = p.user_id
WHERE u.active = ? AND u.created_at > ?params (optional)
Type: Array of mixed values (String, Number, Boolean)
Description: Query parameters for prepared statements
Supports: Template expressions
with:
query: "SELECT * FROM users WHERE id = ? AND active = ?"
params: [123, true, "{{vars.user_email}}"]timeout (optional)
Type: Duration
Default: 30s
Description: Query execution timeout
with:
query: "SELECT COUNT(*) FROM large_table"
timeout: "60s"Response Object
The database action provides a res object with the following properties:
| Property | Type | Description |
|---|---|---|
code | Integer | Operation result (0 = success, 1 = error) |
rows_affected | Integer | Number of rows affected by the query |
rows | Array | Query results for SELECT statements (as objects) |
error | String | Error message if operation failed |
Response Examples
SELECT Query Response
steps:
- name: "Fetch Users"
id: fetch-users
uses: db
with:
dsn: "mysql://user:pass@localhost/db"
query: "SELECT id, name, email FROM users WHERE active = ?"
params: [true]
test: res.code == 0 && res.rows_affected > 0
outputs:
user_count: res.rows_affected
first_user_id: res.rows__0__id
first_user_name: res.rows__0__nameINSERT/UPDATE Query Response
steps:
- name: "Insert User"
uses: db
with:
dsn: "postgres://user:pass@localhost/db"
query: "INSERT INTO users (name, email) VALUES ($1, $2)"
params: ["John Doe", "john@example.com"]
test: res.code == 0 && res.rows_affected == 1Database-Specific Features
MySQL Examples
# MySQL with connection options
- name: "MySQL Query"
uses: db
with:
dsn: "mysql://user:pass@tcp(localhost:3306)/database?charset=utf8mb4&parseTime=true"
query: "SELECT VERSION() as mysql_version, NOW() as current_time"
test: res.code == 0
# MySQL stored procedure
- name: "Call Procedure"
uses: db
with:
dsn: "mysql://user:pass@localhost:3306/database"
query: "CALL GetUsersByDepartment(?)"
params: ["Engineering"]
test: res.code == 0PostgreSQL Examples
# PostgreSQL with JSON operations
- name: "JSON Query"
uses: db
with:
dsn: "postgres://user:pass@localhost:5432/database?sslmode=disable"
query: |
SELECT name, data->>'role' as role, data->'preferences' as prefs
FROM users
WHERE data ? 'role' AND data->>'role' = $1
params: ["admin"]
test: res.code == 0
# PostgreSQL array operations
- name: "Array Query"
uses: db
with:
dsn: "postgres://user:pass@localhost:5432/database"
query: "SELECT name FROM users WHERE tags && $1"
params: ['{"admin","moderator"}']
test: res.code == 0SQLite Examples
# SQLite with file creation
- name: "SQLite Query"
uses: db
with:
dsn: "file:./testdata/sqlite.db"
query: |
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
test: res.code == 0
# SQLite with in-memory database
- name: "Memory Database"
uses: db
with:
dsn: "file::memory:"
query: "CREATE TABLE temp_data (id INTEGER, value TEXT)"
test: res.code == 0Common Query Patterns
Data Validation Queries
- name: "Check Data Integrity"
uses: db
with:
dsn: "mysql://user:pass@localhost/db"
query: |
SELECT
COUNT(*) as total_users,
COUNT(CASE WHEN active = 1 THEN 1 END) as active_users,
COUNT(CASE WHEN email IS NULL THEN 1 END) as missing_emails
FROM users
test: |
res.code == 0 &&
res.rows__0__total_users > 0 &&
res.rows__0__missing_emails == 0Performance Monitoring
- name: "Database Performance Check"
uses: db
with:
dsn: "postgres://user:pass@localhost/db"
query: |
SELECT
schemaname,
tablename,
seq_scan,
seq_tup_read,
idx_scan,
idx_tup_fetch
FROM pg_stat_user_tables
WHERE seq_scan > 1000
timeout: "10s"
test: res.code == 0
outputs:
high_seq_scan_tables: res.rows_affectedBatch Operations
- name: "Batch Insert"
uses: db
with:
dsn: "mysql://user:pass@localhost/db"
query: |
INSERT INTO audit_log (action, table_name, record_id, timestamp) VALUES
('CREATE', 'users', 123, NOW()),
('UPDATE', 'profiles', 456, NOW()),
('DELETE', 'sessions', 789, NOW())
test: res.code == 0 && res.rows_affected == 3Security Features
The database action implements several security measures:
- Prepared Statements: All parameterized queries use prepared statements to prevent SQL injection
- Connection String Masking: Passwords are masked in logs and output
- Timeout Protection: Prevents long-running queries from hanging
- Driver Validation: Only supports approved database drivers
- DSN Validation: Validates connection string format before execution
Error Handling
Common error scenarios and handling patterns:
- name: "Database with Error Handling"
uses: db
with:
dsn: "mysql://user:pass@localhost/db"
query: "SELECT * FROM users WHERE id = ?"
params: [999999]
test: |
res.code == 0 ? true :
res.error | contains("connection") ? false :
res.error | contains("not found") ? true :
false
outputs:
query_success: res.code == 0
error_type: |
{{res.code == 0 ? "none" :
res.error | contains("connection") ? "connection" :
res.error | contains("syntax") ? "syntax" :
"unknown"}}Transaction Examples
While the action doesn’t directly support transactions, you can use database-specific transaction syntax:
# PostgreSQL transaction
- name: "Begin Transaction"
uses: db
with:
dsn: "postgres://user:pass@localhost/db"
query: "BEGIN"
test: res.code == 0
- name: "Insert Data"
uses: db
with:
dsn: "postgres://user:pass@localhost/db"
query: "INSERT INTO users (name) VALUES ($1)"
params: ["Test User"]
test: res.code == 0
- name: "Commit Transaction"
uses: db
with:
dsn: "postgres://user:pass@localhost/db"
query: "COMMIT"
test: res.code == 0