Skip to main content

PostgreSQL

DoubleDino supports native PostgreSQL queries through the /query endpoint.

The query is sent directly to PostgreSQL. DoubleDino does not rewrite or transform the query. PostgreSQL executes it normally, and DoubleDino transforms the returned values before sending the result to the client.

Query

Use normal PostgreSQL SQL:

curl -G "http://localhost:8080/query" \
--data-urlencode "q=SELECT * FROM orders WHERE id=1" \
-H "x-api-key: your-api-key"

Example response:

{
"id": 1,
"order_uid": "JHG-9685K",
"status": "processing",
"total_amount": "591.87"
}

The result keeps the original structure and data formats while sensitive values are transformed.

For example:

XTD-1234L → JHG-9685K
Alice → Dkyr

The exact transformed value depends on the configured secret key.

Filtering with production values

You can query using a known production value.

curl -G "http://localhost:8080/query" \
--data-urlencode "q=SELECT * FROM orders WHERE order_uid='XTD-1234L'" \
-H "x-api-key: your-api-key"

PostgreSQL receives the original query and uses the real value to locate the record.

The returned value is transformed:

{
"order_uid": "JHG-9685K",
"status": "processing"
}

Joins

Normal PostgreSQL joins work as supported by PostgreSQL.

SELECT
orders.id,
orders.order_uid,
users.email
FROM orders
JOIN users
ON users.id = orders.user_id
WHERE orders.id = 1;

PostgreSQL executes the query normally. DoubleDino transforms the returned values while preserving their structure and formats.

Deterministic transformation keeps repeated values consistent, so relationships between records remain useful.

JSON and JSONB

PostgreSQL JSON and JSONB fields are transformed recursively, including nested objects and arrays.

For example:

{
"customer": {
"name": "Alice",
"contacts": [
{
"email": "[email protected]"
}
]
}
}

can become:

{
"customer": {
"name": "Dkyr",
"contacts": [
{
"email": "[email protected]"
}
]
}
}

The surrounding JSON structure remains intact.

Preserved expressions

If enabled by your administrator, you can provide additional expressions that should remain unchanged using the x-preserve-expressions header.

curl -G "http://localhost:8080/query" \
--data-urlencode "q=SELECT * FROM orders" \
-H "x-api-key: your-api-key" \
-H "x-preserve-expressions: tracking metadata"

Dynamic expressions are available only when the administrator has enabled:

DD_ALLOW_DYNAMIC_EXPRESSIONS=true

Only use this when you need additional expressions to remain visible. Developers cannot change expressions configured by the administrator.

Response format

Query results are returned as JSON.

A single row:

{
"id": 1,
"name": "Dkyr"
}

Multiple rows:

[
{
"id": 1,
"name": "Dkyr"
},
{
"id": 2,
"name": "Qmrt"
}
]

The response follows the result returned by PostgreSQL.

Read-only

DoubleDino Proxy does not modify the PostgreSQL source.

The query is executed by PostgreSQL, and only the returned result is transformed before it reaches the client.