chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:28:13 +08:00
commit 0878425be3
1160 changed files with 491311 additions and 0 deletions
+268
View File
@@ -0,0 +1,268 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: agentlogs.sql
package database
import (
"context"
"database/sql"
)
const createAgentLog = `-- name: CreateAgentLog :one
INSERT INTO agentlogs (
initiator,
executor,
task,
result,
flow_id,
task_id,
subtask_id
)
VALUES (
$1, $2, $3, $4, $5, $6, $7
)
RETURNING id, initiator, executor, task, result, flow_id, task_id, subtask_id, created_at
`
type CreateAgentLogParams struct {
Initiator MsgchainType `json:"initiator"`
Executor MsgchainType `json:"executor"`
Task string `json:"task"`
Result string `json:"result"`
FlowID int64 `json:"flow_id"`
TaskID sql.NullInt64 `json:"task_id"`
SubtaskID sql.NullInt64 `json:"subtask_id"`
}
func (q *Queries) CreateAgentLog(ctx context.Context, arg CreateAgentLogParams) (Agentlog, error) {
row := q.db.QueryRowContext(ctx, createAgentLog,
arg.Initiator,
arg.Executor,
arg.Task,
arg.Result,
arg.FlowID,
arg.TaskID,
arg.SubtaskID,
)
var i Agentlog
err := row.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Task,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
)
return i, err
}
const getFlowAgentLog = `-- name: GetFlowAgentLog :one
SELECT
al.id, al.initiator, al.executor, al.task, al.result, al.flow_id, al.task_id, al.subtask_id, al.created_at
FROM agentlogs al
INNER JOIN flows f ON al.flow_id = f.id
WHERE al.id = $1 AND al.flow_id = $2 AND f.deleted_at IS NULL
`
type GetFlowAgentLogParams struct {
ID int64 `json:"id"`
FlowID int64 `json:"flow_id"`
}
func (q *Queries) GetFlowAgentLog(ctx context.Context, arg GetFlowAgentLogParams) (Agentlog, error) {
row := q.db.QueryRowContext(ctx, getFlowAgentLog, arg.ID, arg.FlowID)
var i Agentlog
err := row.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Task,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
)
return i, err
}
const getFlowAgentLogs = `-- name: GetFlowAgentLogs :many
SELECT
al.id, al.initiator, al.executor, al.task, al.result, al.flow_id, al.task_id, al.subtask_id, al.created_at
FROM agentlogs al
INNER JOIN flows f ON al.flow_id = f.id
WHERE al.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY al.created_at ASC
`
func (q *Queries) GetFlowAgentLogs(ctx context.Context, flowID int64) ([]Agentlog, error) {
rows, err := q.db.QueryContext(ctx, getFlowAgentLogs, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Agentlog
for rows.Next() {
var i Agentlog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Task,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getSubtaskAgentLogs = `-- name: GetSubtaskAgentLogs :many
SELECT
al.id, al.initiator, al.executor, al.task, al.result, al.flow_id, al.task_id, al.subtask_id, al.created_at
FROM agentlogs al
INNER JOIN flows f ON al.flow_id = f.id
INNER JOIN subtasks s ON al.subtask_id = s.id
WHERE al.subtask_id = $1 AND f.deleted_at IS NULL
ORDER BY al.created_at ASC
`
func (q *Queries) GetSubtaskAgentLogs(ctx context.Context, subtaskID sql.NullInt64) ([]Agentlog, error) {
rows, err := q.db.QueryContext(ctx, getSubtaskAgentLogs, subtaskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Agentlog
for rows.Next() {
var i Agentlog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Task,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTaskAgentLogs = `-- name: GetTaskAgentLogs :many
SELECT
al.id, al.initiator, al.executor, al.task, al.result, al.flow_id, al.task_id, al.subtask_id, al.created_at
FROM agentlogs al
INNER JOIN flows f ON al.flow_id = f.id
INNER JOIN tasks t ON al.task_id = t.id
WHERE al.task_id = $1 AND f.deleted_at IS NULL
ORDER BY al.created_at ASC
`
func (q *Queries) GetTaskAgentLogs(ctx context.Context, taskID sql.NullInt64) ([]Agentlog, error) {
rows, err := q.db.QueryContext(ctx, getTaskAgentLogs, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Agentlog
for rows.Next() {
var i Agentlog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Task,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlowAgentLogs = `-- name: GetUserFlowAgentLogs :many
SELECT
al.id, al.initiator, al.executor, al.task, al.result, al.flow_id, al.task_id, al.subtask_id, al.created_at
FROM agentlogs al
INNER JOIN flows f ON al.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE al.flow_id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL
ORDER BY al.created_at ASC
`
type GetUserFlowAgentLogsParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowAgentLogs(ctx context.Context, arg GetUserFlowAgentLogsParams) ([]Agentlog, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowAgentLogs, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Agentlog
for rows.Next() {
var i Agentlog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Task,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
+332
View File
@@ -0,0 +1,332 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: analytics.sql
package database
import (
"context"
"database/sql"
"github.com/lib/pq"
)
const getAssistantsCountForFlow = `-- name: GetAssistantsCountForFlow :one
SELECT COALESCE(COUNT(id), 0)::bigint AS total_assistants_count
FROM assistants
WHERE flow_id = $1 AND deleted_at IS NULL
`
// Get total count of assistants for a specific flow
func (q *Queries) GetAssistantsCountForFlow(ctx context.Context, flowID int64) (int64, error) {
row := q.db.QueryRowContext(ctx, getAssistantsCountForFlow, flowID)
var total_assistants_count int64
err := row.Scan(&total_assistants_count)
return total_assistants_count, err
}
const getFlowsForPeriodLast3Months = `-- name: GetFlowsForPeriodLast3Months :many
SELECT id, title
FROM flows
WHERE created_at >= NOW() - INTERVAL '90 days' AND deleted_at IS NULL AND user_id = $1
ORDER BY created_at DESC
`
type GetFlowsForPeriodLast3MonthsRow struct {
ID int64 `json:"id"`
Title string `json:"title"`
}
// Get flow IDs created in the last 3 months for analytics
func (q *Queries) GetFlowsForPeriodLast3Months(ctx context.Context, userID int64) ([]GetFlowsForPeriodLast3MonthsRow, error) {
rows, err := q.db.QueryContext(ctx, getFlowsForPeriodLast3Months, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetFlowsForPeriodLast3MonthsRow
for rows.Next() {
var i GetFlowsForPeriodLast3MonthsRow
if err := rows.Scan(&i.ID, &i.Title); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFlowsForPeriodLastMonth = `-- name: GetFlowsForPeriodLastMonth :many
SELECT id, title
FROM flows
WHERE created_at >= NOW() - INTERVAL '30 days' AND deleted_at IS NULL AND user_id = $1
ORDER BY created_at DESC
`
type GetFlowsForPeriodLastMonthRow struct {
ID int64 `json:"id"`
Title string `json:"title"`
}
// Get flow IDs created in the last month for analytics
func (q *Queries) GetFlowsForPeriodLastMonth(ctx context.Context, userID int64) ([]GetFlowsForPeriodLastMonthRow, error) {
rows, err := q.db.QueryContext(ctx, getFlowsForPeriodLastMonth, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetFlowsForPeriodLastMonthRow
for rows.Next() {
var i GetFlowsForPeriodLastMonthRow
if err := rows.Scan(&i.ID, &i.Title); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFlowsForPeriodLastWeek = `-- name: GetFlowsForPeriodLastWeek :many
SELECT id, title
FROM flows
WHERE created_at >= NOW() - INTERVAL '7 days' AND deleted_at IS NULL AND user_id = $1
ORDER BY created_at DESC
`
type GetFlowsForPeriodLastWeekRow struct {
ID int64 `json:"id"`
Title string `json:"title"`
}
// Get flow IDs created in the last week for analytics
func (q *Queries) GetFlowsForPeriodLastWeek(ctx context.Context, userID int64) ([]GetFlowsForPeriodLastWeekRow, error) {
rows, err := q.db.QueryContext(ctx, getFlowsForPeriodLastWeek, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetFlowsForPeriodLastWeekRow
for rows.Next() {
var i GetFlowsForPeriodLastWeekRow
if err := rows.Scan(&i.ID, &i.Title); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getMsgchainsForFlow = `-- name: GetMsgchainsForFlow :many
SELECT id, type, flow_id, task_id, subtask_id, duration_seconds, created_at, updated_at
FROM msgchains
WHERE flow_id = $1
ORDER BY created_at ASC
`
type GetMsgchainsForFlowRow struct {
ID int64 `json:"id"`
Type MsgchainType `json:"type"`
FlowID int64 `json:"flow_id"`
TaskID sql.NullInt64 `json:"task_id"`
SubtaskID sql.NullInt64 `json:"subtask_id"`
DurationSeconds float64 `json:"duration_seconds"`
CreatedAt sql.NullTime `json:"created_at"`
UpdatedAt sql.NullTime `json:"updated_at"`
}
// Get all msgchains for a flow (including task and subtask level)
func (q *Queries) GetMsgchainsForFlow(ctx context.Context, flowID int64) ([]GetMsgchainsForFlowRow, error) {
rows, err := q.db.QueryContext(ctx, getMsgchainsForFlow, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetMsgchainsForFlowRow
for rows.Next() {
var i GetMsgchainsForFlowRow
if err := rows.Scan(
&i.ID,
&i.Type,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.DurationSeconds,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getSubtasksForTasks = `-- name: GetSubtasksForTasks :many
SELECT id, task_id, title, status, created_at, updated_at
FROM subtasks
WHERE task_id = ANY($1::BIGINT[])
ORDER BY id ASC
`
type GetSubtasksForTasksRow struct {
ID int64 `json:"id"`
TaskID int64 `json:"task_id"`
Title string `json:"title"`
Status SubtaskStatus `json:"status"`
CreatedAt sql.NullTime `json:"created_at"`
UpdatedAt sql.NullTime `json:"updated_at"`
}
// Get all subtasks for multiple tasks
func (q *Queries) GetSubtasksForTasks(ctx context.Context, taskIds []int64) ([]GetSubtasksForTasksRow, error) {
rows, err := q.db.QueryContext(ctx, getSubtasksForTasks, pq.Array(taskIds))
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetSubtasksForTasksRow
for rows.Next() {
var i GetSubtasksForTasksRow
if err := rows.Scan(
&i.ID,
&i.TaskID,
&i.Title,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTasksForFlow = `-- name: GetTasksForFlow :many
SELECT id, title, created_at, updated_at
FROM tasks
WHERE flow_id = $1
ORDER BY id ASC
`
type GetTasksForFlowRow struct {
ID int64 `json:"id"`
Title string `json:"title"`
CreatedAt sql.NullTime `json:"created_at"`
UpdatedAt sql.NullTime `json:"updated_at"`
}
// Get all tasks for a flow
func (q *Queries) GetTasksForFlow(ctx context.Context, flowID int64) ([]GetTasksForFlowRow, error) {
rows, err := q.db.QueryContext(ctx, getTasksForFlow, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetTasksForFlowRow
for rows.Next() {
var i GetTasksForFlowRow
if err := rows.Scan(
&i.ID,
&i.Title,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getToolcallsForFlow = `-- name: GetToolcallsForFlow :many
SELECT tc.id, tc.status, tc.flow_id, tc.task_id, tc.subtask_id, tc.duration_seconds, tc.created_at, tc.updated_at
FROM toolcalls tc
LEFT JOIN tasks t ON tc.task_id = t.id
LEFT JOIN subtasks s ON tc.subtask_id = s.id
INNER JOIN flows f ON tc.flow_id = f.id
WHERE tc.flow_id = $1 AND f.deleted_at IS NULL
AND (tc.task_id IS NULL OR t.id IS NOT NULL)
AND (tc.subtask_id IS NULL OR s.id IS NOT NULL)
ORDER BY tc.created_at ASC
`
type GetToolcallsForFlowRow struct {
ID int64 `json:"id"`
Status ToolcallStatus `json:"status"`
FlowID int64 `json:"flow_id"`
TaskID sql.NullInt64 `json:"task_id"`
SubtaskID sql.NullInt64 `json:"subtask_id"`
DurationSeconds float64 `json:"duration_seconds"`
CreatedAt sql.NullTime `json:"created_at"`
UpdatedAt sql.NullTime `json:"updated_at"`
}
// Get all toolcalls for a flow
func (q *Queries) GetToolcallsForFlow(ctx context.Context, flowID int64) ([]GetToolcallsForFlowRow, error) {
rows, err := q.db.QueryContext(ctx, getToolcallsForFlow, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetToolcallsForFlowRow
for rows.Next() {
var i GetToolcallsForFlowRow
if err := rows.Scan(
&i.ID,
&i.Status,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.DurationSeconds,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
@@ -0,0 +1,6 @@
package database
type APITokenWithSecret struct {
ApiToken
Token string `json:"token"`
}
+409
View File
@@ -0,0 +1,409 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: api_tokens.sql
package database
import (
"context"
"database/sql"
)
const createAPIToken = `-- name: CreateAPIToken :one
INSERT INTO api_tokens (
token_id,
user_id,
role_id,
name,
ttl,
status
) VALUES (
$1, $2, $3, $4, $5, $6
)
RETURNING id, token_id, user_id, role_id, name, ttl, status, created_at, updated_at, deleted_at
`
type CreateAPITokenParams struct {
TokenID string `json:"token_id"`
UserID int64 `json:"user_id"`
RoleID int64 `json:"role_id"`
Name sql.NullString `json:"name"`
Ttl int64 `json:"ttl"`
Status TokenStatus `json:"status"`
}
func (q *Queries) CreateAPIToken(ctx context.Context, arg CreateAPITokenParams) (ApiToken, error) {
row := q.db.QueryRowContext(ctx, createAPIToken,
arg.TokenID,
arg.UserID,
arg.RoleID,
arg.Name,
arg.Ttl,
arg.Status,
)
var i ApiToken
err := row.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const deleteAPIToken = `-- name: DeleteAPIToken :one
UPDATE api_tokens
SET deleted_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING id, token_id, user_id, role_id, name, ttl, status, created_at, updated_at, deleted_at
`
func (q *Queries) DeleteAPIToken(ctx context.Context, id int64) (ApiToken, error) {
row := q.db.QueryRowContext(ctx, deleteAPIToken, id)
var i ApiToken
err := row.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const deleteUserAPIToken = `-- name: DeleteUserAPIToken :one
UPDATE api_tokens
SET deleted_at = CURRENT_TIMESTAMP
WHERE id = $1 AND user_id = $2
RETURNING id, token_id, user_id, role_id, name, ttl, status, created_at, updated_at, deleted_at
`
type DeleteUserAPITokenParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) DeleteUserAPIToken(ctx context.Context, arg DeleteUserAPITokenParams) (ApiToken, error) {
row := q.db.QueryRowContext(ctx, deleteUserAPIToken, arg.ID, arg.UserID)
var i ApiToken
err := row.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const deleteUserAPITokenByTokenID = `-- name: DeleteUserAPITokenByTokenID :one
UPDATE api_tokens
SET deleted_at = CURRENT_TIMESTAMP
WHERE token_id = $1 AND user_id = $2
RETURNING id, token_id, user_id, role_id, name, ttl, status, created_at, updated_at, deleted_at
`
type DeleteUserAPITokenByTokenIDParams struct {
TokenID string `json:"token_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) DeleteUserAPITokenByTokenID(ctx context.Context, arg DeleteUserAPITokenByTokenIDParams) (ApiToken, error) {
row := q.db.QueryRowContext(ctx, deleteUserAPITokenByTokenID, arg.TokenID, arg.UserID)
var i ApiToken
err := row.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const getAPIToken = `-- name: GetAPIToken :one
SELECT
t.id, t.token_id, t.user_id, t.role_id, t.name, t.ttl, t.status, t.created_at, t.updated_at, t.deleted_at
FROM api_tokens t
WHERE t.id = $1 AND t.deleted_at IS NULL
`
func (q *Queries) GetAPIToken(ctx context.Context, id int64) (ApiToken, error) {
row := q.db.QueryRowContext(ctx, getAPIToken, id)
var i ApiToken
err := row.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const getAPITokenByTokenID = `-- name: GetAPITokenByTokenID :one
SELECT
t.id, t.token_id, t.user_id, t.role_id, t.name, t.ttl, t.status, t.created_at, t.updated_at, t.deleted_at
FROM api_tokens t
WHERE t.token_id = $1 AND t.deleted_at IS NULL
`
func (q *Queries) GetAPITokenByTokenID(ctx context.Context, tokenID string) (ApiToken, error) {
row := q.db.QueryRowContext(ctx, getAPITokenByTokenID, tokenID)
var i ApiToken
err := row.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const getAPITokens = `-- name: GetAPITokens :many
SELECT
t.id, t.token_id, t.user_id, t.role_id, t.name, t.ttl, t.status, t.created_at, t.updated_at, t.deleted_at
FROM api_tokens t
WHERE t.deleted_at IS NULL
ORDER BY t.created_at DESC
`
func (q *Queries) GetAPITokens(ctx context.Context) ([]ApiToken, error) {
rows, err := q.db.QueryContext(ctx, getAPITokens)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ApiToken
for rows.Next() {
var i ApiToken
if err := rows.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserAPIToken = `-- name: GetUserAPIToken :one
SELECT
t.id, t.token_id, t.user_id, t.role_id, t.name, t.ttl, t.status, t.created_at, t.updated_at, t.deleted_at
FROM api_tokens t
INNER JOIN users u ON t.user_id = u.id
WHERE t.id = $1 AND t.user_id = $2 AND t.deleted_at IS NULL
`
type GetUserAPITokenParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserAPIToken(ctx context.Context, arg GetUserAPITokenParams) (ApiToken, error) {
row := q.db.QueryRowContext(ctx, getUserAPIToken, arg.ID, arg.UserID)
var i ApiToken
err := row.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const getUserAPITokenByTokenID = `-- name: GetUserAPITokenByTokenID :one
SELECT
t.id, t.token_id, t.user_id, t.role_id, t.name, t.ttl, t.status, t.created_at, t.updated_at, t.deleted_at
FROM api_tokens t
INNER JOIN users u ON t.user_id = u.id
WHERE t.token_id = $1 AND t.user_id = $2 AND t.deleted_at IS NULL
`
type GetUserAPITokenByTokenIDParams struct {
TokenID string `json:"token_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserAPITokenByTokenID(ctx context.Context, arg GetUserAPITokenByTokenIDParams) (ApiToken, error) {
row := q.db.QueryRowContext(ctx, getUserAPITokenByTokenID, arg.TokenID, arg.UserID)
var i ApiToken
err := row.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const getUserAPITokens = `-- name: GetUserAPITokens :many
SELECT
t.id, t.token_id, t.user_id, t.role_id, t.name, t.ttl, t.status, t.created_at, t.updated_at, t.deleted_at
FROM api_tokens t
INNER JOIN users u ON t.user_id = u.id
WHERE t.user_id = $1 AND t.deleted_at IS NULL
ORDER BY t.created_at DESC
`
func (q *Queries) GetUserAPITokens(ctx context.Context, userID int64) ([]ApiToken, error) {
rows, err := q.db.QueryContext(ctx, getUserAPITokens, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ApiToken
for rows.Next() {
var i ApiToken
if err := rows.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateAPIToken = `-- name: UpdateAPIToken :one
UPDATE api_tokens
SET name = $2, status = $3
WHERE id = $1
RETURNING id, token_id, user_id, role_id, name, ttl, status, created_at, updated_at, deleted_at
`
type UpdateAPITokenParams struct {
ID int64 `json:"id"`
Name sql.NullString `json:"name"`
Status TokenStatus `json:"status"`
}
func (q *Queries) UpdateAPIToken(ctx context.Context, arg UpdateAPITokenParams) (ApiToken, error) {
row := q.db.QueryRowContext(ctx, updateAPIToken, arg.ID, arg.Name, arg.Status)
var i ApiToken
err := row.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const updateUserAPIToken = `-- name: UpdateUserAPIToken :one
UPDATE api_tokens
SET name = $3, status = $4
WHERE id = $1 AND user_id = $2
RETURNING id, token_id, user_id, role_id, name, ttl, status, created_at, updated_at, deleted_at
`
type UpdateUserAPITokenParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
Name sql.NullString `json:"name"`
Status TokenStatus `json:"status"`
}
func (q *Queries) UpdateUserAPIToken(ctx context.Context, arg UpdateUserAPITokenParams) (ApiToken, error) {
row := q.db.QueryRowContext(ctx, updateUserAPIToken,
arg.ID,
arg.UserID,
arg.Name,
arg.Status,
)
var i ApiToken
err := row.Scan(
&i.ID,
&i.TokenID,
&i.UserID,
&i.RoleID,
&i.Name,
&i.Ttl,
&i.Status,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
+347
View File
@@ -0,0 +1,347 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: assistantlogs.sql
package database
import (
"context"
"database/sql"
)
const createAssistantLog = `-- name: CreateAssistantLog :one
INSERT INTO assistantlogs (
type,
message,
thinking,
flow_id,
assistant_id
)
VALUES (
$1, $2, $3, $4, $5
)
RETURNING id, type, message, result, result_format, flow_id, assistant_id, created_at, thinking
`
type CreateAssistantLogParams struct {
Type MsglogType `json:"type"`
Message string `json:"message"`
Thinking sql.NullString `json:"thinking"`
FlowID int64 `json:"flow_id"`
AssistantID int64 `json:"assistant_id"`
}
func (q *Queries) CreateAssistantLog(ctx context.Context, arg CreateAssistantLogParams) (Assistantlog, error) {
row := q.db.QueryRowContext(ctx, createAssistantLog,
arg.Type,
arg.Message,
arg.Thinking,
arg.FlowID,
arg.AssistantID,
)
var i Assistantlog
err := row.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.ResultFormat,
&i.FlowID,
&i.AssistantID,
&i.CreatedAt,
&i.Thinking,
)
return i, err
}
const createResultAssistantLog = `-- name: CreateResultAssistantLog :one
INSERT INTO assistantlogs (
type,
message,
thinking,
result,
result_format,
flow_id,
assistant_id
)
VALUES (
$1, $2, $3, $4, $5, $6, $7
)
RETURNING id, type, message, result, result_format, flow_id, assistant_id, created_at, thinking
`
type CreateResultAssistantLogParams struct {
Type MsglogType `json:"type"`
Message string `json:"message"`
Thinking sql.NullString `json:"thinking"`
Result string `json:"result"`
ResultFormat MsglogResultFormat `json:"result_format"`
FlowID int64 `json:"flow_id"`
AssistantID int64 `json:"assistant_id"`
}
func (q *Queries) CreateResultAssistantLog(ctx context.Context, arg CreateResultAssistantLogParams) (Assistantlog, error) {
row := q.db.QueryRowContext(ctx, createResultAssistantLog,
arg.Type,
arg.Message,
arg.Thinking,
arg.Result,
arg.ResultFormat,
arg.FlowID,
arg.AssistantID,
)
var i Assistantlog
err := row.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.ResultFormat,
&i.FlowID,
&i.AssistantID,
&i.CreatedAt,
&i.Thinking,
)
return i, err
}
const deleteFlowAssistantLog = `-- name: DeleteFlowAssistantLog :exec
DELETE FROM assistantlogs
WHERE id = $1
`
func (q *Queries) DeleteFlowAssistantLog(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, deleteFlowAssistantLog, id)
return err
}
const getFlowAssistantLog = `-- name: GetFlowAssistantLog :one
SELECT
al.id, al.type, al.message, al.result, al.result_format, al.flow_id, al.assistant_id, al.created_at, al.thinking
FROM assistantlogs al
INNER JOIN assistants a ON al.assistant_id = a.id
INNER JOIN flows f ON al.flow_id = f.id
WHERE al.id = $1 AND f.deleted_at IS NULL AND a.deleted_at IS NULL
`
func (q *Queries) GetFlowAssistantLog(ctx context.Context, id int64) (Assistantlog, error) {
row := q.db.QueryRowContext(ctx, getFlowAssistantLog, id)
var i Assistantlog
err := row.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.ResultFormat,
&i.FlowID,
&i.AssistantID,
&i.CreatedAt,
&i.Thinking,
)
return i, err
}
const getFlowAssistantLogs = `-- name: GetFlowAssistantLogs :many
SELECT
al.id, al.type, al.message, al.result, al.result_format, al.flow_id, al.assistant_id, al.created_at, al.thinking
FROM assistantlogs al
INNER JOIN assistants a ON al.assistant_id = a.id
INNER JOIN flows f ON al.flow_id = f.id
WHERE al.flow_id = $1 AND al.assistant_id = $2 AND f.deleted_at IS NULL AND a.deleted_at IS NULL
ORDER BY al.created_at ASC
`
type GetFlowAssistantLogsParams struct {
FlowID int64 `json:"flow_id"`
AssistantID int64 `json:"assistant_id"`
}
func (q *Queries) GetFlowAssistantLogs(ctx context.Context, arg GetFlowAssistantLogsParams) ([]Assistantlog, error) {
rows, err := q.db.QueryContext(ctx, getFlowAssistantLogs, arg.FlowID, arg.AssistantID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Assistantlog
for rows.Next() {
var i Assistantlog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.ResultFormat,
&i.FlowID,
&i.AssistantID,
&i.CreatedAt,
&i.Thinking,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlowAssistantLogs = `-- name: GetUserFlowAssistantLogs :many
SELECT
al.id, al.type, al.message, al.result, al.result_format, al.flow_id, al.assistant_id, al.created_at, al.thinking
FROM assistantlogs al
INNER JOIN assistants a ON al.assistant_id = a.id
INNER JOIN flows f ON al.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE al.flow_id = $1 AND al.assistant_id = $2 AND f.user_id = $3 AND f.deleted_at IS NULL AND a.deleted_at IS NULL
ORDER BY al.created_at ASC
`
type GetUserFlowAssistantLogsParams struct {
FlowID int64 `json:"flow_id"`
AssistantID int64 `json:"assistant_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowAssistantLogs(ctx context.Context, arg GetUserFlowAssistantLogsParams) ([]Assistantlog, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowAssistantLogs, arg.FlowID, arg.AssistantID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Assistantlog
for rows.Next() {
var i Assistantlog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.ResultFormat,
&i.FlowID,
&i.AssistantID,
&i.CreatedAt,
&i.Thinking,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateAssistantLog = `-- name: UpdateAssistantLog :one
UPDATE assistantlogs
SET type = $1, message = $2, thinking = $3, result = $4, result_format = $5
WHERE id = $6
RETURNING id, type, message, result, result_format, flow_id, assistant_id, created_at, thinking
`
type UpdateAssistantLogParams struct {
Type MsglogType `json:"type"`
Message string `json:"message"`
Thinking sql.NullString `json:"thinking"`
Result string `json:"result"`
ResultFormat MsglogResultFormat `json:"result_format"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateAssistantLog(ctx context.Context, arg UpdateAssistantLogParams) (Assistantlog, error) {
row := q.db.QueryRowContext(ctx, updateAssistantLog,
arg.Type,
arg.Message,
arg.Thinking,
arg.Result,
arg.ResultFormat,
arg.ID,
)
var i Assistantlog
err := row.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.ResultFormat,
&i.FlowID,
&i.AssistantID,
&i.CreatedAt,
&i.Thinking,
)
return i, err
}
const updateAssistantLogContent = `-- name: UpdateAssistantLogContent :one
UPDATE assistantlogs
SET type = $1, message = $2, thinking = $3
WHERE id = $4
RETURNING id, type, message, result, result_format, flow_id, assistant_id, created_at, thinking
`
type UpdateAssistantLogContentParams struct {
Type MsglogType `json:"type"`
Message string `json:"message"`
Thinking sql.NullString `json:"thinking"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateAssistantLogContent(ctx context.Context, arg UpdateAssistantLogContentParams) (Assistantlog, error) {
row := q.db.QueryRowContext(ctx, updateAssistantLogContent,
arg.Type,
arg.Message,
arg.Thinking,
arg.ID,
)
var i Assistantlog
err := row.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.ResultFormat,
&i.FlowID,
&i.AssistantID,
&i.CreatedAt,
&i.Thinking,
)
return i, err
}
const updateAssistantLogResult = `-- name: UpdateAssistantLogResult :one
UPDATE assistantlogs
SET result = $1, result_format = $2
WHERE id = $3
RETURNING id, type, message, result, result_format, flow_id, assistant_id, created_at, thinking
`
type UpdateAssistantLogResultParams struct {
Result string `json:"result"`
ResultFormat MsglogResultFormat `json:"result_format"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateAssistantLogResult(ctx context.Context, arg UpdateAssistantLogResultParams) (Assistantlog, error) {
row := q.db.QueryRowContext(ctx, updateAssistantLogResult, arg.Result, arg.ResultFormat, arg.ID)
var i Assistantlog
err := row.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.ResultFormat,
&i.FlowID,
&i.AssistantID,
&i.CreatedAt,
&i.Thinking,
)
return i, err
}
+591
View File
@@ -0,0 +1,591 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: assistants.sql
package database
import (
"context"
"database/sql"
"encoding/json"
)
const createAssistant = `-- name: CreateAssistant :one
INSERT INTO assistants (
title, status, model, model_provider_name, model_provider_type, language, tool_call_id_template, functions, flow_id, use_agents
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10
)
RETURNING id, status, title, model, model_provider_name, language, functions, trace_id, flow_id, use_agents, msgchain_id, created_at, updated_at, deleted_at, model_provider_type, tool_call_id_template
`
type CreateAssistantParams struct {
Title string `json:"title"`
Status AssistantStatus `json:"status"`
Model string `json:"model"`
ModelProviderName string `json:"model_provider_name"`
ModelProviderType ProviderType `json:"model_provider_type"`
Language string `json:"language"`
ToolCallIDTemplate string `json:"tool_call_id_template"`
Functions json.RawMessage `json:"functions"`
FlowID int64 `json:"flow_id"`
UseAgents bool `json:"use_agents"`
}
func (q *Queries) CreateAssistant(ctx context.Context, arg CreateAssistantParams) (Assistant, error) {
row := q.db.QueryRowContext(ctx, createAssistant,
arg.Title,
arg.Status,
arg.Model,
arg.ModelProviderName,
arg.ModelProviderType,
arg.Language,
arg.ToolCallIDTemplate,
arg.Functions,
arg.FlowID,
arg.UseAgents,
)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const deleteAssistant = `-- name: DeleteAssistant :one
UPDATE assistants
SET deleted_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING id, status, title, model, model_provider_name, language, functions, trace_id, flow_id, use_agents, msgchain_id, created_at, updated_at, deleted_at, model_provider_type, tool_call_id_template
`
func (q *Queries) DeleteAssistant(ctx context.Context, id int64) (Assistant, error) {
row := q.db.QueryRowContext(ctx, deleteAssistant, id)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const getAssistant = `-- name: GetAssistant :one
SELECT
a.id, a.status, a.title, a.model, a.model_provider_name, a.language, a.functions, a.trace_id, a.flow_id, a.use_agents, a.msgchain_id, a.created_at, a.updated_at, a.deleted_at, a.model_provider_type, a.tool_call_id_template
FROM assistants a
WHERE a.id = $1 AND a.deleted_at IS NULL
`
func (q *Queries) GetAssistant(ctx context.Context, id int64) (Assistant, error) {
row := q.db.QueryRowContext(ctx, getAssistant, id)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const getAssistantUseAgents = `-- name: GetAssistantUseAgents :one
SELECT use_agents
FROM assistants
WHERE id = $1 AND deleted_at IS NULL
`
func (q *Queries) GetAssistantUseAgents(ctx context.Context, id int64) (bool, error) {
row := q.db.QueryRowContext(ctx, getAssistantUseAgents, id)
var use_agents bool
err := row.Scan(&use_agents)
return use_agents, err
}
const getFlowAssistant = `-- name: GetFlowAssistant :one
SELECT
a.id, a.status, a.title, a.model, a.model_provider_name, a.language, a.functions, a.trace_id, a.flow_id, a.use_agents, a.msgchain_id, a.created_at, a.updated_at, a.deleted_at, a.model_provider_type, a.tool_call_id_template
FROM assistants a
INNER JOIN flows f ON a.flow_id = f.id
WHERE a.id = $1 AND a.flow_id = $2 AND f.deleted_at IS NULL AND a.deleted_at IS NULL
`
type GetFlowAssistantParams struct {
ID int64 `json:"id"`
FlowID int64 `json:"flow_id"`
}
func (q *Queries) GetFlowAssistant(ctx context.Context, arg GetFlowAssistantParams) (Assistant, error) {
row := q.db.QueryRowContext(ctx, getFlowAssistant, arg.ID, arg.FlowID)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const getFlowAssistants = `-- name: GetFlowAssistants :many
SELECT
a.id, a.status, a.title, a.model, a.model_provider_name, a.language, a.functions, a.trace_id, a.flow_id, a.use_agents, a.msgchain_id, a.created_at, a.updated_at, a.deleted_at, a.model_provider_type, a.tool_call_id_template
FROM assistants a
INNER JOIN flows f ON a.flow_id = f.id
WHERE a.flow_id = $1 AND f.deleted_at IS NULL AND a.deleted_at IS NULL
ORDER BY a.created_at DESC
`
func (q *Queries) GetFlowAssistants(ctx context.Context, flowID int64) ([]Assistant, error) {
rows, err := q.db.QueryContext(ctx, getFlowAssistants, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Assistant
for rows.Next() {
var i Assistant
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlowAssistant = `-- name: GetUserFlowAssistant :one
SELECT
a.id, a.status, a.title, a.model, a.model_provider_name, a.language, a.functions, a.trace_id, a.flow_id, a.use_agents, a.msgchain_id, a.created_at, a.updated_at, a.deleted_at, a.model_provider_type, a.tool_call_id_template
FROM assistants a
INNER JOIN flows f ON a.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE a.id = $1 AND a.flow_id = $2 AND f.user_id = $3 AND f.deleted_at IS NULL AND a.deleted_at IS NULL
`
type GetUserFlowAssistantParams struct {
ID int64 `json:"id"`
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowAssistant(ctx context.Context, arg GetUserFlowAssistantParams) (Assistant, error) {
row := q.db.QueryRowContext(ctx, getUserFlowAssistant, arg.ID, arg.FlowID, arg.UserID)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const getUserFlowAssistants = `-- name: GetUserFlowAssistants :many
SELECT
a.id, a.status, a.title, a.model, a.model_provider_name, a.language, a.functions, a.trace_id, a.flow_id, a.use_agents, a.msgchain_id, a.created_at, a.updated_at, a.deleted_at, a.model_provider_type, a.tool_call_id_template
FROM assistants a
INNER JOIN flows f ON a.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE a.flow_id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL AND a.deleted_at IS NULL
ORDER BY a.created_at DESC
`
type GetUserFlowAssistantsParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowAssistants(ctx context.Context, arg GetUserFlowAssistantsParams) ([]Assistant, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowAssistants, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Assistant
for rows.Next() {
var i Assistant
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateAssistant = `-- name: UpdateAssistant :one
UPDATE assistants
SET title = $1, model = $2, language = $3, tool_call_id_template = $4, functions = $5, trace_id = $6, msgchain_id = $7
WHERE id = $8
RETURNING id, status, title, model, model_provider_name, language, functions, trace_id, flow_id, use_agents, msgchain_id, created_at, updated_at, deleted_at, model_provider_type, tool_call_id_template
`
type UpdateAssistantParams struct {
Title string `json:"title"`
Model string `json:"model"`
Language string `json:"language"`
ToolCallIDTemplate string `json:"tool_call_id_template"`
Functions json.RawMessage `json:"functions"`
TraceID sql.NullString `json:"trace_id"`
MsgchainID sql.NullInt64 `json:"msgchain_id"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateAssistant(ctx context.Context, arg UpdateAssistantParams) (Assistant, error) {
row := q.db.QueryRowContext(ctx, updateAssistant,
arg.Title,
arg.Model,
arg.Language,
arg.ToolCallIDTemplate,
arg.Functions,
arg.TraceID,
arg.MsgchainID,
arg.ID,
)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateAssistantLanguage = `-- name: UpdateAssistantLanguage :one
UPDATE assistants
SET language = $1
WHERE id = $2
RETURNING id, status, title, model, model_provider_name, language, functions, trace_id, flow_id, use_agents, msgchain_id, created_at, updated_at, deleted_at, model_provider_type, tool_call_id_template
`
type UpdateAssistantLanguageParams struct {
Language string `json:"language"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateAssistantLanguage(ctx context.Context, arg UpdateAssistantLanguageParams) (Assistant, error) {
row := q.db.QueryRowContext(ctx, updateAssistantLanguage, arg.Language, arg.ID)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateAssistantModel = `-- name: UpdateAssistantModel :one
UPDATE assistants
SET model = $1
WHERE id = $2
RETURNING id, status, title, model, model_provider_name, language, functions, trace_id, flow_id, use_agents, msgchain_id, created_at, updated_at, deleted_at, model_provider_type, tool_call_id_template
`
type UpdateAssistantModelParams struct {
Model string `json:"model"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateAssistantModel(ctx context.Context, arg UpdateAssistantModelParams) (Assistant, error) {
row := q.db.QueryRowContext(ctx, updateAssistantModel, arg.Model, arg.ID)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateAssistantStatus = `-- name: UpdateAssistantStatus :one
UPDATE assistants
SET status = $1
WHERE id = $2
RETURNING id, status, title, model, model_provider_name, language, functions, trace_id, flow_id, use_agents, msgchain_id, created_at, updated_at, deleted_at, model_provider_type, tool_call_id_template
`
type UpdateAssistantStatusParams struct {
Status AssistantStatus `json:"status"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateAssistantStatus(ctx context.Context, arg UpdateAssistantStatusParams) (Assistant, error) {
row := q.db.QueryRowContext(ctx, updateAssistantStatus, arg.Status, arg.ID)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateAssistantTitle = `-- name: UpdateAssistantTitle :one
UPDATE assistants
SET title = $1
WHERE id = $2
RETURNING id, status, title, model, model_provider_name, language, functions, trace_id, flow_id, use_agents, msgchain_id, created_at, updated_at, deleted_at, model_provider_type, tool_call_id_template
`
type UpdateAssistantTitleParams struct {
Title string `json:"title"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateAssistantTitle(ctx context.Context, arg UpdateAssistantTitleParams) (Assistant, error) {
row := q.db.QueryRowContext(ctx, updateAssistantTitle, arg.Title, arg.ID)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateAssistantToolCallIDTemplate = `-- name: UpdateAssistantToolCallIDTemplate :one
UPDATE assistants
SET tool_call_id_template = $1
WHERE id = $2
RETURNING id, status, title, model, model_provider_name, language, functions, trace_id, flow_id, use_agents, msgchain_id, created_at, updated_at, deleted_at, model_provider_type, tool_call_id_template
`
type UpdateAssistantToolCallIDTemplateParams struct {
ToolCallIDTemplate string `json:"tool_call_id_template"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateAssistantToolCallIDTemplate(ctx context.Context, arg UpdateAssistantToolCallIDTemplateParams) (Assistant, error) {
row := q.db.QueryRowContext(ctx, updateAssistantToolCallIDTemplate, arg.ToolCallIDTemplate, arg.ID)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateAssistantUseAgents = `-- name: UpdateAssistantUseAgents :one
UPDATE assistants
SET use_agents = $1
WHERE id = $2
RETURNING id, status, title, model, model_provider_name, language, functions, trace_id, flow_id, use_agents, msgchain_id, created_at, updated_at, deleted_at, model_provider_type, tool_call_id_template
`
type UpdateAssistantUseAgentsParams struct {
UseAgents bool `json:"use_agents"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateAssistantUseAgents(ctx context.Context, arg UpdateAssistantUseAgentsParams) (Assistant, error) {
row := q.db.QueryRowContext(ctx, updateAssistantUseAgents, arg.UseAgents, arg.ID)
var i Assistant
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.TraceID,
&i.FlowID,
&i.UseAgents,
&i.MsgchainID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
+406
View File
@@ -0,0 +1,406 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: containers.sql
package database
import (
"context"
"database/sql"
)
const createContainer = `-- name: CreateContainer :one
INSERT INTO containers (
type, name, image, status, flow_id, local_id, local_dir
)
VALUES (
$1, $2, $3, $4, $5, $6, $7
)
ON CONFLICT ON CONSTRAINT containers_local_id_unique
DO UPDATE SET
type = EXCLUDED.type,
name = EXCLUDED.name,
image = EXCLUDED.image,
status = EXCLUDED.status,
flow_id = EXCLUDED.flow_id,
local_dir = EXCLUDED.local_dir
RETURNING id, type, name, image, status, local_id, local_dir, flow_id, created_at, updated_at
`
type CreateContainerParams struct {
Type ContainerType `json:"type"`
Name string `json:"name"`
Image string `json:"image"`
Status ContainerStatus `json:"status"`
FlowID int64 `json:"flow_id"`
LocalID sql.NullString `json:"local_id"`
LocalDir sql.NullString `json:"local_dir"`
}
func (q *Queries) CreateContainer(ctx context.Context, arg CreateContainerParams) (Container, error) {
row := q.db.QueryRowContext(ctx, createContainer,
arg.Type,
arg.Name,
arg.Image,
arg.Status,
arg.FlowID,
arg.LocalID,
arg.LocalDir,
)
var i Container
err := row.Scan(
&i.ID,
&i.Type,
&i.Name,
&i.Image,
&i.Status,
&i.LocalID,
&i.LocalDir,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getContainers = `-- name: GetContainers :many
SELECT
c.id, c.type, c.name, c.image, c.status, c.local_id, c.local_dir, c.flow_id, c.created_at, c.updated_at
FROM containers c
INNER JOIN flows f ON c.flow_id = f.id
WHERE f.deleted_at IS NULL
ORDER BY c.created_at DESC
`
func (q *Queries) GetContainers(ctx context.Context) ([]Container, error) {
rows, err := q.db.QueryContext(ctx, getContainers)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Container
for rows.Next() {
var i Container
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Name,
&i.Image,
&i.Status,
&i.LocalID,
&i.LocalDir,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFlowContainers = `-- name: GetFlowContainers :many
SELECT
c.id, c.type, c.name, c.image, c.status, c.local_id, c.local_dir, c.flow_id, c.created_at, c.updated_at
FROM containers c
INNER JOIN flows f ON c.flow_id = f.id
WHERE c.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY c.created_at DESC
`
func (q *Queries) GetFlowContainers(ctx context.Context, flowID int64) ([]Container, error) {
rows, err := q.db.QueryContext(ctx, getFlowContainers, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Container
for rows.Next() {
var i Container
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Name,
&i.Image,
&i.Status,
&i.LocalID,
&i.LocalDir,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFlowPrimaryContainer = `-- name: GetFlowPrimaryContainer :one
SELECT
c.id, c.type, c.name, c.image, c.status, c.local_id, c.local_dir, c.flow_id, c.created_at, c.updated_at
FROM containers c
INNER JOIN flows f ON c.flow_id = f.id
WHERE c.flow_id = $1 AND c.type = 'primary' AND f.deleted_at IS NULL
ORDER BY c.created_at DESC
LIMIT 1
`
func (q *Queries) GetFlowPrimaryContainer(ctx context.Context, flowID int64) (Container, error) {
row := q.db.QueryRowContext(ctx, getFlowPrimaryContainer, flowID)
var i Container
err := row.Scan(
&i.ID,
&i.Type,
&i.Name,
&i.Image,
&i.Status,
&i.LocalID,
&i.LocalDir,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getRunningContainers = `-- name: GetRunningContainers :many
SELECT
c.id, c.type, c.name, c.image, c.status, c.local_id, c.local_dir, c.flow_id, c.created_at, c.updated_at
FROM containers c
INNER JOIN flows f ON c.flow_id = f.id
WHERE c.status = 'running' AND f.deleted_at IS NULL
ORDER BY c.created_at DESC
`
func (q *Queries) GetRunningContainers(ctx context.Context) ([]Container, error) {
rows, err := q.db.QueryContext(ctx, getRunningContainers)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Container
for rows.Next() {
var i Container
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Name,
&i.Image,
&i.Status,
&i.LocalID,
&i.LocalDir,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserContainers = `-- name: GetUserContainers :many
SELECT
c.id, c.type, c.name, c.image, c.status, c.local_id, c.local_dir, c.flow_id, c.created_at, c.updated_at
FROM containers c
INNER JOIN flows f ON c.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE f.user_id = $1 AND f.deleted_at IS NULL
ORDER BY c.created_at DESC
`
func (q *Queries) GetUserContainers(ctx context.Context, userID int64) ([]Container, error) {
rows, err := q.db.QueryContext(ctx, getUserContainers, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Container
for rows.Next() {
var i Container
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Name,
&i.Image,
&i.Status,
&i.LocalID,
&i.LocalDir,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlowContainers = `-- name: GetUserFlowContainers :many
SELECT
c.id, c.type, c.name, c.image, c.status, c.local_id, c.local_dir, c.flow_id, c.created_at, c.updated_at
FROM containers c
INNER JOIN flows f ON c.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE c.flow_id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL
ORDER BY c.created_at DESC
`
type GetUserFlowContainersParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowContainers(ctx context.Context, arg GetUserFlowContainersParams) ([]Container, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowContainers, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Container
for rows.Next() {
var i Container
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Name,
&i.Image,
&i.Status,
&i.LocalID,
&i.LocalDir,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateContainerImage = `-- name: UpdateContainerImage :one
UPDATE containers
SET image = $1
WHERE id = $2
RETURNING id, type, name, image, status, local_id, local_dir, flow_id, created_at, updated_at
`
type UpdateContainerImageParams struct {
Image string `json:"image"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateContainerImage(ctx context.Context, arg UpdateContainerImageParams) (Container, error) {
row := q.db.QueryRowContext(ctx, updateContainerImage, arg.Image, arg.ID)
var i Container
err := row.Scan(
&i.ID,
&i.Type,
&i.Name,
&i.Image,
&i.Status,
&i.LocalID,
&i.LocalDir,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const updateContainerStatus = `-- name: UpdateContainerStatus :one
UPDATE containers
SET status = $1
WHERE id = $2
RETURNING id, type, name, image, status, local_id, local_dir, flow_id, created_at, updated_at
`
type UpdateContainerStatusParams struct {
Status ContainerStatus `json:"status"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateContainerStatus(ctx context.Context, arg UpdateContainerStatusParams) (Container, error) {
row := q.db.QueryRowContext(ctx, updateContainerStatus, arg.Status, arg.ID)
var i Container
err := row.Scan(
&i.ID,
&i.Type,
&i.Name,
&i.Image,
&i.Status,
&i.LocalID,
&i.LocalDir,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const updateContainerStatusLocalID = `-- name: UpdateContainerStatusLocalID :one
UPDATE containers
SET status = $1, local_id = $2
WHERE id = $3
RETURNING id, type, name, image, status, local_id, local_dir, flow_id, created_at, updated_at
`
type UpdateContainerStatusLocalIDParams struct {
Status ContainerStatus `json:"status"`
LocalID sql.NullString `json:"local_id"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateContainerStatusLocalID(ctx context.Context, arg UpdateContainerStatusLocalIDParams) (Container, error) {
row := q.db.QueryRowContext(ctx, updateContainerStatusLocalID, arg.Status, arg.LocalID, arg.ID)
var i Container
err := row.Scan(
&i.ID,
&i.Type,
&i.Name,
&i.Image,
&i.Status,
&i.LocalID,
&i.LocalDir,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
+407
View File
@@ -0,0 +1,407 @@
package converter
import (
"math"
"pentagi/pkg/database"
"pentagi/pkg/graph/model"
"sort"
"time"
)
// ========== Subtask Duration Calculation ==========
// CalculateSubtaskDuration calculates the actual execution duration of a subtask
// Uses linear time (created_at -> updated_at) with compensation for:
// - Subtasks in 'created' or 'waiting' status (returns 0)
// - Running subtasks (returns time from created_at to now)
// - Finished/Failed subtasks (returns time from created_at to updated_at)
// Optionally validates against primary_agent msgchain duration if available
func CalculateSubtaskDuration(subtask database.Subtask, msgchains []database.Msgchain) float64 {
// Ignore subtasks that haven't started or are waiting
if subtask.Status == database.SubtaskStatusCreated || subtask.Status == database.SubtaskStatusWaiting {
return 0
}
// Calculate linear duration
var linearDuration float64
if subtask.Status == database.SubtaskStatusRunning {
// For running subtasks: from created_at to now
linearDuration = time.Since(subtask.CreatedAt.Time).Seconds()
} else {
// For finished/failed: from created_at to updated_at
linearDuration = subtask.UpdatedAt.Time.Sub(subtask.CreatedAt.Time).Seconds()
}
// Try to find primary_agent msgchain for validation
var msgchainDuration float64
for _, mc := range msgchains {
if mc.Type == database.MsgchainTypePrimaryAgent &&
mc.SubtaskID.Valid && mc.SubtaskID.Int64 == subtask.ID {
msgchainDuration += mc.DurationSeconds
}
}
// If msgchain exists, use the minimum (more conservative estimate)
if msgchainDuration > 0 {
return math.Min(linearDuration, msgchainDuration)
}
return linearDuration
}
// SubtaskDurationInfo holds calculated duration info for a subtask
type SubtaskDurationInfo struct {
SubtaskID int64
Duration float64
}
// CalculateSubtasksWithOverlapCompensation calculates duration for each subtask
// accounting for potential overlap in created_at timestamps when subtasks are created in batch
// Returns map of subtask_id -> compensated_duration
func CalculateSubtasksWithOverlapCompensation(subtasks []database.Subtask, msgchains []database.Msgchain) map[int64]float64 {
result := make(map[int64]float64)
if len(subtasks) == 0 {
return result
}
// Sort subtasks by ID (which is monotonic and represents execution order)
sorted := make([]database.Subtask, len(subtasks))
copy(sorted, subtasks)
sort.Slice(sorted, func(i, j int) bool {
return sorted[i].ID < sorted[j].ID
})
var previousEndTime time.Time
for _, subtask := range sorted {
// Skip subtasks that haven't started
if subtask.Status == database.SubtaskStatusCreated || subtask.Status == database.SubtaskStatusWaiting {
result[subtask.ID] = 0
continue
}
// Determine actual start time (compensating for overlap)
startTime := subtask.CreatedAt.Time
if !previousEndTime.IsZero() && startTime.Before(previousEndTime) {
// If current subtask was created before previous one finished,
// use previous end time as start time
startTime = previousEndTime
}
// Determine end time
var endTime time.Time
if subtask.Status == database.SubtaskStatusRunning {
endTime = time.Now()
} else {
endTime = subtask.UpdatedAt.Time
}
// Calculate duration for this subtask
duration := 0.0
if endTime.After(startTime) {
duration = endTime.Sub(startTime).Seconds()
// Validate against sum of all primary_agent msgchains for this subtask
var msgchainDuration float64
for _, mc := range msgchains {
if mc.Type == database.MsgchainTypePrimaryAgent &&
mc.SubtaskID.Valid && mc.SubtaskID.Int64 == subtask.ID {
msgchainDuration += mc.DurationSeconds
}
}
if msgchainDuration > 0 {
duration = math.Min(duration, msgchainDuration)
}
}
result[subtask.ID] = duration
previousEndTime = endTime
}
return result
}
// ========== Task Duration Calculation ==========
// CalculateTaskDuration calculates total task execution time including:
// 1. Generator agent execution (before subtasks)
// 2. All subtasks execution (with overlap compensation)
// 3. Refiner agent executions (between subtasks)
// 4. Task reporter agent execution (after subtasks)
func CalculateTaskDuration(task database.Task, subtasks []database.Subtask, msgchains []database.Msgchain) float64 {
// 1. Calculate subtasks duration with overlap compensation
subtaskDurations := CalculateSubtasksWithOverlapCompensation(subtasks, msgchains)
var subtasksDuration float64
for _, duration := range subtaskDurations {
subtasksDuration += duration
}
// 2. Calculate generator agent duration (runs before subtasks)
generatorDuration := getMsgchainDuration(msgchains, database.MsgchainTypeGenerator, task.ID, nil)
// 3. Calculate total refiner agent duration (runs between subtasks)
refinerDuration := sumMsgchainsDuration(msgchains, database.MsgchainTypeRefiner, task.ID)
// 4. Calculate task reporter agent duration (runs after subtasks)
reporterDuration := getMsgchainDuration(msgchains, database.MsgchainTypeReporter, task.ID, nil)
return subtasksDuration + generatorDuration + refinerDuration + reporterDuration
}
// getMsgchainDuration returns duration of a single msgchain matching criteria
func getMsgchainDuration(msgchains []database.Msgchain, msgType database.MsgchainType, taskID int64, subtaskID *int64) float64 {
for _, mc := range msgchains {
if mc.Type == msgType && mc.TaskID.Valid && mc.TaskID.Int64 == taskID {
// Check subtaskID match if specified
if subtaskID != nil {
if !mc.SubtaskID.Valid || mc.SubtaskID.Int64 != *subtaskID {
continue
}
} else {
// If subtaskID is nil, we want msgchains without subtask_id
if mc.SubtaskID.Valid {
continue
}
}
return mc.DurationSeconds
}
}
return 0
}
// sumMsgchainsDuration returns sum of durations for all msgchains matching criteria
func sumMsgchainsDuration(msgchains []database.Msgchain, msgType database.MsgchainType, taskID int64) float64 {
var total float64
for _, mc := range msgchains {
if mc.Type == msgType && mc.TaskID.Valid && mc.TaskID.Int64 == taskID && !mc.SubtaskID.Valid {
total += mc.DurationSeconds
}
}
return total
}
// ========== Flow Duration Calculation ==========
// CalculateFlowDuration calculates total flow execution time including:
// 1. All tasks duration (which includes generator, subtasks, and refiner)
// 2. Assistant msgchains duration (flow-level, without task binding)
func CalculateFlowDuration(tasks []database.Task, subtasksMap map[int64][]database.Subtask,
msgchainsMap map[int64][]database.Msgchain, assistantMsgchains []database.Msgchain) float64 {
// 1. Calculate total tasks duration
var tasksDuration float64
for _, task := range tasks {
subtasks := subtasksMap[task.ID]
msgchains := msgchainsMap[task.ID]
tasksDuration += CalculateTaskDuration(task, subtasks, msgchains)
}
// 2. Calculate assistant msgchains duration (flow-level operations without task binding)
var assistantDuration float64
for _, mc := range assistantMsgchains {
if mc.Type == database.MsgchainTypeAssistant && !mc.TaskID.Valid && !mc.SubtaskID.Valid {
assistantDuration += mc.DurationSeconds
}
}
return tasksDuration + assistantDuration
}
// ========== Toolcalls Count Calculation ==========
// CountFinishedToolcalls counts only finished and failed toolcalls (excludes created/running)
func CountFinishedToolcalls(toolcalls []database.Toolcall) int {
count := 0
for _, tc := range toolcalls {
if tc.Status == database.ToolcallStatusFinished || tc.Status == database.ToolcallStatusFailed {
count++
}
}
return count
}
// CountFinishedToolcallsForSubtask counts finished toolcalls for a specific subtask
func CountFinishedToolcallsForSubtask(toolcalls []database.Toolcall, subtaskID int64) int {
count := 0
for _, tc := range toolcalls {
if tc.SubtaskID.Valid && tc.SubtaskID.Int64 == subtaskID {
if tc.Status == database.ToolcallStatusFinished || tc.Status == database.ToolcallStatusFailed {
count++
}
}
}
return count
}
// CountFinishedToolcallsForTask counts finished toolcalls for a task (including subtasks)
func CountFinishedToolcallsForTask(toolcalls []database.Toolcall, taskID int64, subtaskIDs []int64) int {
subtaskIDSet := make(map[int64]bool)
for _, id := range subtaskIDs {
subtaskIDSet[id] = true
}
count := 0
for _, tc := range toolcalls {
// Count task-level toolcalls
if tc.TaskID.Valid && tc.TaskID.Int64 == taskID && !tc.SubtaskID.Valid {
if tc.Status == database.ToolcallStatusFinished || tc.Status == database.ToolcallStatusFailed {
count++
}
}
// Count subtask-level toolcalls
if tc.SubtaskID.Valid && subtaskIDSet[tc.SubtaskID.Int64] {
if tc.Status == database.ToolcallStatusFinished || tc.Status == database.ToolcallStatusFailed {
count++
}
}
}
return count
}
// ========== Hierarchical Stats Building ==========
// BuildFlowExecutionStats builds hierarchical execution statistics for a flow
func BuildFlowExecutionStats(flowID int64, flowTitle string, tasks []database.GetTasksForFlowRow,
subtasks []database.GetSubtasksForTasksRow, msgchains []database.GetMsgchainsForFlowRow,
toolcalls []database.GetToolcallsForFlowRow, assistantsCount int) *model.FlowExecutionStats {
// Convert row types to internal structures
subtasksMap := make(map[int64][]database.Subtask)
for _, s := range subtasks {
subtasksMap[s.TaskID] = append(subtasksMap[s.TaskID], database.Subtask{
ID: s.ID,
TaskID: s.TaskID,
Title: s.Title,
Status: s.Status,
CreatedAt: s.CreatedAt,
UpdatedAt: s.UpdatedAt,
})
}
msgchainsMap := make(map[int64][]database.Msgchain)
assistantMsgchains := make([]database.Msgchain, 0)
for _, mc := range msgchains {
msgchain := database.Msgchain{
ID: mc.ID,
Type: mc.Type,
FlowID: mc.FlowID,
TaskID: mc.TaskID,
SubtaskID: mc.SubtaskID,
DurationSeconds: mc.DurationSeconds,
CreatedAt: mc.CreatedAt,
UpdatedAt: mc.UpdatedAt,
}
if mc.TaskID.Valid {
msgchainsMap[mc.TaskID.Int64] = append(msgchainsMap[mc.TaskID.Int64], msgchain)
} else if mc.Type == database.MsgchainTypeAssistant {
// Collect flow-level assistant msgchains
assistantMsgchains = append(assistantMsgchains, msgchain)
}
}
toolcallsMap := make(map[int64][]database.Toolcall)
flowToolcalls := make([]database.Toolcall, 0, len(toolcalls))
for _, tc := range toolcalls {
toolcall := database.Toolcall{
ID: tc.ID,
Status: tc.Status,
FlowID: tc.FlowID,
TaskID: tc.TaskID,
SubtaskID: tc.SubtaskID,
DurationSeconds: tc.DurationSeconds,
CreatedAt: tc.CreatedAt,
UpdatedAt: tc.UpdatedAt,
}
if tc.FlowID == flowID {
flowToolcalls = append(flowToolcalls, toolcall)
}
if tc.TaskID.Valid {
toolcallsMap[tc.TaskID.Int64] = append(toolcallsMap[tc.TaskID.Int64], toolcall)
} else if tc.SubtaskID.Valid {
// Find task for this subtask
for taskID, subs := range subtasksMap {
for _, sub := range subs {
if sub.ID == tc.SubtaskID.Int64 {
toolcallsMap[taskID] = append(toolcallsMap[taskID], toolcall)
break
}
}
}
}
}
// Build task stats
taskStats := make([]*model.TaskExecutionStats, 0, len(tasks))
for _, taskRow := range tasks {
task := database.Task{
ID: taskRow.ID,
Title: taskRow.Title,
CreatedAt: taskRow.CreatedAt,
UpdatedAt: taskRow.UpdatedAt,
}
subs := subtasksMap[task.ID]
mcs := msgchainsMap[task.ID]
tcs := toolcallsMap[task.ID]
// Calculate compensated durations for all subtasks at once
compensatedDurations := CalculateSubtasksWithOverlapCompensation(subs, mcs)
// Build subtask stats using compensated durations
subtaskStats := make([]*model.SubtaskExecutionStats, 0, len(subs))
subtaskIDs := make([]int64, 0, len(subs))
for _, subtask := range subs {
subtaskIDs = append(subtaskIDs, subtask.ID)
duration := compensatedDurations[subtask.ID]
count := CountFinishedToolcallsForSubtask(tcs, subtask.ID)
subtaskStats = append(subtaskStats, &model.SubtaskExecutionStats{
SubtaskID: subtask.ID,
SubtaskTitle: subtask.Title,
TotalDurationSeconds: duration,
TotalToolcallsCount: count,
})
}
// Build task stats
taskDuration := CalculateTaskDuration(task, subs, mcs)
taskCount := CountFinishedToolcallsForTask(tcs, task.ID, subtaskIDs)
taskStats = append(taskStats, &model.TaskExecutionStats{
TaskID: task.ID,
TaskTitle: task.Title,
TotalDurationSeconds: taskDuration,
TotalToolcallsCount: taskCount,
Subtasks: subtaskStats,
})
}
// Build flow stats
tasksInternal := make([]database.Task, len(tasks))
for i, t := range tasks {
tasksInternal[i] = database.Task{
ID: t.ID,
Title: t.Title,
CreatedAt: t.CreatedAt,
UpdatedAt: t.UpdatedAt,
}
}
flowDuration := CalculateFlowDuration(tasksInternal, subtasksMap, msgchainsMap, assistantMsgchains)
flowCount := CountFinishedToolcalls(flowToolcalls)
return &model.FlowExecutionStats{
FlowID: flowID,
FlowTitle: flowTitle,
TotalDurationSeconds: flowDuration,
TotalToolcallsCount: flowCount,
TotalAssistantsCount: assistantsCount,
Tasks: taskStats,
}
}
@@ -0,0 +1,842 @@
package converter
import (
"database/sql"
"math"
"pentagi/pkg/database"
"testing"
"time"
)
// Helper functions for test data creation
func makeSubtask(id int64, status database.SubtaskStatus, createdAt, updatedAt time.Time) database.Subtask {
return database.Subtask{
ID: id,
Status: status,
Title: "Test Subtask",
CreatedAt: sql.NullTime{Time: createdAt, Valid: true},
UpdatedAt: sql.NullTime{Time: updatedAt, Valid: true},
TaskID: 1,
}
}
func makeMsgchain(id int64, msgType database.MsgchainType, taskID int64, subtaskID *int64, createdAt, updatedAt time.Time) database.Msgchain {
mc := database.Msgchain{
ID: id,
Type: msgType,
TaskID: sql.NullInt64{Int64: taskID, Valid: true},
CreatedAt: sql.NullTime{Time: createdAt, Valid: true},
UpdatedAt: sql.NullTime{Time: updatedAt, Valid: true},
DurationSeconds: updatedAt.Sub(createdAt).Seconds(),
}
if subtaskID != nil {
mc.SubtaskID = sql.NullInt64{Int64: *subtaskID, Valid: true}
}
return mc
}
func makeToolcall(id int64, status database.ToolcallStatus, taskID, subtaskID *int64, createdAt, updatedAt time.Time) database.Toolcall {
tc := database.Toolcall{
ID: id,
Status: status,
CreatedAt: sql.NullTime{Time: createdAt, Valid: true},
UpdatedAt: sql.NullTime{Time: updatedAt, Valid: true},
}
// Duration is only set for finished/failed toolcalls
if status == database.ToolcallStatusFinished || status == database.ToolcallStatusFailed {
tc.DurationSeconds = updatedAt.Sub(createdAt).Seconds()
} else {
tc.DurationSeconds = 0
}
if taskID != nil {
tc.TaskID = sql.NullInt64{Int64: *taskID, Valid: true}
}
if subtaskID != nil {
tc.SubtaskID = sql.NullInt64{Int64: *subtaskID, Valid: true}
}
return tc
}
// ========== Subtask Duration Tests ==========
func TestCalculateSubtaskDuration_CreatedStatus(t *testing.T) {
now := time.Now()
subtask := makeSubtask(1, database.SubtaskStatusCreated, now, now.Add(10*time.Second))
duration := CalculateSubtaskDuration(subtask, nil)
if duration != 0 {
t.Errorf("Expected 0 for created subtask, got %f", duration)
}
}
func TestCalculateSubtaskDuration_WaitingStatus(t *testing.T) {
now := time.Now()
subtask := makeSubtask(1, database.SubtaskStatusWaiting, now, now.Add(10*time.Second))
duration := CalculateSubtaskDuration(subtask, nil)
if duration != 0 {
t.Errorf("Expected 0 for waiting subtask, got %f", duration)
}
}
func TestCalculateSubtaskDuration_FinishedStatus(t *testing.T) {
now := time.Now()
subtask := makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(100*time.Second))
duration := CalculateSubtaskDuration(subtask, nil)
if duration < 99 || duration > 101 {
t.Errorf("Expected ~100 seconds, got %f", duration)
}
}
func TestCalculateSubtaskDuration_WithMsgchainValidation(t *testing.T) {
now := time.Now()
subtaskID := int64(1)
// Subtask shows 100 seconds
subtask := makeSubtask(subtaskID, database.SubtaskStatusFinished, now, now.Add(100*time.Second))
// But msgchain shows only 50 seconds (more accurate)
msgchains := []database.Msgchain{
makeMsgchain(1, database.MsgchainTypePrimaryAgent, 1, &subtaskID, now, now.Add(50*time.Second)),
}
duration := CalculateSubtaskDuration(subtask, msgchains)
// Should use minimum (msgchain duration)
if duration < 49 || duration > 51 {
t.Errorf("Expected ~50 seconds (msgchain), got %f", duration)
}
}
// ========== Overlap Compensation Tests ==========
func TestCalculateSubtasksWithOverlapCompensation_NoOverlap(t *testing.T) {
now := time.Now()
subtasks := []database.Subtask{
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
makeSubtask(2, database.SubtaskStatusFinished, now.Add(10*time.Second), now.Add(20*time.Second)),
}
durations := CalculateSubtasksWithOverlapCompensation(subtasks, nil)
// Check individual subtask durations
if durations[1] < 9 || durations[1] > 11 {
t.Errorf("Expected subtask 1 duration ~10s, got %f", durations[1])
}
if durations[2] < 9 || durations[2] > 11 {
t.Errorf("Expected subtask 2 duration ~10s, got %f", durations[2])
}
// Check total
total := durations[1] + durations[2]
expected := 20.0
if total < expected-1 || total > expected+1 {
t.Errorf("Expected total ~%f seconds, got %f", expected, total)
}
}
func TestCalculateSubtasksWithOverlapCompensation_WithOverlap(t *testing.T) {
now := time.Now()
// Both subtasks created at the same time (batch creation)
// but executed sequentially
subtasks := []database.Subtask{
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
makeSubtask(2, database.SubtaskStatusFinished, now, now.Add(20*time.Second)), // Same start time!
}
durations := CalculateSubtasksWithOverlapCompensation(subtasks, nil)
// Subtask 1: should be 10s (no compensation needed)
if durations[1] < 9 || durations[1] > 11 {
t.Errorf("Expected subtask 1 duration ~10s, got %f", durations[1])
}
// Subtask 2: should be 10s (compensated from 20s)
// Original: 10:00:20 - 10:00:00 = 20s
// Compensated: 10:00:20 - 10:00:10 = 10s (starts when subtask 1 finished)
if durations[2] < 9 || durations[2] > 11 {
t.Errorf("Expected subtask 2 duration ~10s (compensated), got %f", durations[2])
}
// Total should be 20s (real wall-clock time)
total := durations[1] + durations[2]
expected := 20.0
if total < expected-1 || total > expected+1 {
t.Errorf("Expected total ~%f seconds (compensated), got %f", expected, total)
}
}
func TestCalculateSubtasksWithOverlapCompensation_IgnoresCreated(t *testing.T) {
now := time.Now()
subtasks := []database.Subtask{
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
makeSubtask(2, database.SubtaskStatusCreated, now, now.Add(100*time.Second)), // Should be ignored
makeSubtask(3, database.SubtaskStatusFinished, now.Add(10*time.Second), now.Add(20*time.Second)),
}
durations := CalculateSubtasksWithOverlapCompensation(subtasks, nil)
// Check created subtask is 0
if durations[2] != 0 {
t.Errorf("Expected created subtask duration 0, got %f", durations[2])
}
// Check finished subtasks
if durations[1] < 9 || durations[1] > 11 {
t.Errorf("Expected subtask 1 duration ~10s, got %f", durations[1])
}
if durations[3] < 9 || durations[3] > 11 {
t.Errorf("Expected subtask 3 duration ~10s, got %f", durations[3])
}
total := durations[1] + durations[2] + durations[3]
expected := 20.0 // Only subtasks 1 and 3
if total < expected-1 || total > expected+1 {
t.Errorf("Expected total ~%f seconds, got %f", expected, total)
}
}
// ========== Task Duration Tests ==========
func TestCalculateTaskDuration_OnlySubtasks(t *testing.T) {
now := time.Now()
task := database.Task{ID: 1}
subtasks := []database.Subtask{
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
}
duration := CalculateTaskDuration(task, subtasks, nil)
expected := 10.0
if duration < expected-1 || duration > expected+1 {
t.Errorf("Expected ~%f seconds, got %f", expected, duration)
}
}
func TestCalculateTaskDuration_WithGenerator(t *testing.T) {
now := time.Now()
task := database.Task{ID: 1}
subtasks := []database.Subtask{
makeSubtask(1, database.SubtaskStatusFinished, now.Add(5*time.Second), now.Add(15*time.Second)),
}
msgchains := []database.Msgchain{
makeMsgchain(1, database.MsgchainTypeGenerator, 1, nil, now, now.Add(5*time.Second)),
}
duration := CalculateTaskDuration(task, subtasks, msgchains)
// 5s generator + 10s subtask = 15s
expected := 15.0
if duration < expected-1 || duration > expected+1 {
t.Errorf("Expected ~%f seconds, got %f", expected, duration)
}
}
func TestCalculateTaskDuration_WithRefiner(t *testing.T) {
now := time.Now()
task := database.Task{ID: 1}
subtasks := []database.Subtask{
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
makeSubtask(2, database.SubtaskStatusFinished, now.Add(13*time.Second), now.Add(23*time.Second)),
}
msgchains := []database.Msgchain{
// Refiner runs between subtasks
makeMsgchain(1, database.MsgchainTypeRefiner, 1, nil, now.Add(10*time.Second), now.Add(13*time.Second)),
}
duration := CalculateTaskDuration(task, subtasks, msgchains)
// 10s subtask1 + 3s refiner + 10s subtask2 = 23s
expected := 23.0
if duration < expected-1 || duration > expected+1 {
t.Errorf("Expected ~%f seconds, got %f", expected, duration)
}
}
// ========== Toolcalls Count Tests ==========
func TestCountFinishedToolcalls(t *testing.T) {
now := time.Now()
toolcalls := []database.Toolcall{
makeToolcall(1, database.ToolcallStatusFinished, nil, nil, now, now.Add(time.Second)),
makeToolcall(2, database.ToolcallStatusFailed, nil, nil, now, now.Add(time.Second)),
makeToolcall(3, database.ToolcallStatusReceived, nil, nil, now, now.Add(time.Second)),
makeToolcall(4, database.ToolcallStatusRunning, nil, nil, now, now.Add(time.Second)),
}
count := CountFinishedToolcalls(toolcalls)
if count != 2 {
t.Errorf("Expected 2 finished toolcalls, got %d", count)
}
}
func TestCountFinishedToolcallsForSubtask(t *testing.T) {
now := time.Now()
subtaskID := int64(1)
otherSubtaskID := int64(2)
toolcalls := []database.Toolcall{
makeToolcall(1, database.ToolcallStatusFinished, nil, &subtaskID, now, now.Add(time.Second)),
makeToolcall(2, database.ToolcallStatusFinished, nil, &otherSubtaskID, now, now.Add(time.Second)),
makeToolcall(3, database.ToolcallStatusReceived, nil, &subtaskID, now, now.Add(time.Second)),
}
count := CountFinishedToolcallsForSubtask(toolcalls, subtaskID)
if count != 1 {
t.Errorf("Expected 1 finished toolcall for subtask, got %d", count)
}
}
func TestCountFinishedToolcallsForTask(t *testing.T) {
now := time.Now()
taskID := int64(1)
subtaskID := int64(1)
toolcalls := []database.Toolcall{
makeToolcall(1, database.ToolcallStatusFinished, &taskID, nil, now, now.Add(time.Second)), // Task-level
makeToolcall(2, database.ToolcallStatusFinished, nil, &subtaskID, now, now.Add(time.Second)), // Subtask-level
makeToolcall(3, database.ToolcallStatusReceived, &taskID, nil, now, now.Add(time.Second)), // Not finished
}
count := CountFinishedToolcallsForTask(toolcalls, taskID, []int64{subtaskID})
if count != 2 {
t.Errorf("Expected 2 finished toolcalls for task, got %d", count)
}
}
// ========== Flow Duration Tests ==========
func TestCalculateFlowDuration_WithTasks(t *testing.T) {
now := time.Now()
tasks := []database.Task{
{ID: 1},
}
subtasksMap := map[int64][]database.Subtask{
1: {
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
},
}
msgchainsMap := map[int64][]database.Msgchain{
1: {},
}
assistantMsgchains := []database.Msgchain{}
duration := CalculateFlowDuration(tasks, subtasksMap, msgchainsMap, assistantMsgchains)
expected := 10.0
if duration < expected-1 || duration > expected+1 {
t.Errorf("Expected ~%f seconds, got %f", expected, duration)
}
}
func TestCalculateFlowDuration_WithAssistantMsgchains(t *testing.T) {
now := time.Now()
tasks := []database.Task{
{ID: 1},
}
subtasksMap := map[int64][]database.Subtask{
1: {
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
},
}
msgchainsMap := map[int64][]database.Msgchain{
1: {},
}
// Assistant msgchains without task/subtask binding (flow-level)
assistantMsgchain := database.Msgchain{
ID: 1,
Type: database.MsgchainTypeAssistant,
FlowID: 1,
TaskID: sql.NullInt64{Valid: false},
SubtaskID: sql.NullInt64{Valid: false},
DurationSeconds: 5.0,
CreatedAt: sql.NullTime{Time: now.Add(20 * time.Second), Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(25 * time.Second), Valid: true},
}
assistantMsgchains := []database.Msgchain{assistantMsgchain}
duration := CalculateFlowDuration(tasks, subtasksMap, msgchainsMap, assistantMsgchains)
expected := 15.0 // 10s task + 5s assistant msgchain
if duration < expected-1 || duration > expected+1 {
t.Errorf("Expected ~%f seconds, got %f", expected, duration)
}
}
func TestCalculateFlowDuration_IgnoresMsgchainsWithTaskOrSubtask(t *testing.T) {
now := time.Now()
taskID := int64(1)
subtaskID := int64(1)
tasks := []database.Task{}
subtasksMap := map[int64][]database.Subtask{}
msgchainsMap := map[int64][]database.Msgchain{}
// These should be ignored in flow-level calculation (have task/subtask binding)
assistantMsgchainWithTask := database.Msgchain{
ID: 1,
Type: database.MsgchainTypeAssistant,
FlowID: 1,
TaskID: sql.NullInt64{Int64: taskID, Valid: true},
SubtaskID: sql.NullInt64{Valid: false},
DurationSeconds: 10.0,
CreatedAt: sql.NullTime{Time: now, Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(10 * time.Second), Valid: true},
}
assistantMsgchainWithSubtask := database.Msgchain{
ID: 2,
Type: database.MsgchainTypeAssistant,
FlowID: 1,
TaskID: sql.NullInt64{Valid: false},
SubtaskID: sql.NullInt64{Int64: subtaskID, Valid: true},
DurationSeconds: 10.0,
CreatedAt: sql.NullTime{Time: now, Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(10 * time.Second), Valid: true},
}
// Only this one should count (no task/subtask binding)
assistantMsgchainFlowLevel := database.Msgchain{
ID: 3,
Type: database.MsgchainTypeAssistant,
FlowID: 1,
TaskID: sql.NullInt64{Valid: false},
SubtaskID: sql.NullInt64{Valid: false},
DurationSeconds: 5.0,
CreatedAt: sql.NullTime{Time: now, Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(5 * time.Second), Valid: true},
}
assistantMsgchains := []database.Msgchain{
assistantMsgchainWithTask,
assistantMsgchainWithSubtask,
assistantMsgchainFlowLevel,
}
duration := CalculateFlowDuration(tasks, subtasksMap, msgchainsMap, assistantMsgchains)
expected := 5.0
if duration < expected-1 || duration > expected+1 {
t.Errorf("Expected ~%f seconds, got %f", expected, duration)
}
}
// ========== Mathematical Correctness Tests ==========
func TestSubtasksSumEqualsTaskSubtasksPart(t *testing.T) {
now := time.Now()
task := database.Task{ID: 1}
// Create subtasks with batch creation (same created_at)
subtasks := []database.Subtask{
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
makeSubtask(2, database.SubtaskStatusFinished, now, now.Add(20*time.Second)),
makeSubtask(3, database.SubtaskStatusFinished, now, now.Add(30*time.Second)),
}
// No generator/refiner for this test
msgchains := []database.Msgchain{}
// Calculate individual subtask durations with compensation
compensatedDurations := CalculateSubtasksWithOverlapCompensation(subtasks, msgchains)
// Sum individual subtask durations
var subtasksSum float64
for _, duration := range compensatedDurations {
subtasksSum += duration
}
// Calculate task duration (should equal subtasks sum since no generator/refiner)
taskDuration := CalculateTaskDuration(task, subtasks, msgchains)
// They should be equal
if math.Abs(subtasksSum-taskDuration) > 0.1 {
t.Errorf("Subtasks sum (%f) should equal task duration (%f)", subtasksSum, taskDuration)
}
}
func TestCompensation_ExtremeBatchCreation(t *testing.T) {
now := time.Now()
// All 5 subtasks created at exactly the same time
// Execute sequentially, 10 seconds each
subtasks := []database.Subtask{
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
makeSubtask(2, database.SubtaskStatusFinished, now, now.Add(20*time.Second)),
makeSubtask(3, database.SubtaskStatusFinished, now, now.Add(30*time.Second)),
makeSubtask(4, database.SubtaskStatusFinished, now, now.Add(40*time.Second)),
makeSubtask(5, database.SubtaskStatusFinished, now, now.Add(50*time.Second)),
}
durations := CalculateSubtasksWithOverlapCompensation(subtasks, nil)
// Each should be ~10 seconds (compensated)
for i := int64(1); i <= 5; i++ {
if durations[i] < 9 || durations[i] > 11 {
t.Errorf("Expected subtask %d duration ~10s, got %f", i, durations[i])
}
}
// Total should be 50s (real wall-clock)
var total float64
for _, d := range durations {
total += d
}
expected := 50.0
if total < expected-1 || total > expected+1 {
t.Errorf("Expected total ~%f seconds, got %f", expected, total)
}
}
func TestCompensation_MixedStatus(t *testing.T) {
now := time.Now()
subtasks := []database.Subtask{
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
makeSubtask(2, database.SubtaskStatusCreated, now, now.Add(100*time.Second)), // Not started
makeSubtask(3, database.SubtaskStatusWaiting, now, now.Add(100*time.Second)), // Waiting
makeSubtask(4, database.SubtaskStatusFinished, now, now.Add(25*time.Second)), // After subtask 1
}
durations := CalculateSubtasksWithOverlapCompensation(subtasks, nil)
// Subtask 1: 10s
if durations[1] < 9 || durations[1] > 11 {
t.Errorf("Expected subtask 1 duration ~10s, got %f", durations[1])
}
// Subtask 2: 0 (created)
if durations[2] != 0 {
t.Errorf("Expected subtask 2 duration 0, got %f", durations[2])
}
// Subtask 3: 0 (waiting)
if durations[3] != 0 {
t.Errorf("Expected subtask 3 duration 0, got %f", durations[3])
}
// Subtask 4: should be compensated to start after subtask 1
// Original: 10:00:25 - 10:00:00 = 25s
// Compensated: 10:00:25 - 10:00:10 = 15s
if durations[4] < 14 || durations[4] > 16 {
t.Errorf("Expected subtask 4 duration ~15s (compensated), got %f", durations[4])
}
}
func TestCompensation_WithMsgchainValidation(t *testing.T) {
now := time.Now()
subtaskID1 := int64(1)
subtaskID2 := int64(2)
subtasks := []database.Subtask{
makeSubtask(1, database.SubtaskStatusFinished, now, now.Add(10*time.Second)),
makeSubtask(2, database.SubtaskStatusFinished, now, now.Add(25*time.Second)), // Overlap
}
// Msgchain for subtask 2 shows it only took 5s (more accurate than compensated 15s)
msgchains := []database.Msgchain{
makeMsgchain(1, database.MsgchainTypePrimaryAgent, 1, &subtaskID1, now, now.Add(10*time.Second)),
makeMsgchain(2, database.MsgchainTypePrimaryAgent, 1, &subtaskID2, now.Add(10*time.Second), now.Add(15*time.Second)),
}
durations := CalculateSubtasksWithOverlapCompensation(subtasks, msgchains)
// Subtask 1: 10s
if durations[1] < 9 || durations[1] > 11 {
t.Errorf("Expected subtask 1 duration ~10s, got %f", durations[1])
}
// Subtask 2: compensated would be 15s, but msgchain shows 5s → use 5s
if durations[2] < 4 || durations[2] > 6 {
t.Errorf("Expected subtask 2 duration ~5s (msgchain), got %f", durations[2])
}
// Total should be 15s (with msgchain validation)
total := durations[1] + durations[2]
expected := 15.0
if total < expected-1 || total > expected+1 {
t.Errorf("Expected total ~%f seconds, got %f", expected, total)
}
}
// ========== Integration Test ==========
func TestBuildFlowExecutionStats_CompleteFlow(t *testing.T) {
now := time.Now()
flowID := int64(1)
flowTitle := "Test Flow"
tasks := []database.GetTasksForFlowRow{
{ID: 1,
Title: "Test Task",
CreatedAt: sql.NullTime{Time: now, Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(10 * time.Second), Valid: true},
},
}
subtaskID := int64(1)
subtasks := []database.GetSubtasksForTasksRow{
{ID: 1,
TaskID: 1,
Title: "Test Subtask",
Status: database.SubtaskStatusFinished,
CreatedAt: sql.NullTime{Time: now, Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(10 * time.Second), Valid: true},
},
}
msgchains := []database.GetMsgchainsForFlowRow{
{
ID: 1,
Type: database.MsgchainTypePrimaryAgent,
FlowID: flowID,
TaskID: sql.NullInt64{Int64: 1, Valid: true},
SubtaskID: sql.NullInt64{Int64: subtaskID, Valid: true},
DurationSeconds: 10.0,
CreatedAt: sql.NullTime{Time: now, Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(10 * time.Second), Valid: true},
},
}
toolcalls := []database.GetToolcallsForFlowRow{
{
ID: 1,
Status: database.ToolcallStatusFinished,
FlowID: flowID,
TaskID: sql.NullInt64{Valid: false},
SubtaskID: sql.NullInt64{Int64: subtaskID, Valid: true},
DurationSeconds: 5.0,
CreatedAt: sql.NullTime{Time: now, Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(5 * time.Second), Valid: true},
},
}
assistantsCount := 2
stats := BuildFlowExecutionStats(flowID, flowTitle, tasks, subtasks, msgchains, toolcalls, assistantsCount)
if stats.FlowID != 1 {
t.Errorf("Expected flow ID 1, got %d", stats.FlowID)
}
if stats.TotalDurationSeconds < 9 || stats.TotalDurationSeconds > 11 {
t.Errorf("Expected ~10 seconds, got %f", stats.TotalDurationSeconds)
}
if stats.TotalToolcallsCount != 1 {
t.Errorf("Expected 1 toolcall, got %d", stats.TotalToolcallsCount)
}
if stats.TotalAssistantsCount != 2 {
t.Errorf("Expected 2 assistants, got %d", stats.TotalAssistantsCount)
}
if len(stats.Tasks) != 1 {
t.Fatalf("Expected 1 task, got %d", len(stats.Tasks))
}
if len(stats.Tasks[0].Subtasks) != 1 {
t.Fatalf("Expected 1 subtask, got %d", len(stats.Tasks[0].Subtasks))
}
}
func TestBuildFlowExecutionStats_MathematicalConsistency(t *testing.T) {
now := time.Now()
flowID := int64(1)
flowTitle := "Test Flow"
tasks := []database.GetTasksForFlowRow{
{ID: 1, Title: "Test Task", CreatedAt: sql.NullTime{Time: now, Valid: true}, UpdatedAt: sql.NullTime{Time: now.Add(100 * time.Second), Valid: true}},
}
// Batch-created subtasks (all created at same time)
subtasks := []database.GetSubtasksForTasksRow{
{ID: 1, TaskID: 1, Title: "Subtask 1", Status: database.SubtaskStatusFinished, CreatedAt: sql.NullTime{Time: now, Valid: true}, UpdatedAt: sql.NullTime{Time: now.Add(10 * time.Second), Valid: true}},
{ID: 2, TaskID: 1, Title: "Subtask 2", Status: database.SubtaskStatusFinished, CreatedAt: sql.NullTime{Time: now, Valid: true}, UpdatedAt: sql.NullTime{Time: now.Add(20 * time.Second), Valid: true}},
{ID: 3, TaskID: 1, Title: "Subtask 3", Status: database.SubtaskStatusFinished, CreatedAt: sql.NullTime{Time: now, Valid: true}, UpdatedAt: sql.NullTime{Time: now.Add(30 * time.Second), Valid: true}},
}
// Generator runs for 5s before subtasks
msgchains := []database.GetMsgchainsForFlowRow{
{
ID: 1,
Type: database.MsgchainTypeGenerator,
FlowID: flowID,
TaskID: sql.NullInt64{Int64: 1, Valid: true},
SubtaskID: sql.NullInt64{Valid: false},
DurationSeconds: 5.0,
CreatedAt: sql.NullTime{Time: now.Add(-5 * time.Second), Valid: true},
UpdatedAt: sql.NullTime{Time: now, Valid: true},
},
}
toolcalls := []database.GetToolcallsForFlowRow{}
assistantsCount := 0
stats := BuildFlowExecutionStats(flowID, flowTitle, tasks, subtasks, msgchains, toolcalls, assistantsCount)
// Critical mathematical consistency check:
// Sum of subtask durations should equal task subtasks part
var subtasksSum float64
for _, subtask := range stats.Tasks[0].Subtasks {
subtasksSum += subtask.TotalDurationSeconds
}
// Task duration should be: subtasks (30s compensated) + generator (5s) = 35s
expectedTaskDuration := 35.0
if stats.Tasks[0].TotalDurationSeconds < expectedTaskDuration-1 || stats.Tasks[0].TotalDurationSeconds > expectedTaskDuration+1 {
t.Errorf("Expected task duration ~%fs, got %f", expectedTaskDuration, stats.Tasks[0].TotalDurationSeconds)
}
// Subtasks sum should be 30s (compensated: 10 + 10 + 10)
expectedSubtasksSum := 30.0
if subtasksSum < expectedSubtasksSum-1 || subtasksSum > expectedSubtasksSum+1 {
t.Errorf("Expected subtasks sum ~%fs, got %f", expectedSubtasksSum, subtasksSum)
}
// Task duration should be >= subtasks sum (includes generator/refiner)
if stats.Tasks[0].TotalDurationSeconds < subtasksSum {
t.Errorf("Task duration (%f) cannot be less than subtasks sum (%f)", stats.Tasks[0].TotalDurationSeconds, subtasksSum)
}
// Flow duration should equal task duration (no flow-level toolcalls in this test)
if math.Abs(stats.TotalDurationSeconds-stats.Tasks[0].TotalDurationSeconds) > 0.1 {
t.Errorf("Flow duration (%f) should equal task duration (%f) with no flow-level toolcalls", stats.TotalDurationSeconds, stats.Tasks[0].TotalDurationSeconds)
}
}
func TestBuildFlowExecutionStats_MultipleTasksWithRefiner(t *testing.T) {
now := time.Now()
flowID := int64(1)
flowTitle := "Complex Flow"
tasks := []database.GetTasksForFlowRow{
{
ID: 1,
Title: "Task 1",
CreatedAt: sql.NullTime{Time: now, Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(50 * time.Second), Valid: true},
},
{
ID: 2,
Title: "Task 2",
CreatedAt: sql.NullTime{Time: now.Add(50 * time.Second), Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(100 * time.Second), Valid: true},
},
}
subtasks := []database.GetSubtasksForTasksRow{
{
ID: 1,
TaskID: 1,
Title: "T1 S1",
Status: database.SubtaskStatusFinished,
CreatedAt: sql.NullTime{Time: now, Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(20 * time.Second), Valid: true},
},
{
ID: 2,
TaskID: 1,
Title: "T1 S2",
Status: database.SubtaskStatusFinished,
CreatedAt: sql.NullTime{Time: now, Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(40 * time.Second), Valid: true},
},
{
ID: 3,
TaskID: 2,
Title: "T2 S1",
Status: database.SubtaskStatusFinished,
CreatedAt: sql.NullTime{Time: now.Add(50 * time.Second), Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(100 * time.Second), Valid: true},
},
}
msgchains := []database.GetMsgchainsForFlowRow{
// Task 1: generator (5s) + refiner between subtasks (5s)
{
ID: 1,
Type: database.MsgchainTypeGenerator,
FlowID: flowID,
TaskID: sql.NullInt64{Int64: 1, Valid: true},
SubtaskID: sql.NullInt64{Valid: false},
DurationSeconds: 5.0,
CreatedAt: sql.NullTime{Time: now.Add(-5 * time.Second), Valid: true},
UpdatedAt: sql.NullTime{Time: now, Valid: true},
},
{
ID: 2,
Type: database.MsgchainTypeRefiner,
FlowID: flowID,
TaskID: sql.NullInt64{Int64: 1, Valid: true},
SubtaskID: sql.NullInt64{Valid: false},
DurationSeconds: 5.0,
CreatedAt: sql.NullTime{Time: now.Add(20 * time.Second), Valid: true},
UpdatedAt: sql.NullTime{Time: now.Add(25 * time.Second), Valid: true},
},
}
toolcalls := []database.GetToolcallsForFlowRow{}
assistantsCount := 1
stats := BuildFlowExecutionStats(flowID, flowTitle, tasks, subtasks, msgchains, toolcalls, assistantsCount)
// Verify we have 2 tasks
if len(stats.Tasks) != 2 {
t.Fatalf("Expected 2 tasks, got %d", len(stats.Tasks))
}
// Task 1: subtasks (20 + 20 compensated = 40s) + generator (5s) + refiner (5s) = 50s
task1Duration := stats.Tasks[0].TotalDurationSeconds
expectedTask1 := 50.0
if task1Duration < expectedTask1-1 || task1Duration > expectedTask1+1 {
t.Errorf("Expected task 1 duration ~%fs, got %f", expectedTask1, task1Duration)
}
// Task 1 subtasks sum should be 40s (compensated)
var task1SubtasksSum float64
for _, subtask := range stats.Tasks[0].Subtasks {
task1SubtasksSum += subtask.TotalDurationSeconds
}
expectedSubtasks1 := 40.0
if task1SubtasksSum < expectedSubtasks1-1 || task1SubtasksSum > expectedSubtasks1+1 {
t.Errorf("Expected task 1 subtasks sum ~%fs, got %f", expectedSubtasks1, task1SubtasksSum)
}
// Task 1 duration should be: subtasks + generator + refiner
if task1Duration < task1SubtasksSum {
t.Errorf("Task 1 duration (%f) should be >= subtasks sum (%f)", task1Duration, task1SubtasksSum)
}
}
// ========== Integration Test ==========
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,58 @@
package converter
import (
"testing"
)
func TestIsAgentTool(t *testing.T) {
tests := []struct {
name string
functionName string
expected bool
}{
// Agent tools
{"coder is agent", "coder", true},
{"pentester is agent", "pentester", true},
{"maintenance is agent", "maintenance", true},
{"memorist is agent", "memorist", true},
{"search is agent", "search", true},
{"advice is agent", "advice", true},
// Agent result tools (also agents)
{"coder_result is agent", "code_result", true},
{"hack_result is agent", "hack_result", true},
{"maintenance_result is agent", "maintenance_result", true},
{"memorist_result is agent", "memorist_result", true},
{"search_result is agent", "search_result", true},
{"enricher_result is agent", "enricher_result", true},
{"report_result is agent", "report_result", true},
{"subtask_list is agent", "subtask_list", true},
{"subtask_patch is agent", "subtask_patch", true},
// Non-agent tools
{"terminal is not agent", "terminal", false},
{"file is not agent", "file", false},
{"browser is not agent", "browser", false},
{"google is not agent", "google", false},
{"duckduckgo is not agent", "duckduckgo", false},
{"tavily is not agent", "tavily", false},
{"sploitus is not agent", "sploitus", false},
{"searxng is not agent", "searxng", false},
{"search_in_memory is not agent", "search_in_memory", false},
{"store_guide is not agent", "store_guide", false},
{"done is not agent", "done", false},
{"ask is not agent", "ask", false},
// Unknown tool
{"unknown tool is not agent", "unknown_tool", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := isAgentTool(tt.functionName)
if result != tt.expected {
t.Errorf("isAgentTool(%q) = %v, want %v", tt.functionName, result, tt.expected)
}
})
}
}
+138
View File
@@ -0,0 +1,138 @@
package database
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"unicode/utf8"
obs "pentagi/pkg/observability"
"github.com/jinzhu/gorm"
"github.com/sirupsen/logrus"
)
func NullStringToPtrString(s sql.NullString) *string {
if s.Valid {
return &s.String
}
return nil
}
func PtrStringToNullString(s *string) sql.NullString {
if s == nil {
return sql.NullString{Valid: false}
}
return sql.NullString{String: *s, Valid: true}
}
func StringToNullString(s string) sql.NullString {
return sql.NullString{String: s, Valid: s != ""}
}
func Int64ToNullInt64(i *int64) sql.NullInt64 {
if i == nil {
return sql.NullInt64{Valid: false}
}
return sql.NullInt64{Int64: *i, Valid: true}
}
func Uint64ToNullInt64(i *uint64) sql.NullInt64 {
if i == nil {
return sql.NullInt64{Int64: 0, Valid: false}
}
return sql.NullInt64{Int64: int64(*i), Valid: true}
}
func NullInt64ToInt64(i sql.NullInt64) *int64 {
if i.Valid {
return &i.Int64
}
return nil
}
func TimeToNullTime(t time.Time) sql.NullTime {
return sql.NullTime{Time: t, Valid: !t.IsZero()}
}
func PtrTimeToNullTime(t *time.Time) sql.NullTime {
if t == nil {
return sql.NullTime{Valid: false}
}
return sql.NullTime{Time: *t, Valid: true}
}
func SanitizeUTF8(msg string) string {
if msg == "" {
return ""
}
var builder strings.Builder
builder.Grow(len(msg)) // Pre-allocate for efficiency
for i := 0; i < len(msg); {
// Explicitly skip null bytes
if msg[i] == '\x00' {
i++
continue
}
// Decode rune and check for errors
r, size := utf8.DecodeRuneInString(msg[i:])
if r == utf8.RuneError && size == 1 {
// Invalid UTF-8 byte, replace with Unicode replacement character
builder.WriteRune(utf8.RuneError)
i += size
} else {
builder.WriteRune(r)
i += size
}
}
return builder.String()
}
type GormLogger struct{}
func (*GormLogger) Print(v ...interface{}) {
ctx, span := obs.Observer.NewSpan(context.TODO(), obs.SpanKindInternal, "gorm.print")
defer span.End()
switch v[0] {
case "sql":
query := fmt.Sprintf("%v", v[3])
values := v[4].([]interface{})
for i, val := range values {
query = strings.Replace(query, fmt.Sprintf("$%d", i+1), fmt.Sprintf("'%v'", val), 1)
}
logrus.WithContext(ctx).WithFields(
logrus.Fields{
"component": "pentagi-gorm",
"type": "sql",
"rows_returned": v[5],
"src": v[1],
"values": v[4],
"duration": v[2],
},
).Info(query)
case "log":
logrus.WithContext(ctx).WithFields(logrus.Fields{"component": "pentagi-gorm"}).Info(v[2])
case "info":
// do not log validators
}
}
// NewGorm creates a GORM instance backed by the provided *sql.DB.
// Passing an existing db ensures GORM shares the same connection pool as
// the sqlc Queries client, so the two clients together consume at most
// DBMaxOpenConns connections instead of doubling the Postgres load.
func NewGorm(db *sql.DB, debug bool) (*gorm.DB, error) {
orm, err := gorm.Open("postgres", db)
if err != nil {
return nil, err
}
orm.SetLogger(&GormLogger{})
orm.LogMode(debug)
return orm, nil
}
+31
View File
@@ -0,0 +1,31 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
package database
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
}
}
+153
View File
@@ -0,0 +1,153 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: flow_templates.sql
package database
import (
"context"
)
const createFlowTemplate = `-- name: CreateFlowTemplate :one
INSERT INTO flow_templates (
user_id,
title,
text
) VALUES (
$1,
$2,
$3
)
RETURNING id, user_id, title, text, created_at, updated_at
`
type CreateFlowTemplateParams struct {
UserID int64 `json:"user_id"`
Title string `json:"title"`
Text string `json:"text"`
}
func (q *Queries) CreateFlowTemplate(ctx context.Context, arg CreateFlowTemplateParams) (FlowTemplate, error) {
row := q.db.QueryRowContext(ctx, createFlowTemplate, arg.UserID, arg.Title, arg.Text)
var i FlowTemplate
err := row.Scan(
&i.ID,
&i.UserID,
&i.Title,
&i.Text,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const deleteFlowTemplate = `-- name: DeleteFlowTemplate :exec
DELETE FROM flow_templates
WHERE id = $1 AND user_id = $2
`
type DeleteFlowTemplateParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) DeleteFlowTemplate(ctx context.Context, arg DeleteFlowTemplateParams) error {
_, err := q.db.ExecContext(ctx, deleteFlowTemplate, arg.ID, arg.UserID)
return err
}
const getFlowTemplate = `-- name: GetFlowTemplate :one
SELECT id, user_id, title, text, created_at, updated_at FROM flow_templates
WHERE id = $1 AND user_id = $2 LIMIT 1
`
type GetFlowTemplateParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetFlowTemplate(ctx context.Context, arg GetFlowTemplateParams) (FlowTemplate, error) {
row := q.db.QueryRowContext(ctx, getFlowTemplate, arg.ID, arg.UserID)
var i FlowTemplate
err := row.Scan(
&i.ID,
&i.UserID,
&i.Title,
&i.Text,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getFlowTemplatesByUserID = `-- name: GetFlowTemplatesByUserID :many
SELECT id, user_id, title, text, created_at, updated_at FROM flow_templates
WHERE user_id = $1
ORDER BY created_at DESC
`
func (q *Queries) GetFlowTemplatesByUserID(ctx context.Context, userID int64) ([]FlowTemplate, error) {
rows, err := q.db.QueryContext(ctx, getFlowTemplatesByUserID, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []FlowTemplate
for rows.Next() {
var i FlowTemplate
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Title,
&i.Text,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateFlowTemplate = `-- name: UpdateFlowTemplate :one
UPDATE flow_templates
SET
title = $3,
text = $4
WHERE id = $1 AND user_id = $2
RETURNING id, user_id, title, text, created_at, updated_at
`
type UpdateFlowTemplateParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
Title string `json:"title"`
Text string `json:"text"`
}
func (q *Queries) UpdateFlowTemplate(ctx context.Context, arg UpdateFlowTemplateParams) (FlowTemplate, error) {
row := q.db.QueryRowContext(ctx, updateFlowTemplate,
arg.ID,
arg.UserID,
arg.Title,
arg.Text,
)
var i FlowTemplate
err := row.Scan(
&i.ID,
&i.UserID,
&i.Title,
&i.Text,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
+702
View File
@@ -0,0 +1,702 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: flows.sql
package database
import (
"context"
"database/sql"
"encoding/json"
"time"
)
const createFlow = `-- name: CreateFlow :one
INSERT INTO flows (
title, status, model, model_provider_name, model_provider_type, language, tool_call_id_template, functions, user_id
)
VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9
)
RETURNING id, status, title, model, model_provider_name, language, functions, user_id, created_at, updated_at, deleted_at, trace_id, model_provider_type, tool_call_id_template
`
type CreateFlowParams struct {
Title string `json:"title"`
Status FlowStatus `json:"status"`
Model string `json:"model"`
ModelProviderName string `json:"model_provider_name"`
ModelProviderType ProviderType `json:"model_provider_type"`
Language string `json:"language"`
ToolCallIDTemplate string `json:"tool_call_id_template"`
Functions json.RawMessage `json:"functions"`
UserID int64 `json:"user_id"`
}
func (q *Queries) CreateFlow(ctx context.Context, arg CreateFlowParams) (Flow, error) {
row := q.db.QueryRowContext(ctx, createFlow,
arg.Title,
arg.Status,
arg.Model,
arg.ModelProviderName,
arg.ModelProviderType,
arg.Language,
arg.ToolCallIDTemplate,
arg.Functions,
arg.UserID,
)
var i Flow
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const deleteFlow = `-- name: DeleteFlow :one
UPDATE flows
SET deleted_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING id, status, title, model, model_provider_name, language, functions, user_id, created_at, updated_at, deleted_at, trace_id, model_provider_type, tool_call_id_template
`
func (q *Queries) DeleteFlow(ctx context.Context, id int64) (Flow, error) {
row := q.db.QueryRowContext(ctx, deleteFlow, id)
var i Flow
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const getFlow = `-- name: GetFlow :one
SELECT
f.id, f.status, f.title, f.model, f.model_provider_name, f.language, f.functions, f.user_id, f.created_at, f.updated_at, f.deleted_at, f.trace_id, f.model_provider_type, f.tool_call_id_template
FROM flows f
WHERE f.id = $1 AND f.deleted_at IS NULL
`
func (q *Queries) GetFlow(ctx context.Context, id int64) (Flow, error) {
row := q.db.QueryRowContext(ctx, getFlow, id)
var i Flow
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const getFlowStats = `-- name: GetFlowStats :one
SELECT
COALESCE(COUNT(DISTINCT t.id), 0)::bigint AS total_tasks_count,
COALESCE(COUNT(DISTINCT s.id), 0)::bigint AS total_subtasks_count,
COALESCE(COUNT(DISTINCT a.id), 0)::bigint AS total_assistants_count
FROM flows f
LEFT JOIN tasks t ON f.id = t.flow_id
LEFT JOIN subtasks s ON t.id = s.task_id
LEFT JOIN assistants a ON f.id = a.flow_id AND a.deleted_at IS NULL
WHERE f.id = $1 AND f.deleted_at IS NULL
`
type GetFlowStatsRow struct {
TotalTasksCount int64 `json:"total_tasks_count"`
TotalSubtasksCount int64 `json:"total_subtasks_count"`
TotalAssistantsCount int64 `json:"total_assistants_count"`
}
// ==================== Flows Analytics Queries ====================
// Get total count of tasks, subtasks, and assistants for a specific flow
func (q *Queries) GetFlowStats(ctx context.Context, id int64) (GetFlowStatsRow, error) {
row := q.db.QueryRowContext(ctx, getFlowStats, id)
var i GetFlowStatsRow
err := row.Scan(&i.TotalTasksCount, &i.TotalSubtasksCount, &i.TotalAssistantsCount)
return i, err
}
const getFlows = `-- name: GetFlows :many
SELECT
f.id, f.status, f.title, f.model, f.model_provider_name, f.language, f.functions, f.user_id, f.created_at, f.updated_at, f.deleted_at, f.trace_id, f.model_provider_type, f.tool_call_id_template
FROM flows f
WHERE f.deleted_at IS NULL
ORDER BY f.created_at DESC
`
func (q *Queries) GetFlows(ctx context.Context) ([]Flow, error) {
rows, err := q.db.QueryContext(ctx, getFlows)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Flow
for rows.Next() {
var i Flow
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFlowsStatsByDayLast3Months = `-- name: GetFlowsStatsByDayLast3Months :many
SELECT
DATE(f.created_at) AS date,
COALESCE(COUNT(DISTINCT f.id), 0)::bigint AS total_flows_count,
COALESCE(COUNT(DISTINCT t.id), 0)::bigint AS total_tasks_count,
COALESCE(COUNT(DISTINCT s.id), 0)::bigint AS total_subtasks_count,
COALESCE(COUNT(DISTINCT a.id), 0)::bigint AS total_assistants_count
FROM flows f
LEFT JOIN tasks t ON f.id = t.flow_id
LEFT JOIN subtasks s ON t.id = s.task_id
LEFT JOIN assistants a ON f.id = a.flow_id AND a.deleted_at IS NULL
WHERE f.created_at >= NOW() - INTERVAL '90 days' AND f.deleted_at IS NULL AND f.user_id = $1
GROUP BY DATE(f.created_at)
ORDER BY date DESC
`
type GetFlowsStatsByDayLast3MonthsRow struct {
Date time.Time `json:"date"`
TotalFlowsCount int64 `json:"total_flows_count"`
TotalTasksCount int64 `json:"total_tasks_count"`
TotalSubtasksCount int64 `json:"total_subtasks_count"`
TotalAssistantsCount int64 `json:"total_assistants_count"`
}
// Get flows stats by day for the last 3 months
func (q *Queries) GetFlowsStatsByDayLast3Months(ctx context.Context, userID int64) ([]GetFlowsStatsByDayLast3MonthsRow, error) {
rows, err := q.db.QueryContext(ctx, getFlowsStatsByDayLast3Months, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetFlowsStatsByDayLast3MonthsRow
for rows.Next() {
var i GetFlowsStatsByDayLast3MonthsRow
if err := rows.Scan(
&i.Date,
&i.TotalFlowsCount,
&i.TotalTasksCount,
&i.TotalSubtasksCount,
&i.TotalAssistantsCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFlowsStatsByDayLastMonth = `-- name: GetFlowsStatsByDayLastMonth :many
SELECT
DATE(f.created_at) AS date,
COALESCE(COUNT(DISTINCT f.id), 0)::bigint AS total_flows_count,
COALESCE(COUNT(DISTINCT t.id), 0)::bigint AS total_tasks_count,
COALESCE(COUNT(DISTINCT s.id), 0)::bigint AS total_subtasks_count,
COALESCE(COUNT(DISTINCT a.id), 0)::bigint AS total_assistants_count
FROM flows f
LEFT JOIN tasks t ON f.id = t.flow_id
LEFT JOIN subtasks s ON t.id = s.task_id
LEFT JOIN assistants a ON f.id = a.flow_id AND a.deleted_at IS NULL
WHERE f.created_at >= NOW() - INTERVAL '30 days' AND f.deleted_at IS NULL AND f.user_id = $1
GROUP BY DATE(f.created_at)
ORDER BY date DESC
`
type GetFlowsStatsByDayLastMonthRow struct {
Date time.Time `json:"date"`
TotalFlowsCount int64 `json:"total_flows_count"`
TotalTasksCount int64 `json:"total_tasks_count"`
TotalSubtasksCount int64 `json:"total_subtasks_count"`
TotalAssistantsCount int64 `json:"total_assistants_count"`
}
// Get flows stats by day for the last month
func (q *Queries) GetFlowsStatsByDayLastMonth(ctx context.Context, userID int64) ([]GetFlowsStatsByDayLastMonthRow, error) {
rows, err := q.db.QueryContext(ctx, getFlowsStatsByDayLastMonth, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetFlowsStatsByDayLastMonthRow
for rows.Next() {
var i GetFlowsStatsByDayLastMonthRow
if err := rows.Scan(
&i.Date,
&i.TotalFlowsCount,
&i.TotalTasksCount,
&i.TotalSubtasksCount,
&i.TotalAssistantsCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFlowsStatsByDayLastWeek = `-- name: GetFlowsStatsByDayLastWeek :many
SELECT
DATE(f.created_at) AS date,
COALESCE(COUNT(DISTINCT f.id), 0)::bigint AS total_flows_count,
COALESCE(COUNT(DISTINCT t.id), 0)::bigint AS total_tasks_count,
COALESCE(COUNT(DISTINCT s.id), 0)::bigint AS total_subtasks_count,
COALESCE(COUNT(DISTINCT a.id), 0)::bigint AS total_assistants_count
FROM flows f
LEFT JOIN tasks t ON f.id = t.flow_id
LEFT JOIN subtasks s ON t.id = s.task_id
LEFT JOIN assistants a ON f.id = a.flow_id AND a.deleted_at IS NULL
WHERE f.created_at >= NOW() - INTERVAL '7 days' AND f.deleted_at IS NULL AND f.user_id = $1
GROUP BY DATE(f.created_at)
ORDER BY date DESC
`
type GetFlowsStatsByDayLastWeekRow struct {
Date time.Time `json:"date"`
TotalFlowsCount int64 `json:"total_flows_count"`
TotalTasksCount int64 `json:"total_tasks_count"`
TotalSubtasksCount int64 `json:"total_subtasks_count"`
TotalAssistantsCount int64 `json:"total_assistants_count"`
}
// Get flows stats by day for the last week
func (q *Queries) GetFlowsStatsByDayLastWeek(ctx context.Context, userID int64) ([]GetFlowsStatsByDayLastWeekRow, error) {
rows, err := q.db.QueryContext(ctx, getFlowsStatsByDayLastWeek, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetFlowsStatsByDayLastWeekRow
for rows.Next() {
var i GetFlowsStatsByDayLastWeekRow
if err := rows.Scan(
&i.Date,
&i.TotalFlowsCount,
&i.TotalTasksCount,
&i.TotalSubtasksCount,
&i.TotalAssistantsCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlow = `-- name: GetUserFlow :one
SELECT
f.id, f.status, f.title, f.model, f.model_provider_name, f.language, f.functions, f.user_id, f.created_at, f.updated_at, f.deleted_at, f.trace_id, f.model_provider_type, f.tool_call_id_template
FROM flows f
INNER JOIN users u ON f.user_id = u.id
WHERE f.id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL
`
type GetUserFlowParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlow(ctx context.Context, arg GetUserFlowParams) (Flow, error) {
row := q.db.QueryRowContext(ctx, getUserFlow, arg.ID, arg.UserID)
var i Flow
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const getUserFlows = `-- name: GetUserFlows :many
SELECT
f.id, f.status, f.title, f.model, f.model_provider_name, f.language, f.functions, f.user_id, f.created_at, f.updated_at, f.deleted_at, f.trace_id, f.model_provider_type, f.tool_call_id_template
FROM flows f
INNER JOIN users u ON f.user_id = u.id
WHERE f.user_id = $1 AND f.deleted_at IS NULL
ORDER BY f.created_at DESC
`
func (q *Queries) GetUserFlows(ctx context.Context, userID int64) ([]Flow, error) {
rows, err := q.db.QueryContext(ctx, getUserFlows, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Flow
for rows.Next() {
var i Flow
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserTotalFlowsStats = `-- name: GetUserTotalFlowsStats :one
SELECT
COALESCE(COUNT(DISTINCT f.id), 0)::bigint AS total_flows_count,
COALESCE(COUNT(DISTINCT t.id), 0)::bigint AS total_tasks_count,
COALESCE(COUNT(DISTINCT s.id), 0)::bigint AS total_subtasks_count,
COALESCE(COUNT(DISTINCT a.id), 0)::bigint AS total_assistants_count
FROM flows f
LEFT JOIN tasks t ON f.id = t.flow_id
LEFT JOIN subtasks s ON t.id = s.task_id
LEFT JOIN assistants a ON f.id = a.flow_id AND a.deleted_at IS NULL
WHERE f.user_id = $1 AND f.deleted_at IS NULL
`
type GetUserTotalFlowsStatsRow struct {
TotalFlowsCount int64 `json:"total_flows_count"`
TotalTasksCount int64 `json:"total_tasks_count"`
TotalSubtasksCount int64 `json:"total_subtasks_count"`
TotalAssistantsCount int64 `json:"total_assistants_count"`
}
// Get total count of flows, tasks, subtasks, and assistants for a user
func (q *Queries) GetUserTotalFlowsStats(ctx context.Context, userID int64) (GetUserTotalFlowsStatsRow, error) {
row := q.db.QueryRowContext(ctx, getUserTotalFlowsStats, userID)
var i GetUserTotalFlowsStatsRow
err := row.Scan(
&i.TotalFlowsCount,
&i.TotalTasksCount,
&i.TotalSubtasksCount,
&i.TotalAssistantsCount,
)
return i, err
}
const updateFlow = `-- name: UpdateFlow :one
UPDATE flows
SET title = $1, model = $2, language = $3, tool_call_id_template = $4, functions = $5, trace_id = $6
WHERE id = $7
RETURNING id, status, title, model, model_provider_name, language, functions, user_id, created_at, updated_at, deleted_at, trace_id, model_provider_type, tool_call_id_template
`
type UpdateFlowParams struct {
Title string `json:"title"`
Model string `json:"model"`
Language string `json:"language"`
ToolCallIDTemplate string `json:"tool_call_id_template"`
Functions json.RawMessage `json:"functions"`
TraceID sql.NullString `json:"trace_id"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateFlow(ctx context.Context, arg UpdateFlowParams) (Flow, error) {
row := q.db.QueryRowContext(ctx, updateFlow,
arg.Title,
arg.Model,
arg.Language,
arg.ToolCallIDTemplate,
arg.Functions,
arg.TraceID,
arg.ID,
)
var i Flow
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateFlowLanguage = `-- name: UpdateFlowLanguage :one
UPDATE flows
SET language = $1
WHERE id = $2
RETURNING id, status, title, model, model_provider_name, language, functions, user_id, created_at, updated_at, deleted_at, trace_id, model_provider_type, tool_call_id_template
`
type UpdateFlowLanguageParams struct {
Language string `json:"language"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateFlowLanguage(ctx context.Context, arg UpdateFlowLanguageParams) (Flow, error) {
row := q.db.QueryRowContext(ctx, updateFlowLanguage, arg.Language, arg.ID)
var i Flow
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateFlowProvider = `-- name: UpdateFlowProvider :one
UPDATE flows
SET model_provider_name = $1, model_provider_type = $2, tool_call_id_template = $3, model = $4
WHERE id = $5
RETURNING id, status, title, model, model_provider_name, language, functions, user_id, created_at, updated_at, deleted_at, trace_id, model_provider_type, tool_call_id_template
`
type UpdateFlowProviderParams struct {
ModelProviderName string `json:"model_provider_name"`
ModelProviderType ProviderType `json:"model_provider_type"`
ToolCallIDTemplate string `json:"tool_call_id_template"`
Model string `json:"model"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateFlowProvider(ctx context.Context, arg UpdateFlowProviderParams) (Flow, error) {
row := q.db.QueryRowContext(ctx, updateFlowProvider,
arg.ModelProviderName,
arg.ModelProviderType,
arg.ToolCallIDTemplate,
arg.Model,
arg.ID,
)
var i Flow
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateFlowStatus = `-- name: UpdateFlowStatus :one
UPDATE flows
SET status = $1
WHERE id = $2
RETURNING id, status, title, model, model_provider_name, language, functions, user_id, created_at, updated_at, deleted_at, trace_id, model_provider_type, tool_call_id_template
`
type UpdateFlowStatusParams struct {
Status FlowStatus `json:"status"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateFlowStatus(ctx context.Context, arg UpdateFlowStatusParams) (Flow, error) {
row := q.db.QueryRowContext(ctx, updateFlowStatus, arg.Status, arg.ID)
var i Flow
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateFlowTitle = `-- name: UpdateFlowTitle :one
UPDATE flows
SET title = $1
WHERE id = $2
RETURNING id, status, title, model, model_provider_name, language, functions, user_id, created_at, updated_at, deleted_at, trace_id, model_provider_type, tool_call_id_template
`
type UpdateFlowTitleParams struct {
Title string `json:"title"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateFlowTitle(ctx context.Context, arg UpdateFlowTitleParams) (Flow, error) {
row := q.db.QueryRowContext(ctx, updateFlowTitle, arg.Title, arg.ID)
var i Flow
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
const updateFlowToolCallIDTemplate = `-- name: UpdateFlowToolCallIDTemplate :one
UPDATE flows
SET tool_call_id_template = $1
WHERE id = $2
RETURNING id, status, title, model, model_provider_name, language, functions, user_id, created_at, updated_at, deleted_at, trace_id, model_provider_type, tool_call_id_template
`
type UpdateFlowToolCallIDTemplateParams struct {
ToolCallIDTemplate string `json:"tool_call_id_template"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateFlowToolCallIDTemplate(ctx context.Context, arg UpdateFlowToolCallIDTemplateParams) (Flow, error) {
row := q.db.QueryRowContext(ctx, updateFlowToolCallIDTemplate, arg.ToolCallIDTemplate, arg.ID)
var i Flow
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Model,
&i.ModelProviderName,
&i.Language,
&i.Functions,
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.TraceID,
&i.ModelProviderType,
&i.ToolCallIDTemplate,
)
return i, err
}
+455
View File
@@ -0,0 +1,455 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: knowledge.sql
package database
import (
"context"
"database/sql"
"encoding/json"
"github.com/google/uuid"
"github.com/sqlc-dev/pqtype"
)
const deleteFlowMemoryDocuments = `-- name: DeleteFlowMemoryDocuments :exec
DELETE FROM langchain_pg_embedding
WHERE collection_id = (SELECT uuid FROM langchain_pg_collection WHERE name = 'langchain')
AND COALESCE(cmetadata ->> 'doc_type', '') = 'memory'
AND (cmetadata ->> 'flow_id') = $1
`
// Delete all memory-type documents for a specific flow.
// Called on flow deletion to free long-term memory that will never be re-used.
// flow_id is the decimal text representation of the flow ID (e.g. "55"), matching the
// text result of (cmetadata ->> 'flow_id') which uses JSON ->> extraction.
func (q *Queries) DeleteFlowMemoryDocuments(ctx context.Context, flowID sql.NullString) error {
_, err := q.db.ExecContext(ctx, deleteFlowMemoryDocuments, flowID)
return err
}
const deleteKnowledgeDocument = `-- name: DeleteKnowledgeDocument :exec
DELETE FROM langchain_pg_embedding
WHERE uuid::text = $1
AND collection_id = (SELECT uuid FROM langchain_pg_collection WHERE name = 'langchain')
`
// Delete a knowledge document by UUID (admin — no user_id check).
func (q *Queries) DeleteKnowledgeDocument(ctx context.Context, argUuid sql.NullString) error {
_, err := q.db.ExecContext(ctx, deleteKnowledgeDocument, argUuid)
return err
}
const deleteUserKnowledgeDocument = `-- name: DeleteUserKnowledgeDocument :exec
DELETE FROM langchain_pg_embedding
WHERE uuid::text = $1
AND (cmetadata ->> 'user_id') = $2
AND collection_id = (SELECT uuid FROM langchain_pg_collection WHERE name = 'langchain')
`
type DeleteUserKnowledgeDocumentParams struct {
Uuid sql.NullString `json:"uuid"`
UserID sql.NullString `json:"user_id"`
}
// Delete a knowledge document by UUID, only if it belongs to the given user.
func (q *Queries) DeleteUserKnowledgeDocument(ctx context.Context, arg DeleteUserKnowledgeDocumentParams) error {
_, err := q.db.ExecContext(ctx, deleteUserKnowledgeDocument, arg.Uuid, arg.UserID)
return err
}
const getKnowledgeDocument = `-- name: GetKnowledgeDocument :one
SELECT
e.uuid::text AS id,
COALESCE(e.document, '') AS document,
COALESCE(e.cmetadata::text, '{}') AS cmetadata
FROM langchain_pg_embedding e
INNER JOIN langchain_pg_collection c ON e.collection_id = c.uuid
WHERE c.name = 'langchain'
AND e.uuid::text = $1
`
type GetKnowledgeDocumentRow struct {
ID string `json:"id"`
Document string `json:"document"`
Cmetadata sql.NullString `json:"cmetadata"`
}
// Fetch a single knowledge document by its UUID (admin view — no user_id check).
func (q *Queries) GetKnowledgeDocument(ctx context.Context, argUuid string) (GetKnowledgeDocumentRow, error) {
row := q.db.QueryRowContext(ctx, getKnowledgeDocument, argUuid)
var i GetKnowledgeDocumentRow
err := row.Scan(&i.ID, &i.Document, &i.Cmetadata)
return i, err
}
const getUserKnowledgeDocument = `-- name: GetUserKnowledgeDocument :one
SELECT
e.uuid::text AS id,
COALESCE(e.document, '') AS document,
COALESCE(e.cmetadata::text, '{}') AS cmetadata
FROM langchain_pg_embedding e
INNER JOIN langchain_pg_collection c ON e.collection_id = c.uuid
WHERE c.name = 'langchain'
AND e.uuid::text = $1
AND (e.cmetadata ->> 'user_id') = $2
`
type GetUserKnowledgeDocumentParams struct {
Uuid string `json:"uuid"`
UserID sql.NullString `json:"user_id"`
}
type GetUserKnowledgeDocumentRow struct {
ID string `json:"id"`
Document string `json:"document"`
Cmetadata sql.NullString `json:"cmetadata"`
}
// Fetch a single knowledge document by UUID, scoped to a specific user.
func (q *Queries) GetUserKnowledgeDocument(ctx context.Context, arg GetUserKnowledgeDocumentParams) (GetUserKnowledgeDocumentRow, error) {
row := q.db.QueryRowContext(ctx, getUserKnowledgeDocument, arg.Uuid, arg.UserID)
var i GetUserKnowledgeDocumentRow
err := row.Scan(&i.ID, &i.Document, &i.Cmetadata)
return i, err
}
const insertKnowledgeDocument = `-- name: InsertKnowledgeDocument :one
INSERT INTO langchain_pg_embedding (uuid, document, embedding, cmetadata, collection_id)
SELECT
$1::uuid,
$2,
$3::vector,
$4::json,
c.uuid
FROM langchain_pg_collection c
WHERE c.name = 'langchain'
RETURNING uuid::text AS id
`
type InsertKnowledgeDocumentParams struct {
Uuid uuid.UUID `json:"uuid"`
Document sql.NullString `json:"document"`
Embedding interface{} `json:"embedding"`
Cmetadata json.RawMessage `json:"cmetadata"`
}
// Insert a document with a pre-computed embedding vector and return its UUID.
// embedding must be formatted as a PostgreSQL vector literal: '[f1,f2,...]'
// cmetadata must be valid JSON text.
func (q *Queries) InsertKnowledgeDocument(ctx context.Context, arg InsertKnowledgeDocumentParams) (string, error) {
row := q.db.QueryRowContext(ctx, insertKnowledgeDocument,
arg.Uuid,
arg.Document,
arg.Embedding,
arg.Cmetadata,
)
var id string
err := row.Scan(&id)
return id, err
}
const listAllKnowledgeDocuments = `-- name: ListAllKnowledgeDocuments :many
SELECT
e.uuid::text AS id,
COALESCE(e.document, '') AS document,
COALESCE(e.cmetadata::text, '{}') AS cmetadata
FROM langchain_pg_embedding e
INNER JOIN langchain_pg_collection c ON e.collection_id = c.uuid
WHERE c.name = 'langchain'
AND COALESCE(e.cmetadata ->> 'doc_type', '') NOT IN ('memory')
ORDER BY e.uuid
`
type ListAllKnowledgeDocumentsRow struct {
ID string `json:"id"`
Document string `json:"document"`
Cmetadata sql.NullString `json:"cmetadata"`
}
// List all knowledge documents excluding the noisy memory type (admin view).
func (q *Queries) ListAllKnowledgeDocuments(ctx context.Context) ([]ListAllKnowledgeDocumentsRow, error) {
rows, err := q.db.QueryContext(ctx, listAllKnowledgeDocuments)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListAllKnowledgeDocumentsRow
for rows.Next() {
var i ListAllKnowledgeDocumentsRow
if err := rows.Scan(&i.ID, &i.Document, &i.Cmetadata); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listFlowKnowledgeDocuments = `-- name: ListFlowKnowledgeDocuments :many
SELECT
e.uuid::text AS id,
COALESCE(e.document, '') AS document,
COALESCE(e.cmetadata::text, '{}') AS cmetadata
FROM langchain_pg_embedding e
INNER JOIN langchain_pg_collection c ON e.collection_id = c.uuid
WHERE c.name = 'langchain'
AND COALESCE(e.cmetadata ->> 'doc_type', '') NOT IN ('memory')
AND (e.cmetadata ->> 'flow_id') = $1
ORDER BY e.uuid
`
type ListFlowKnowledgeDocumentsRow struct {
ID string `json:"id"`
Document string `json:"document"`
Cmetadata sql.NullString `json:"cmetadata"`
}
// List non-memory knowledge documents belonging to a specific flow (admin scoped).
func (q *Queries) ListFlowKnowledgeDocuments(ctx context.Context, flowID sql.NullString) ([]ListFlowKnowledgeDocumentsRow, error) {
rows, err := q.db.QueryContext(ctx, listFlowKnowledgeDocuments, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListFlowKnowledgeDocumentsRow
for rows.Next() {
var i ListFlowKnowledgeDocumentsRow
if err := rows.Scan(&i.ID, &i.Document, &i.Cmetadata); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listUserKnowledgeDocuments = `-- name: ListUserKnowledgeDocuments :many
SELECT
e.uuid::text AS id,
COALESCE(e.document, '') AS document,
COALESCE(e.cmetadata::text, '{}') AS cmetadata
FROM langchain_pg_embedding e
INNER JOIN langchain_pg_collection c ON e.collection_id = c.uuid
WHERE c.name = 'langchain'
AND COALESCE(e.cmetadata ->> 'doc_type', '') NOT IN ('memory')
AND (e.cmetadata ->> 'user_id') = $1
ORDER BY e.uuid
`
type ListUserKnowledgeDocumentsRow struct {
ID string `json:"id"`
Document string `json:"document"`
Cmetadata sql.NullString `json:"cmetadata"`
}
// List all non-memory knowledge documents owned by a specific user (user-scoped view).
func (q *Queries) ListUserKnowledgeDocuments(ctx context.Context, userID sql.NullString) ([]ListUserKnowledgeDocumentsRow, error) {
rows, err := q.db.QueryContext(ctx, listUserKnowledgeDocuments, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListUserKnowledgeDocumentsRow
for rows.Next() {
var i ListUserKnowledgeDocumentsRow
if err := rows.Scan(&i.ID, &i.Document, &i.Cmetadata); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const searchKnowledgeDocuments = `-- name: SearchKnowledgeDocuments :many
SELECT
e.uuid::text AS id,
COALESCE(e.document, '') AS document,
COALESCE(e.cmetadata::text, '{}') AS cmetadata,
(1.0 - (e.embedding <=> $1::vector))::float8 AS score
FROM langchain_pg_embedding e
INNER JOIN langchain_pg_collection c ON e.collection_id = c.uuid
WHERE c.name = 'langchain'
AND COALESCE(e.cmetadata ->> 'doc_type', '') NOT IN ('memory')
AND (e.embedding <=> $1::vector)::float8 < $2::float8
ORDER BY e.embedding <=> $1::vector
LIMIT $3::int
`
type SearchKnowledgeDocumentsParams struct {
Embedding interface{} `json:"embedding"`
MaxDistance float64 `json:"max_distance"`
Lim int32 `json:"lim"`
}
type SearchKnowledgeDocumentsRow struct {
ID string `json:"id"`
Document string `json:"document"`
Cmetadata sql.NullString `json:"cmetadata"`
Score float64 `json:"score"`
}
// Vector similarity search over all knowledge documents (admin view, no user filter).
// Returns rows ordered by cosine similarity descending (highest score first).
// embedding query vector as a PostgreSQL vector literal, e.g. '[0.1,0.2,...]'
// max_distance cosine-distance upper bound (exclusive); equals (1 - score_threshold),
//
// e.g. pass 0.8 to get documents with similarity score > 0.2
//
// lim maximum number of rows to return
func (q *Queries) SearchKnowledgeDocuments(ctx context.Context, arg SearchKnowledgeDocumentsParams) ([]SearchKnowledgeDocumentsRow, error) {
rows, err := q.db.QueryContext(ctx, searchKnowledgeDocuments, arg.Embedding, arg.MaxDistance, arg.Lim)
if err != nil {
return nil, err
}
defer rows.Close()
var items []SearchKnowledgeDocumentsRow
for rows.Next() {
var i SearchKnowledgeDocumentsRow
if err := rows.Scan(
&i.ID,
&i.Document,
&i.Cmetadata,
&i.Score,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const searchUserKnowledgeDocuments = `-- name: SearchUserKnowledgeDocuments :many
SELECT
e.uuid::text AS id,
COALESCE(e.document, '') AS document,
COALESCE(e.cmetadata::text, '{}') AS cmetadata,
(1.0 - (e.embedding <=> $1::vector))::float8 AS score
FROM langchain_pg_embedding e
INNER JOIN langchain_pg_collection c ON e.collection_id = c.uuid
WHERE c.name = 'langchain'
AND COALESCE(e.cmetadata ->> 'doc_type', '') NOT IN ('memory')
AND (e.cmetadata ->> 'user_id') = $2
AND (e.embedding <=> $1::vector)::float8 < $3::float8
ORDER BY e.embedding <=> $1::vector
LIMIT $4::int
`
type SearchUserKnowledgeDocumentsParams struct {
Embedding interface{} `json:"embedding"`
UserID sql.NullString `json:"user_id"`
MaxDistance float64 `json:"max_distance"`
Lim int32 `json:"lim"`
}
type SearchUserKnowledgeDocumentsRow struct {
ID string `json:"id"`
Document string `json:"document"`
Cmetadata sql.NullString `json:"cmetadata"`
Score float64 `json:"score"`
}
// Vector similarity search scoped to a specific user (by cmetadata user_id).
// Returns rows ordered by cosine similarity descending (highest score first).
// embedding query vector as a PostgreSQL vector literal, e.g. '[0.1,0.2,...]'
// max_distance cosine-distance upper bound (exclusive); equals (1 - score_threshold)
// lim maximum number of rows to return
// user_id owner filter as a decimal text string (e.g. "42")
func (q *Queries) SearchUserKnowledgeDocuments(ctx context.Context, arg SearchUserKnowledgeDocumentsParams) ([]SearchUserKnowledgeDocumentsRow, error) {
rows, err := q.db.QueryContext(ctx, searchUserKnowledgeDocuments,
arg.Embedding,
arg.UserID,
arg.MaxDistance,
arg.Lim,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []SearchUserKnowledgeDocumentsRow
for rows.Next() {
var i SearchUserKnowledgeDocumentsRow
if err := rows.Scan(
&i.ID,
&i.Document,
&i.Cmetadata,
&i.Score,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateKnowledgeDocument = `-- name: UpdateKnowledgeDocument :one
UPDATE langchain_pg_embedding
SET
embedding = $1::vector,
document = $2,
cmetadata = $3::json
WHERE uuid::text = $4
AND collection_id = (SELECT uuid FROM langchain_pg_collection WHERE name = 'langchain')
RETURNING
uuid::text AS id,
COALESCE(document, '') AS document,
COALESCE(cmetadata::text, '{}') AS cmetadata
`
type UpdateKnowledgeDocumentParams struct {
Embedding string `json:"embedding"`
Document sql.NullString `json:"document"`
Cmetadata pqtype.NullRawMessage `json:"cmetadata"`
Uuid sql.NullString `json:"uuid"`
}
type UpdateKnowledgeDocumentRow struct {
ID string `json:"id"`
Document string `json:"document"`
Cmetadata sql.NullString `json:"cmetadata"`
}
// Update an existing document's embedding, text and metadata atomically.
// embedding must be formatted as a PostgreSQL vector literal: '[f1,f2,...]'
// cmetadata must be valid JSON text.
func (q *Queries) UpdateKnowledgeDocument(ctx context.Context, arg UpdateKnowledgeDocumentParams) (UpdateKnowledgeDocumentRow, error) {
row := q.db.QueryRowContext(ctx, updateKnowledgeDocument,
arg.Embedding,
arg.Document,
arg.Cmetadata,
arg.Uuid,
)
var i UpdateKnowledgeDocumentRow
err := row.Scan(&i.ID, &i.Document, &i.Cmetadata)
return i, err
}
+726
View File
@@ -0,0 +1,726 @@
package knowledge
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"slices"
"strconv"
"strings"
"pentagi/pkg/database"
"pentagi/pkg/graph/model"
"pentagi/pkg/graph/subscriptions"
"pentagi/pkg/providers/embeddings"
"github.com/google/uuid"
"github.com/sqlc-dev/pqtype"
"github.com/vxcontrol/langchaingo/vectorstores"
)
const (
defaultSearchLimit = 10
defaultSearchThreshold = float32(0.2)
manualDocumentFlag = "manual"
)
// PublisherFactory creates a per-user KnowledgePublisher.
// Matches subscriptions.SubscriptionsController.NewKnowledgePublisher signature.
type PublisherFactory func(userID int64) subscriptions.KnowledgePublisher
// KnowledgeStore covers all GraphQL knowledge operations:
// - Admin read methods have no user_id filtering.
// - User-scoped read methods filter cmetadata by user_id.
// - Write methods always record the caller's userID for event scoping and
// are added to cmetadata; user-scoped delete/update also enforce ownership.
type KnowledgeStore interface {
// Admin reads
ListDocuments(ctx context.Context, filter *model.KnowledgeFilter, withContent bool) ([]*model.KnowledgeDocument, error)
GetDocument(ctx context.Context, id string) (*model.KnowledgeDocument, error)
SearchDocuments(ctx context.Context, query string, filter *model.KnowledgeFilter, limit int) ([]*model.KnowledgeDocumentWithScore, error)
// User-scoped reads (filter by user_id in cmetadata)
ListUserDocuments(ctx context.Context, userID int64, filter *model.KnowledgeFilter, withContent bool) ([]*model.KnowledgeDocument, error)
GetUserDocument(ctx context.Context, userID int64, id string) (*model.KnowledgeDocument, error)
SearchUserDocuments(ctx context.Context, userID int64, query string, filter *model.KnowledgeFilter, limit int) ([]*model.KnowledgeDocumentWithScore, error)
// Writes
CreateDocument(ctx context.Context, userID int64, input model.CreateKnowledgeDocumentInput) (*model.KnowledgeDocument, error)
UpdateDocument(ctx context.Context, userID int64, id string, input model.UpdateKnowledgeDocumentInput) (*model.KnowledgeDocument, error)
UpdateUserDocument(ctx context.Context, userID int64, id string, input model.UpdateKnowledgeDocumentInput) (*model.KnowledgeDocument, error)
DeleteDocument(ctx context.Context, userID int64, id string) error
DeleteUserDocument(ctx context.Context, userID int64, id string) error
}
type knowledgeStore struct {
db database.Querier
store vectorstores.VectorStore // may be nil when no embedder is configured
embedder embeddings.Embedder // used for computing new embeddings on create/update
newKnp PublisherFactory
maxEmbeddingBytes int
}
// NewKnowledgeStore constructs a KnowledgeStore.
// - store and embedder may be nil when the embedding provider is not configured;
// in that case create/update/search return a descriptive error while
// list/get/delete still work.
// - newKnp is called with the acting user's ID on each write to create a
// correctly scoped event publisher.
// - maxEmbeddingBytes is the maximum byte size of text sent to the embedding
// model. Text is truncated to this limit before embedding to avoid token
// limit errors; the full original text is always stored in the database.
func NewKnowledgeStore(
db database.Querier,
store vectorstores.VectorStore,
embedder embeddings.Embedder,
newKnp PublisherFactory,
maxEmbeddingBytes int,
) KnowledgeStore {
if maxEmbeddingBytes <= 0 {
maxEmbeddingBytes = 8192
}
return &knowledgeStore{
db: db,
store: store,
embedder: embedder,
newKnp: newKnp,
maxEmbeddingBytes: maxEmbeddingBytes,
}
}
// ---- cmetadata helpers -------------------------------------------------------
// knowledgeMeta mirrors the flat JSON stored in langchain_pg_embedding.cmetadata.
type knowledgeMeta struct {
DocType string `json:"doc_type,omitempty"`
UserID int64 `json:"user_id,omitempty"`
FlowID *int64 `json:"flow_id,omitempty"`
TaskID *int64 `json:"task_id,omitempty"`
SubtaskID *int64 `json:"subtask_id,omitempty"`
Question string `json:"question,omitempty"`
Description string `json:"description,omitempty"`
GuideType string `json:"guide_type,omitempty"`
AnswerType string `json:"answer_type,omitempty"`
CodeLang string `json:"code_lang,omitempty"`
PartSize int `json:"part_size,omitempty"`
TotalSize int `json:"total_size,omitempty"`
Manual bool `json:"manual,omitempty"`
}
func parseMeta(raw string) knowledgeMeta {
var m knowledgeMeta
if raw != "" {
_ = json.Unmarshal([]byte(raw), &m)
}
return m
}
func nullStr(ns sql.NullString) string {
if ns.Valid {
return ns.String
}
return "{}"
}
func nsOf(s string) sql.NullString {
return sql.NullString{String: s, Valid: true}
}
// formatVector converts a float32 slice into the PostgreSQL vector literal '[f1,f2,...]'.
func formatVector(v []float32) string {
strs := make([]string, len(v))
for i, f := range v {
strs[i] = strconv.FormatFloat(float64(f), 'f', -1, 32)
}
return "[" + strings.Join(strs, ",") + "]"
}
// metaToJSON serialises a knowledgeMeta into a pqtype.NullRawMessage for sqlc.
func metaToJSON(m knowledgeMeta) (pqtype.NullRawMessage, error) {
b, err := json.Marshal(m)
if err != nil {
return pqtype.NullRawMessage{}, err
}
return pqtype.NullRawMessage{RawMessage: b, Valid: true}, nil
}
// rowToModel converts a sqlc knowledge row into a GraphQL model.
func rowToModel(id, document, cmetadataRaw string, withContent bool) *model.KnowledgeDocument {
meta := parseMeta(cmetadataRaw)
content := document
if !withContent {
content = ""
}
return metaToModelDoc(id, content, meta)
}
func metaToModelDoc(id, content string, meta knowledgeMeta) *model.KnowledgeDocument {
doc := &model.KnowledgeDocument{
ID: id,
UserID: meta.UserID,
Content: content,
Question: meta.Question,
PartSize: meta.PartSize,
TotalSize: meta.TotalSize,
Manual: meta.Manual,
}
switch meta.DocType {
case "answer":
doc.DocType = model.KnowledgeDocTypeAnswer
case "guide":
doc.DocType = model.KnowledgeDocTypeGuide
case "code":
doc.DocType = model.KnowledgeDocTypeCode
default:
doc.DocType = model.KnowledgeDocTypeAnswer
}
if meta.FlowID != nil {
doc.FlowID = meta.FlowID
}
if meta.TaskID != nil {
doc.TaskID = meta.TaskID
}
if meta.SubtaskID != nil {
doc.SubtaskID = meta.SubtaskID
}
if meta.Description != "" {
d := meta.Description
doc.Description = &d
}
if meta.GuideType != "" {
gt := model.KnowledgeGuideType(meta.GuideType)
doc.GuideType = &gt
}
if meta.AnswerType != "" {
at := model.KnowledgeAnswerType(meta.AnswerType)
doc.AnswerType = &at
}
if meta.CodeLang != "" {
cl := meta.CodeLang
doc.CodeLang = &cl
}
return doc
}
// applyGoFilters applies optional filters that cannot be expressed as single SQL predicates.
func applyGoFilters(docs []*model.KnowledgeDocument, filter *model.KnowledgeFilter) []*model.KnowledgeDocument {
if filter == nil {
return docs
}
result := make([]*model.KnowledgeDocument, 0, len(docs))
for _, doc := range docs {
if len(filter.DocTypes) > 0 && !slices.Contains(filter.DocTypes, doc.DocType) {
continue
}
if len(filter.GuideTypes) > 0 && (doc.GuideType == nil || !slices.Contains(filter.GuideTypes, *doc.GuideType)) {
continue
}
if len(filter.AnswerTypes) > 0 && (doc.AnswerType == nil || !slices.Contains(filter.AnswerTypes, *doc.AnswerType)) {
continue
}
if len(filter.CodeLangs) > 0 && (doc.CodeLang == nil || !slices.Contains(filter.CodeLangs, *doc.CodeLang)) {
continue
}
if filter.Manual != nil && doc.Manual != *filter.Manual {
continue
}
result = append(result, doc)
}
return result
}
func (ks *knowledgeStore) requireStore() error {
if ks.store == nil {
return fmt.Errorf("knowledge: embedding provider is not configured")
}
return nil
}
func (ks *knowledgeStore) requireEmbedder() error {
if ks.embedder == nil || !ks.embedder.IsAvailable() {
return fmt.Errorf("knowledge: embedding provider is not available")
}
return nil
}
// ---- ListDocuments (admin) --------------------------------------------------
func (ks *knowledgeStore) ListDocuments(ctx context.Context, filter *model.KnowledgeFilter, withContent bool) ([]*model.KnowledgeDocument, error) {
var docs []*model.KnowledgeDocument
if filter != nil && filter.FlowID != nil {
rows, err := ks.db.ListFlowKnowledgeDocuments(ctx, nsOf(strconv.FormatInt(*filter.FlowID, 10)))
if err != nil {
return nil, fmt.Errorf("knowledge: list by flow: %w", err)
}
for _, r := range rows {
docs = append(docs, rowToModel(r.ID, r.Document, nullStr(r.Cmetadata), withContent))
}
} else {
rows, err := ks.db.ListAllKnowledgeDocuments(ctx)
if err != nil {
return nil, fmt.Errorf("knowledge: list all: %w", err)
}
for _, r := range rows {
docs = append(docs, rowToModel(r.ID, r.Document, nullStr(r.Cmetadata), withContent))
}
}
return applyGoFilters(docs, filter), nil
}
// ---- ListUserDocuments (user-scoped) ----------------------------------------
func (ks *knowledgeStore) ListUserDocuments(ctx context.Context, userID int64, filter *model.KnowledgeFilter, withContent bool) ([]*model.KnowledgeDocument, error) {
userIDStr := strconv.FormatInt(userID, 10)
var docs []*model.KnowledgeDocument
if filter != nil && filter.FlowID != nil {
// Flow-scoped listing; user_id check applied in Go for safety.
rows, err := ks.db.ListFlowKnowledgeDocuments(ctx, nsOf(strconv.FormatInt(*filter.FlowID, 10)))
if err != nil {
return nil, fmt.Errorf("knowledge: list by flow (user): %w", err)
}
for _, r := range rows {
meta := parseMeta(nullStr(r.Cmetadata))
if strconv.FormatInt(meta.UserID, 10) != userIDStr {
continue
}
docs = append(docs, rowToModel(r.ID, r.Document, nullStr(r.Cmetadata), withContent))
}
} else {
rows, err := ks.db.ListUserKnowledgeDocuments(ctx, nsOf(userIDStr))
if err != nil {
return nil, fmt.Errorf("knowledge: list user docs: %w", err)
}
for _, r := range rows {
docs = append(docs, rowToModel(r.ID, r.Document, nullStr(r.Cmetadata), withContent))
}
}
return applyGoFilters(docs, filter), nil
}
// ---- GetDocument (admin) ----------------------------------------------------
func (ks *knowledgeStore) GetDocument(ctx context.Context, id string) (*model.KnowledgeDocument, error) {
row, err := ks.db.GetKnowledgeDocument(ctx, id)
if err != nil {
return nil, fmt.Errorf("knowledge: get document %s: %w", id, err)
}
return rowToModel(row.ID, row.Document, nullStr(row.Cmetadata), true), nil
}
// ---- GetUserDocument (user-scoped) ------------------------------------------
func (ks *knowledgeStore) GetUserDocument(ctx context.Context, userID int64, id string) (*model.KnowledgeDocument, error) {
row, err := ks.db.GetUserKnowledgeDocument(ctx, database.GetUserKnowledgeDocumentParams{
Uuid: id,
UserID: nsOf(strconv.FormatInt(userID, 10)),
})
if err != nil {
return nil, fmt.Errorf("knowledge: get user document %s: %w", id, err)
}
return rowToModel(row.ID, row.Document, nullStr(row.Cmetadata), true), nil
}
// ---- SearchDocuments (admin) ------------------------------------------------
func (ks *knowledgeStore) SearchDocuments(ctx context.Context, query string, filter *model.KnowledgeFilter, limit int) ([]*model.KnowledgeDocumentWithScore, error) {
return ks.doSearch(ctx, 0, query, filter, limit)
}
// ---- SearchUserDocuments (user-scoped) --------------------------------------
func (ks *knowledgeStore) SearchUserDocuments(ctx context.Context, userID int64, query string, filter *model.KnowledgeFilter, limit int) ([]*model.KnowledgeDocumentWithScore, error) {
return ks.doSearch(ctx, userID, query, filter, limit)
}
// doSearch performs a parameterised vector similarity search and returns
// matched documents with their cosine-similarity scores and correct UUIDs.
//
// Filters are applied in two layers:
// 1. SQL layer — user_id ownership (when userID > 0); cosine-distance
// threshold; row limit. All values are bound as query parameters so
// there is no risk of SQL injection.
// 2. Go layer — multi-value enum filters (DocTypes, GuideTypes, etc.) and
// the Manual flag that cannot be expressed as static SQL predicates.
func (ks *knowledgeStore) doSearch(ctx context.Context, userID int64, query string, filter *model.KnowledgeFilter, limit int) ([]*model.KnowledgeDocumentWithScore, error) {
if err := ks.requireEmbedder(); err != nil {
return nil, err
}
if limit <= 0 {
limit = defaultSearchLimit
}
// Truncate query to embedding size limit to avoid token limit errors.
// The search quality is preserved since the most relevant context is at the start.
if len(query) > ks.maxEmbeddingBytes {
query = query[:ks.maxEmbeddingBytes]
}
// Compute query embedding.
vecs, err := ks.embedder.EmbedDocuments(ctx, []string{query})
if err != nil {
return nil, fmt.Errorf("knowledge: embed query: %w", err)
}
if len(vecs) == 0 {
return nil, fmt.Errorf("knowledge: embedder returned no vectors for query")
}
vecLiteral := formatVector(vecs[0])
// maxDist is the cosine-distance upper bound (exclusive):
// distance = 1 - similarity, so maxDist = 1 - threshold.
maxDist := float64(1.0 - defaultSearchThreshold)
type searchRow struct {
ID string
Document string
Cmetadata sql.NullString
Score float64
}
var rawRows []searchRow
if userID > 0 {
rows, err := ks.db.SearchUserKnowledgeDocuments(ctx, database.SearchUserKnowledgeDocumentsParams{
Embedding: vecLiteral,
UserID: nsOf(strconv.FormatInt(userID, 10)),
MaxDistance: maxDist,
Lim: int32(limit), //nolint:gosec
})
if err != nil {
return nil, fmt.Errorf("knowledge: similarity search (user %d): %w", userID, err)
}
rawRows = make([]searchRow, len(rows))
for i, r := range rows {
rawRows[i] = searchRow{r.ID, r.Document, r.Cmetadata, r.Score}
}
} else {
rows, err := ks.db.SearchKnowledgeDocuments(ctx, database.SearchKnowledgeDocumentsParams{
Embedding: vecLiteral,
MaxDistance: maxDist,
Lim: int32(limit), //nolint:gosec
})
if err != nil {
return nil, fmt.Errorf("knowledge: similarity search (admin): %w", err)
}
rawRows = make([]searchRow, len(rows))
for i, r := range rows {
rawRows[i] = searchRow{r.ID, r.Document, r.Cmetadata, r.Score}
}
}
results := make([]*model.KnowledgeDocumentWithScore, 0, len(rawRows))
for _, r := range rawRows {
doc := rowToModel(r.ID, r.Document, nullStr(r.Cmetadata), true)
if !passesSearchFilter(doc, filter) {
continue
}
results = append(results, &model.KnowledgeDocumentWithScore{
Score: r.Score,
Document: doc,
})
}
return results, nil
}
// passesSearchFilter checks the Go-side filters that cannot be expressed as
// static SQL predicates (FlowID equality, multi-value enums, and the Manual flag).
func passesSearchFilter(doc *model.KnowledgeDocument, filter *model.KnowledgeFilter) bool {
if filter == nil {
return true
}
if filter.FlowID != nil && (doc.FlowID == nil || *doc.FlowID != *filter.FlowID) {
return false
}
if len(filter.DocTypes) > 0 && !slices.Contains(filter.DocTypes, doc.DocType) {
return false
}
if len(filter.GuideTypes) > 0 && (doc.GuideType == nil || !slices.Contains(filter.GuideTypes, *doc.GuideType)) {
return false
}
if len(filter.AnswerTypes) > 0 && (doc.AnswerType == nil || !slices.Contains(filter.AnswerTypes, *doc.AnswerType)) {
return false
}
if len(filter.CodeLangs) > 0 && (doc.CodeLang == nil || !slices.Contains(filter.CodeLangs, *doc.CodeLang)) {
return false
}
if filter.Manual != nil && doc.Manual != *filter.Manual {
return false
}
return true
}
// ---- CreateDocument ---------------------------------------------------------
func (ks *knowledgeStore) CreateDocument(ctx context.Context, userID int64, input model.CreateKnowledgeDocumentInput) (*model.KnowledgeDocument, error) {
if err := ks.requireEmbedder(); err != nil {
return nil, err
}
meta := knowledgeMeta{
DocType: string(input.DocType),
UserID: userID,
Question: input.Question,
Manual: true,
}
if input.Description != nil {
meta.Description = *input.Description
}
if input.GuideType != nil {
meta.GuideType = string(*input.GuideType)
}
if input.AnswerType != nil {
meta.AnswerType = string(*input.AnswerType)
}
if input.CodeLang != nil {
meta.CodeLang = *input.CodeLang
}
content := strings.TrimSpace(input.Content)
meta.PartSize = len(content)
meta.TotalSize = len(content)
// Truncate to embedding size limit for vector computation; full content goes to DB.
embeddingText := content
if len(embeddingText) > ks.maxEmbeddingBytes {
embeddingText = embeddingText[:ks.maxEmbeddingBytes]
}
vecs, err := ks.embedder.EmbedDocuments(ctx, []string{embeddingText})
if err != nil {
return nil, fmt.Errorf("knowledge: compute embedding: %w", err)
}
if len(vecs) == 0 {
return nil, fmt.Errorf("knowledge: embedder returned no vectors")
}
cmJSON, err := metaToJSON(meta)
if err != nil {
return nil, fmt.Errorf("knowledge: marshal cmetadata: %w", err)
}
id := uuid.New()
docID, err := ks.db.InsertKnowledgeDocument(ctx, database.InsertKnowledgeDocumentParams{
Uuid: id,
Document: nsOf(content),
Embedding: formatVector(vecs[0]),
Cmetadata: cmJSON.RawMessage,
})
if err != nil {
return nil, fmt.Errorf("knowledge: create document: %w", err)
}
doc := metaToModelDoc(docID, content, meta)
ks.newKnp(userID).KnowledgeDocumentCreated(ctx, doc)
return doc, nil
}
// ---- UpdateDocument (admin) -------------------------------------------------
func (ks *knowledgeStore) UpdateDocument(ctx context.Context, userID int64, id string, input model.UpdateKnowledgeDocumentInput) (*model.KnowledgeDocument, error) {
existing, err := ks.GetDocument(ctx, id)
if err != nil {
return nil, err
}
return ks.doUpdate(ctx, userID, id, existing, input)
}
// ---- UpdateUserDocument (user-scoped) ---------------------------------------
func (ks *knowledgeStore) UpdateUserDocument(ctx context.Context, userID int64, id string, input model.UpdateKnowledgeDocumentInput) (*model.KnowledgeDocument, error) {
existing, err := ks.GetUserDocument(ctx, userID, id)
if err != nil {
return nil, err
}
return ks.doUpdate(ctx, userID, id, existing, input)
}
func (ks *knowledgeStore) doUpdate(ctx context.Context, userID int64, id string, existing *model.KnowledgeDocument, input model.UpdateKnowledgeDocumentInput) (*model.KnowledgeDocument, error) {
if err := ks.requireEmbedder(); err != nil {
return nil, err
}
// Build updated metadata from existing document.
// Preserve the original owner (UserID) — the caller's identity (userID) is
// used only for event scoping via the publisher, not stored in cmetadata.
meta := knowledgeMeta{
DocType: string(existing.DocType),
UserID: existing.UserID,
Manual: existing.Manual,
Question: existing.Question,
}
if existing.FlowID != nil {
meta.FlowID = existing.FlowID
}
if existing.TaskID != nil {
meta.TaskID = existing.TaskID
}
if existing.SubtaskID != nil {
meta.SubtaskID = existing.SubtaskID
}
if existing.Description != nil {
meta.Description = *existing.Description
}
if existing.GuideType != nil {
meta.GuideType = string(*existing.GuideType)
}
if existing.AnswerType != nil {
meta.AnswerType = string(*existing.AnswerType)
}
if existing.CodeLang != nil {
meta.CodeLang = *existing.CodeLang
}
// Apply input fields.
content := strings.TrimSpace(input.Content)
if input.Question != nil {
meta.Question = *input.Question
}
if input.Description != nil {
meta.Description = *input.Description
}
if input.GuideType != nil {
meta.GuideType = string(*input.GuideType)
}
if input.AnswerType != nil {
meta.AnswerType = string(*input.AnswerType)
}
if input.CodeLang != nil {
meta.CodeLang = *input.CodeLang
}
// Map of sub-type fields to their pointers to be cleared when DocType changes.
subTypeFields := map[string]*string{
"guide": &meta.GuideType,
"answer": &meta.AnswerType,
"code": &meta.CodeLang,
}
if input.DocType != nil {
newDocType := string(*input.DocType)
for subType, field := range subTypeFields {
if newDocType != subType {
*field = ""
}
}
meta.DocType = newDocType
}
deltaContentLen := len(content) - len(existing.Content)
if existing.PartSize <= 0 {
meta.PartSize = len(content)
} else {
meta.PartSize = existing.PartSize + deltaContentLen
}
if existing.TotalSize <= 0 {
meta.TotalSize = len(content)
} else {
meta.TotalSize = existing.TotalSize + deltaContentLen
}
// Compute new embedding. Truncate to maxEmbeddingBytes to avoid token limit
// errors; the full content is stored in the document column.
embeddingText := content
if len(embeddingText) > ks.maxEmbeddingBytes {
embeddingText = embeddingText[:ks.maxEmbeddingBytes]
}
vecs, err := ks.embedder.EmbedDocuments(ctx, []string{embeddingText})
if err != nil {
return nil, fmt.Errorf("knowledge: compute embedding: %w", err)
}
if len(vecs) == 0 {
return nil, fmt.Errorf("knowledge: embedder returned no vectors")
}
cmJSON, err := metaToJSON(meta)
if err != nil {
return nil, fmt.Errorf("knowledge: marshal cmetadata: %w", err)
}
row, err := ks.db.UpdateKnowledgeDocument(ctx, database.UpdateKnowledgeDocumentParams{
Uuid: nsOf(id),
Embedding: formatVector(vecs[0]),
Document: nsOf(content),
Cmetadata: cmJSON,
})
if err != nil {
return nil, fmt.Errorf("knowledge: update document %s: %w", id, err)
}
doc := rowToModel(row.ID, row.Document, nullStr(row.Cmetadata), true)
ks.newKnp(userID).KnowledgeDocumentUpdated(ctx, doc)
return doc, nil
}
// ---- DeleteDocument (admin) -------------------------------------------------
func (ks *knowledgeStore) DeleteDocument(ctx context.Context, userID int64, id string) error {
doc, err := ks.GetDocument(ctx, id)
if err != nil {
return err
}
if err := ks.db.DeleteKnowledgeDocument(ctx, nsOf(id)); err != nil {
return fmt.Errorf("knowledge: delete document %s: %w", id, err)
}
ks.newKnp(userID).KnowledgeDocumentDeleted(ctx, doc)
return nil
}
// ---- DeleteUserDocument (user-scoped) ---------------------------------------
func (ks *knowledgeStore) DeleteUserDocument(ctx context.Context, userID int64, id string) error {
doc, err := ks.GetUserDocument(ctx, userID, id)
if err != nil {
return err
}
if err := ks.db.DeleteUserKnowledgeDocument(ctx, database.DeleteUserKnowledgeDocumentParams{
Uuid: nsOf(id),
UserID: nsOf(strconv.FormatInt(userID, 10)),
}); err != nil {
return fmt.Errorf("knowledge: delete user document %s: %w", id, err)
}
ks.newKnp(userID).KnowledgeDocumentDeleted(ctx, doc)
return nil
}
// ---- helpers ----------------------------------------------------------------
// metaToMap converts knowledgeMeta to the map[string]any format used by
// langchaingo's schema.Document.Metadata / pgvector cmetadata.
func metaToMap(m knowledgeMeta) map[string]any {
mp := map[string]any{
"doc_type": m.DocType,
"user_id": m.UserID,
"question": m.Question,
"part_size": m.PartSize,
"total_size": m.TotalSize,
manualDocumentFlag: m.Manual,
}
if m.Description != "" {
mp["description"] = m.Description
}
if m.GuideType != "" {
mp["guide_type"] = m.GuideType
}
if m.AnswerType != "" {
mp["answer_type"] = m.AnswerType
}
if m.CodeLang != "" {
mp["code_lang"] = m.CodeLang
}
if m.FlowID != nil {
mp["flow_id"] = *m.FlowID
}
if m.TaskID != nil {
mp["task_id"] = *m.TaskID
}
if m.SubtaskID != nil {
mp["subtask_id"] = *m.SubtaskID
}
return mp
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+327
View File
@@ -0,0 +1,327 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: msglogs.sql
package database
import (
"context"
"database/sql"
)
const createMsgLog = `-- name: CreateMsgLog :one
INSERT INTO msglogs (
type,
message,
thinking,
flow_id,
task_id,
subtask_id
)
VALUES (
$1, $2, $3, $4, $5, $6
)
RETURNING id, type, message, result, flow_id, task_id, subtask_id, created_at, result_format, thinking
`
type CreateMsgLogParams struct {
Type MsglogType `json:"type"`
Message string `json:"message"`
Thinking sql.NullString `json:"thinking"`
FlowID int64 `json:"flow_id"`
TaskID sql.NullInt64 `json:"task_id"`
SubtaskID sql.NullInt64 `json:"subtask_id"`
}
func (q *Queries) CreateMsgLog(ctx context.Context, arg CreateMsgLogParams) (Msglog, error) {
row := q.db.QueryRowContext(ctx, createMsgLog,
arg.Type,
arg.Message,
arg.Thinking,
arg.FlowID,
arg.TaskID,
arg.SubtaskID,
)
var i Msglog
err := row.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.ResultFormat,
&i.Thinking,
)
return i, err
}
const createResultMsgLog = `-- name: CreateResultMsgLog :one
INSERT INTO msglogs (
type,
message,
thinking,
result,
result_format,
flow_id,
task_id,
subtask_id
)
VALUES (
$1, $2, $3, $4, $5, $6, $7, $8
)
RETURNING id, type, message, result, flow_id, task_id, subtask_id, created_at, result_format, thinking
`
type CreateResultMsgLogParams struct {
Type MsglogType `json:"type"`
Message string `json:"message"`
Thinking sql.NullString `json:"thinking"`
Result string `json:"result"`
ResultFormat MsglogResultFormat `json:"result_format"`
FlowID int64 `json:"flow_id"`
TaskID sql.NullInt64 `json:"task_id"`
SubtaskID sql.NullInt64 `json:"subtask_id"`
}
func (q *Queries) CreateResultMsgLog(ctx context.Context, arg CreateResultMsgLogParams) (Msglog, error) {
row := q.db.QueryRowContext(ctx, createResultMsgLog,
arg.Type,
arg.Message,
arg.Thinking,
arg.Result,
arg.ResultFormat,
arg.FlowID,
arg.TaskID,
arg.SubtaskID,
)
var i Msglog
err := row.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.ResultFormat,
&i.Thinking,
)
return i, err
}
const getFlowMsgLogs = `-- name: GetFlowMsgLogs :many
SELECT
ml.id, ml.type, ml.message, ml.result, ml.flow_id, ml.task_id, ml.subtask_id, ml.created_at, ml.result_format, ml.thinking
FROM msglogs ml
INNER JOIN flows f ON ml.flow_id = f.id
WHERE ml.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY ml.created_at ASC
`
func (q *Queries) GetFlowMsgLogs(ctx context.Context, flowID int64) ([]Msglog, error) {
rows, err := q.db.QueryContext(ctx, getFlowMsgLogs, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Msglog
for rows.Next() {
var i Msglog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.ResultFormat,
&i.Thinking,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getSubtaskMsgLogs = `-- name: GetSubtaskMsgLogs :many
SELECT
ml.id, ml.type, ml.message, ml.result, ml.flow_id, ml.task_id, ml.subtask_id, ml.created_at, ml.result_format, ml.thinking
FROM msglogs ml
INNER JOIN subtasks s ON ml.subtask_id = s.id
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE ml.subtask_id = $1 AND f.deleted_at IS NULL
ORDER BY ml.created_at ASC
`
func (q *Queries) GetSubtaskMsgLogs(ctx context.Context, subtaskID sql.NullInt64) ([]Msglog, error) {
rows, err := q.db.QueryContext(ctx, getSubtaskMsgLogs, subtaskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Msglog
for rows.Next() {
var i Msglog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.ResultFormat,
&i.Thinking,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTaskMsgLogs = `-- name: GetTaskMsgLogs :many
SELECT
ml.id, ml.type, ml.message, ml.result, ml.flow_id, ml.task_id, ml.subtask_id, ml.created_at, ml.result_format, ml.thinking
FROM msglogs ml
INNER JOIN tasks t ON ml.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE ml.task_id = $1 AND f.deleted_at IS NULL
ORDER BY ml.created_at ASC
`
func (q *Queries) GetTaskMsgLogs(ctx context.Context, taskID sql.NullInt64) ([]Msglog, error) {
rows, err := q.db.QueryContext(ctx, getTaskMsgLogs, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Msglog
for rows.Next() {
var i Msglog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.ResultFormat,
&i.Thinking,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlowMsgLogs = `-- name: GetUserFlowMsgLogs :many
SELECT
ml.id, ml.type, ml.message, ml.result, ml.flow_id, ml.task_id, ml.subtask_id, ml.created_at, ml.result_format, ml.thinking
FROM msglogs ml
INNER JOIN flows f ON ml.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE ml.flow_id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL
ORDER BY ml.created_at ASC
`
type GetUserFlowMsgLogsParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowMsgLogs(ctx context.Context, arg GetUserFlowMsgLogsParams) ([]Msglog, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowMsgLogs, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Msglog
for rows.Next() {
var i Msglog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.ResultFormat,
&i.Thinking,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateMsgLogResult = `-- name: UpdateMsgLogResult :one
UPDATE msglogs
SET result = $1, result_format = $2
WHERE id = $3
RETURNING id, type, message, result, flow_id, task_id, subtask_id, created_at, result_format, thinking
`
type UpdateMsgLogResultParams struct {
Result string `json:"result"`
ResultFormat MsglogResultFormat `json:"result_format"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateMsgLogResult(ctx context.Context, arg UpdateMsgLogResultParams) (Msglog, error) {
row := q.db.QueryRowContext(ctx, updateMsgLogResult, arg.Result, arg.ResultFormat, arg.ID)
var i Msglog
err := row.Scan(
&i.ID,
&i.Type,
&i.Message,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.ResultFormat,
&i.Thinking,
)
return i, err
}
+277
View File
@@ -0,0 +1,277 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: prompts.sql
package database
import (
"context"
)
const createUserPrompt = `-- name: CreateUserPrompt :one
INSERT INTO prompts (
type,
user_id,
prompt
) VALUES (
$1, $2, $3
)
RETURNING id, type, user_id, prompt, created_at, updated_at
`
type CreateUserPromptParams struct {
Type PromptType `json:"type"`
UserID int64 `json:"user_id"`
Prompt string `json:"prompt"`
}
func (q *Queries) CreateUserPrompt(ctx context.Context, arg CreateUserPromptParams) (Prompt, error) {
row := q.db.QueryRowContext(ctx, createUserPrompt, arg.Type, arg.UserID, arg.Prompt)
var i Prompt
err := row.Scan(
&i.ID,
&i.Type,
&i.UserID,
&i.Prompt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const deletePrompt = `-- name: DeletePrompt :exec
DELETE FROM prompts
WHERE id = $1
`
func (q *Queries) DeletePrompt(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, deletePrompt, id)
return err
}
const deleteUserPrompt = `-- name: DeleteUserPrompt :exec
DELETE FROM prompts
WHERE id = $1 AND user_id = $2
`
type DeleteUserPromptParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) DeleteUserPrompt(ctx context.Context, arg DeleteUserPromptParams) error {
_, err := q.db.ExecContext(ctx, deleteUserPrompt, arg.ID, arg.UserID)
return err
}
const getPrompts = `-- name: GetPrompts :many
SELECT
p.id, p.type, p.user_id, p.prompt, p.created_at, p.updated_at
FROM prompts p
ORDER BY p.user_id ASC, p.type ASC
`
func (q *Queries) GetPrompts(ctx context.Context) ([]Prompt, error) {
rows, err := q.db.QueryContext(ctx, getPrompts)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Prompt
for rows.Next() {
var i Prompt
if err := rows.Scan(
&i.ID,
&i.Type,
&i.UserID,
&i.Prompt,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserPrompt = `-- name: GetUserPrompt :one
SELECT
p.id, p.type, p.user_id, p.prompt, p.created_at, p.updated_at
FROM prompts p
INNER JOIN users u ON p.user_id = u.id
WHERE p.id = $1 AND p.user_id = $2
`
type GetUserPromptParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserPrompt(ctx context.Context, arg GetUserPromptParams) (Prompt, error) {
row := q.db.QueryRowContext(ctx, getUserPrompt, arg.ID, arg.UserID)
var i Prompt
err := row.Scan(
&i.ID,
&i.Type,
&i.UserID,
&i.Prompt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getUserPromptByType = `-- name: GetUserPromptByType :one
SELECT
p.id, p.type, p.user_id, p.prompt, p.created_at, p.updated_at
FROM prompts p
INNER JOIN users u ON p.user_id = u.id
WHERE p.type = $1 AND p.user_id = $2
LIMIT 1
`
type GetUserPromptByTypeParams struct {
Type PromptType `json:"type"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserPromptByType(ctx context.Context, arg GetUserPromptByTypeParams) (Prompt, error) {
row := q.db.QueryRowContext(ctx, getUserPromptByType, arg.Type, arg.UserID)
var i Prompt
err := row.Scan(
&i.ID,
&i.Type,
&i.UserID,
&i.Prompt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getUserPrompts = `-- name: GetUserPrompts :many
SELECT
p.id, p.type, p.user_id, p.prompt, p.created_at, p.updated_at
FROM prompts p
INNER JOIN users u ON p.user_id = u.id
WHERE p.user_id = $1
ORDER BY p.type ASC
`
func (q *Queries) GetUserPrompts(ctx context.Context, userID int64) ([]Prompt, error) {
rows, err := q.db.QueryContext(ctx, getUserPrompts, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Prompt
for rows.Next() {
var i Prompt
if err := rows.Scan(
&i.ID,
&i.Type,
&i.UserID,
&i.Prompt,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updatePrompt = `-- name: UpdatePrompt :one
UPDATE prompts
SET prompt = $1
WHERE id = $2
RETURNING id, type, user_id, prompt, created_at, updated_at
`
type UpdatePromptParams struct {
Prompt string `json:"prompt"`
ID int64 `json:"id"`
}
func (q *Queries) UpdatePrompt(ctx context.Context, arg UpdatePromptParams) (Prompt, error) {
row := q.db.QueryRowContext(ctx, updatePrompt, arg.Prompt, arg.ID)
var i Prompt
err := row.Scan(
&i.ID,
&i.Type,
&i.UserID,
&i.Prompt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const updateUserPrompt = `-- name: UpdateUserPrompt :one
UPDATE prompts
SET prompt = $1
WHERE id = $2 AND user_id = $3
RETURNING id, type, user_id, prompt, created_at, updated_at
`
type UpdateUserPromptParams struct {
Prompt string `json:"prompt"`
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) UpdateUserPrompt(ctx context.Context, arg UpdateUserPromptParams) (Prompt, error) {
row := q.db.QueryRowContext(ctx, updateUserPrompt, arg.Prompt, arg.ID, arg.UserID)
var i Prompt
err := row.Scan(
&i.ID,
&i.Type,
&i.UserID,
&i.Prompt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const updateUserPromptByType = `-- name: UpdateUserPromptByType :one
UPDATE prompts
SET prompt = $1
WHERE type = $2 AND user_id = $3
RETURNING id, type, user_id, prompt, created_at, updated_at
`
type UpdateUserPromptByTypeParams struct {
Prompt string `json:"prompt"`
Type PromptType `json:"type"`
UserID int64 `json:"user_id"`
}
func (q *Queries) UpdateUserPromptByType(ctx context.Context, arg UpdateUserPromptByTypeParams) (Prompt, error) {
row := q.db.QueryRowContext(ctx, updateUserPromptByType, arg.Prompt, arg.Type, arg.UserID)
var i Prompt
err := row.Scan(
&i.ID,
&i.Type,
&i.UserID,
&i.Prompt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
+414
View File
@@ -0,0 +1,414 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: providers.sql
package database
import (
"context"
"encoding/json"
)
const createProvider = `-- name: CreateProvider :one
INSERT INTO providers (
user_id,
type,
name,
config
) VALUES (
$1, $2, $3, $4
)
RETURNING id, user_id, type, name, config, created_at, updated_at, deleted_at
`
type CreateProviderParams struct {
UserID int64 `json:"user_id"`
Type ProviderType `json:"type"`
Name string `json:"name"`
Config json.RawMessage `json:"config"`
}
func (q *Queries) CreateProvider(ctx context.Context, arg CreateProviderParams) (Provider, error) {
row := q.db.QueryRowContext(ctx, createProvider,
arg.UserID,
arg.Type,
arg.Name,
arg.Config,
)
var i Provider
err := row.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const deleteProvider = `-- name: DeleteProvider :one
UPDATE providers
SET deleted_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING id, user_id, type, name, config, created_at, updated_at, deleted_at
`
func (q *Queries) DeleteProvider(ctx context.Context, id int64) (Provider, error) {
row := q.db.QueryRowContext(ctx, deleteProvider, id)
var i Provider
err := row.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const deleteUserProvider = `-- name: DeleteUserProvider :one
UPDATE providers
SET deleted_at = CURRENT_TIMESTAMP
WHERE id = $1 AND user_id = $2
RETURNING id, user_id, type, name, config, created_at, updated_at, deleted_at
`
type DeleteUserProviderParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) DeleteUserProvider(ctx context.Context, arg DeleteUserProviderParams) (Provider, error) {
row := q.db.QueryRowContext(ctx, deleteUserProvider, arg.ID, arg.UserID)
var i Provider
err := row.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const getProvider = `-- name: GetProvider :one
SELECT
p.id, p.user_id, p.type, p.name, p.config, p.created_at, p.updated_at, p.deleted_at
FROM providers p
WHERE p.id = $1 AND p.deleted_at IS NULL
`
func (q *Queries) GetProvider(ctx context.Context, id int64) (Provider, error) {
row := q.db.QueryRowContext(ctx, getProvider, id)
var i Provider
err := row.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const getProviders = `-- name: GetProviders :many
SELECT
p.id, p.user_id, p.type, p.name, p.config, p.created_at, p.updated_at, p.deleted_at
FROM providers p
WHERE p.deleted_at IS NULL
ORDER BY p.created_at ASC
`
func (q *Queries) GetProviders(ctx context.Context) ([]Provider, error) {
rows, err := q.db.QueryContext(ctx, getProviders)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Provider
for rows.Next() {
var i Provider
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getProvidersByType = `-- name: GetProvidersByType :many
SELECT
p.id, p.user_id, p.type, p.name, p.config, p.created_at, p.updated_at, p.deleted_at
FROM providers p
WHERE p.type = $1 AND p.deleted_at IS NULL
ORDER BY p.created_at ASC
`
func (q *Queries) GetProvidersByType(ctx context.Context, type_ ProviderType) ([]Provider, error) {
rows, err := q.db.QueryContext(ctx, getProvidersByType, type_)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Provider
for rows.Next() {
var i Provider
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserProvider = `-- name: GetUserProvider :one
SELECT
p.id, p.user_id, p.type, p.name, p.config, p.created_at, p.updated_at, p.deleted_at
FROM providers p
INNER JOIN users u ON p.user_id = u.id
WHERE p.id = $1 AND p.user_id = $2 AND p.deleted_at IS NULL
`
type GetUserProviderParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserProvider(ctx context.Context, arg GetUserProviderParams) (Provider, error) {
row := q.db.QueryRowContext(ctx, getUserProvider, arg.ID, arg.UserID)
var i Provider
err := row.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const getUserProviderByName = `-- name: GetUserProviderByName :one
SELECT
p.id, p.user_id, p.type, p.name, p.config, p.created_at, p.updated_at, p.deleted_at
FROM providers p
INNER JOIN users u ON p.user_id = u.id
WHERE p.name = $1 AND p.user_id = $2 AND p.deleted_at IS NULL
`
type GetUserProviderByNameParams struct {
Name string `json:"name"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserProviderByName(ctx context.Context, arg GetUserProviderByNameParams) (Provider, error) {
row := q.db.QueryRowContext(ctx, getUserProviderByName, arg.Name, arg.UserID)
var i Provider
err := row.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const getUserProviders = `-- name: GetUserProviders :many
SELECT
p.id, p.user_id, p.type, p.name, p.config, p.created_at, p.updated_at, p.deleted_at
FROM providers p
INNER JOIN users u ON p.user_id = u.id
WHERE p.user_id = $1 AND p.deleted_at IS NULL
ORDER BY p.created_at ASC
`
func (q *Queries) GetUserProviders(ctx context.Context, userID int64) ([]Provider, error) {
rows, err := q.db.QueryContext(ctx, getUserProviders, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Provider
for rows.Next() {
var i Provider
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserProvidersByType = `-- name: GetUserProvidersByType :many
SELECT
p.id, p.user_id, p.type, p.name, p.config, p.created_at, p.updated_at, p.deleted_at
FROM providers p
INNER JOIN users u ON p.user_id = u.id
WHERE p.user_id = $1 AND p.type = $2 AND p.deleted_at IS NULL
ORDER BY p.created_at ASC
`
type GetUserProvidersByTypeParams struct {
UserID int64 `json:"user_id"`
Type ProviderType `json:"type"`
}
func (q *Queries) GetUserProvidersByType(ctx context.Context, arg GetUserProvidersByTypeParams) ([]Provider, error) {
rows, err := q.db.QueryContext(ctx, getUserProvidersByType, arg.UserID, arg.Type)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Provider
for rows.Next() {
var i Provider
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateProvider = `-- name: UpdateProvider :one
UPDATE providers
SET config = $2, name = $3
WHERE id = $1
RETURNING id, user_id, type, name, config, created_at, updated_at, deleted_at
`
type UpdateProviderParams struct {
ID int64 `json:"id"`
Config json.RawMessage `json:"config"`
Name string `json:"name"`
}
func (q *Queries) UpdateProvider(ctx context.Context, arg UpdateProviderParams) (Provider, error) {
row := q.db.QueryRowContext(ctx, updateProvider, arg.ID, arg.Config, arg.Name)
var i Provider
err := row.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
const updateUserProvider = `-- name: UpdateUserProvider :one
UPDATE providers
SET config = $3, name = $4
WHERE id = $1 AND user_id = $2
RETURNING id, user_id, type, name, config, created_at, updated_at, deleted_at
`
type UpdateUserProviderParams struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
Config json.RawMessage `json:"config"`
Name string `json:"name"`
}
func (q *Queries) UpdateUserProvider(ctx context.Context, arg UpdateUserProviderParams) (Provider, error) {
row := q.db.QueryRowContext(ctx, updateUserProvider,
arg.ID,
arg.UserID,
arg.Config,
arg.Name,
)
var i Provider
err := row.Scan(
&i.ID,
&i.UserID,
&i.Type,
&i.Name,
&i.Config,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
)
return i, err
}
+319
View File
@@ -0,0 +1,319 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
package database
import (
"context"
"database/sql"
)
type Querier interface {
AddFavoriteFlow(ctx context.Context, arg AddFavoriteFlowParams) (UserPreference, error)
CreateAPIToken(ctx context.Context, arg CreateAPITokenParams) (ApiToken, error)
CreateAgentLog(ctx context.Context, arg CreateAgentLogParams) (Agentlog, error)
CreateAssistant(ctx context.Context, arg CreateAssistantParams) (Assistant, error)
CreateAssistantLog(ctx context.Context, arg CreateAssistantLogParams) (Assistantlog, error)
CreateContainer(ctx context.Context, arg CreateContainerParams) (Container, error)
CreateFlow(ctx context.Context, arg CreateFlowParams) (Flow, error)
CreateFlowTemplate(ctx context.Context, arg CreateFlowTemplateParams) (FlowTemplate, error)
CreateMsgChain(ctx context.Context, arg CreateMsgChainParams) (Msgchain, error)
CreateMsgLog(ctx context.Context, arg CreateMsgLogParams) (Msglog, error)
CreateProvider(ctx context.Context, arg CreateProviderParams) (Provider, error)
CreateResultAssistantLog(ctx context.Context, arg CreateResultAssistantLogParams) (Assistantlog, error)
CreateResultMsgLog(ctx context.Context, arg CreateResultMsgLogParams) (Msglog, error)
CreateScreenshot(ctx context.Context, arg CreateScreenshotParams) (Screenshot, error)
CreateSearchLog(ctx context.Context, arg CreateSearchLogParams) (Searchlog, error)
CreateSubtask(ctx context.Context, arg CreateSubtaskParams) (Subtask, error)
CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error)
CreateTermLog(ctx context.Context, arg CreateTermLogParams) (Termlog, error)
CreateToolcall(ctx context.Context, arg CreateToolcallParams) (Toolcall, error)
CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
CreateUserPreferences(ctx context.Context, arg CreateUserPreferencesParams) (UserPreference, error)
CreateUserPrompt(ctx context.Context, arg CreateUserPromptParams) (Prompt, error)
CreateVectorStoreLog(ctx context.Context, arg CreateVectorStoreLogParams) (Vecstorelog, error)
DeleteAPIToken(ctx context.Context, id int64) (ApiToken, error)
DeleteAssistant(ctx context.Context, id int64) (Assistant, error)
DeleteFavoriteFlow(ctx context.Context, arg DeleteFavoriteFlowParams) (UserPreference, error)
DeleteFlow(ctx context.Context, id int64) (Flow, error)
DeleteFlowAssistantLog(ctx context.Context, id int64) error
// Delete all memory-type documents for a specific flow.
// Called on flow deletion to free long-term memory that will never be re-used.
// flow_id is the decimal text representation of the flow ID (e.g. "55"), matching the
// text result of (cmetadata ->> 'flow_id') which uses JSON ->> extraction.
DeleteFlowMemoryDocuments(ctx context.Context, flowID sql.NullString) error
DeleteFlowTemplate(ctx context.Context, arg DeleteFlowTemplateParams) error
// Delete a knowledge document by UUID (admin — no user_id check).
DeleteKnowledgeDocument(ctx context.Context, uuid sql.NullString) error
DeletePrompt(ctx context.Context, id int64) error
DeleteProvider(ctx context.Context, id int64) (Provider, error)
DeleteSubtask(ctx context.Context, id int64) error
DeleteSubtasks(ctx context.Context, ids []int64) error
DeleteUser(ctx context.Context, id int64) error
DeleteUserAPIToken(ctx context.Context, arg DeleteUserAPITokenParams) (ApiToken, error)
DeleteUserAPITokenByTokenID(ctx context.Context, arg DeleteUserAPITokenByTokenIDParams) (ApiToken, error)
// Delete a knowledge document by UUID, only if it belongs to the given user.
DeleteUserKnowledgeDocument(ctx context.Context, arg DeleteUserKnowledgeDocumentParams) error
DeleteUserPreferences(ctx context.Context, userID int64) error
DeleteUserPrompt(ctx context.Context, arg DeleteUserPromptParams) error
DeleteUserProvider(ctx context.Context, arg DeleteUserProviderParams) (Provider, error)
GetAPIToken(ctx context.Context, id int64) (ApiToken, error)
GetAPITokenByTokenID(ctx context.Context, tokenID string) (ApiToken, error)
GetAPITokens(ctx context.Context) ([]ApiToken, error)
// Get toolcalls stats for all flows
GetAllFlowsToolcallsStats(ctx context.Context) ([]GetAllFlowsToolcallsStatsRow, error)
GetAllFlowsUsageStats(ctx context.Context) ([]GetAllFlowsUsageStatsRow, error)
GetAllResourcesAll(ctx context.Context) ([]UserResource, error)
GetAllResourcesInDir(ctx context.Context, arg GetAllResourcesInDirParams) ([]UserResource, error)
GetAllResourcesRecursive(ctx context.Context, arg GetAllResourcesRecursiveParams) ([]UserResource, error)
GetAllResourcesRoot(ctx context.Context) ([]UserResource, error)
GetAssistant(ctx context.Context, id int64) (Assistant, error)
GetAssistantUseAgents(ctx context.Context, id int64) (bool, error)
// Get total count of assistants for a specific flow
GetAssistantsCountForFlow(ctx context.Context, flowID int64) (int64, error)
GetCallToolcall(ctx context.Context, callID string) (Toolcall, error)
GetContainerTermLogs(ctx context.Context, containerID int64) ([]Termlog, error)
GetContainers(ctx context.Context) ([]Container, error)
GetFlow(ctx context.Context, id int64) (Flow, error)
GetFlowAgentLog(ctx context.Context, arg GetFlowAgentLogParams) (Agentlog, error)
GetFlowAgentLogs(ctx context.Context, flowID int64) ([]Agentlog, error)
GetFlowAssistant(ctx context.Context, arg GetFlowAssistantParams) (Assistant, error)
GetFlowAssistantLog(ctx context.Context, id int64) (Assistantlog, error)
GetFlowAssistantLogs(ctx context.Context, arg GetFlowAssistantLogsParams) ([]Assistantlog, error)
GetFlowAssistants(ctx context.Context, flowID int64) ([]Assistant, error)
GetFlowContainers(ctx context.Context, flowID int64) ([]Container, error)
GetFlowMsgChains(ctx context.Context, flowID int64) ([]Msgchain, error)
GetFlowMsgLogs(ctx context.Context, flowID int64) ([]Msglog, error)
GetFlowPrimaryContainer(ctx context.Context, flowID int64) (Container, error)
GetFlowScreenshots(ctx context.Context, flowID int64) ([]Screenshot, error)
GetFlowSearchLog(ctx context.Context, arg GetFlowSearchLogParams) (Searchlog, error)
GetFlowSearchLogs(ctx context.Context, flowID int64) ([]Searchlog, error)
// ==================== Flows Analytics Queries ====================
// Get total count of tasks, subtasks, and assistants for a specific flow
GetFlowStats(ctx context.Context, id int64) (GetFlowStatsRow, error)
GetFlowSubtask(ctx context.Context, arg GetFlowSubtaskParams) (Subtask, error)
GetFlowSubtasks(ctx context.Context, flowID int64) ([]Subtask, error)
GetFlowTask(ctx context.Context, arg GetFlowTaskParams) (Task, error)
GetFlowTaskSubtasks(ctx context.Context, arg GetFlowTaskSubtasksParams) ([]Subtask, error)
GetFlowTaskTypeLastMsgChain(ctx context.Context, arg GetFlowTaskTypeLastMsgChainParams) (Msgchain, error)
GetFlowTasks(ctx context.Context, flowID int64) ([]Task, error)
GetFlowTemplate(ctx context.Context, arg GetFlowTemplateParams) (FlowTemplate, error)
GetFlowTemplatesByUserID(ctx context.Context, userID int64) ([]FlowTemplate, error)
GetFlowTermLogs(ctx context.Context, flowID int64) ([]Termlog, error)
GetFlowToolcall(ctx context.Context, arg GetFlowToolcallParams) (Toolcall, error)
GetFlowToolcalls(ctx context.Context, flowID int64) ([]Toolcall, error)
// ==================== Toolcalls Analytics Queries ====================
// Get total execution time and count of toolcalls for a specific flow
GetFlowToolcallsStats(ctx context.Context, flowID int64) (GetFlowToolcallsStatsRow, error)
GetFlowTypeMsgChains(ctx context.Context, arg GetFlowTypeMsgChainsParams) ([]Msgchain, error)
GetFlowUsageStats(ctx context.Context, flowID int64) (GetFlowUsageStatsRow, error)
GetFlowVectorStoreLog(ctx context.Context, arg GetFlowVectorStoreLogParams) (Vecstorelog, error)
GetFlowVectorStoreLogs(ctx context.Context, flowID int64) ([]Vecstorelog, error)
GetFlows(ctx context.Context) ([]Flow, error)
// Get flow IDs created in the last 3 months for analytics
GetFlowsForPeriodLast3Months(ctx context.Context, userID int64) ([]GetFlowsForPeriodLast3MonthsRow, error)
// Get flow IDs created in the last month for analytics
GetFlowsForPeriodLastMonth(ctx context.Context, userID int64) ([]GetFlowsForPeriodLastMonthRow, error)
// Get flow IDs created in the last week for analytics
GetFlowsForPeriodLastWeek(ctx context.Context, userID int64) ([]GetFlowsForPeriodLastWeekRow, error)
// Get flows stats by day for the last 3 months
GetFlowsStatsByDayLast3Months(ctx context.Context, userID int64) ([]GetFlowsStatsByDayLast3MonthsRow, error)
// Get flows stats by day for the last month
GetFlowsStatsByDayLastMonth(ctx context.Context, userID int64) ([]GetFlowsStatsByDayLastMonthRow, error)
// Get flows stats by day for the last week
GetFlowsStatsByDayLastWeek(ctx context.Context, userID int64) ([]GetFlowsStatsByDayLastWeekRow, error)
// Fetch a single knowledge document by its UUID (admin view — no user_id check).
GetKnowledgeDocument(ctx context.Context, uuid string) (GetKnowledgeDocumentRow, error)
GetMsgChain(ctx context.Context, id int64) (Msgchain, error)
// Get all msgchains for a flow (including task and subtask level)
GetMsgchainsForFlow(ctx context.Context, flowID int64) ([]GetMsgchainsForFlowRow, error)
GetPrompts(ctx context.Context) ([]Prompt, error)
GetProvider(ctx context.Context, id int64) (Provider, error)
GetProviders(ctx context.Context) ([]Provider, error)
GetProvidersByType(ctx context.Context, type_ ProviderType) ([]Provider, error)
GetRole(ctx context.Context, id int64) (GetRoleRow, error)
GetRoleByName(ctx context.Context, name string) (GetRoleByNameRow, error)
GetRoles(ctx context.Context) ([]GetRolesRow, error)
GetRunningContainers(ctx context.Context) ([]Container, error)
GetScreenshot(ctx context.Context, id int64) (Screenshot, error)
GetSubtask(ctx context.Context, id int64) (Subtask, error)
GetSubtaskAgentLogs(ctx context.Context, subtaskID sql.NullInt64) ([]Agentlog, error)
GetSubtaskMsgChains(ctx context.Context, subtaskID sql.NullInt64) ([]Msgchain, error)
GetSubtaskMsgLogs(ctx context.Context, subtaskID sql.NullInt64) ([]Msglog, error)
GetSubtaskPrimaryMsgChains(ctx context.Context, subtaskID sql.NullInt64) ([]Msgchain, error)
GetSubtaskScreenshots(ctx context.Context, subtaskID sql.NullInt64) ([]Screenshot, error)
GetSubtaskSearchLogs(ctx context.Context, subtaskID sql.NullInt64) ([]Searchlog, error)
GetSubtaskTermLogs(ctx context.Context, subtaskID sql.NullInt64) ([]Termlog, error)
GetSubtaskToolcalls(ctx context.Context, subtaskID sql.NullInt64) ([]Toolcall, error)
// Get total execution time and count of toolcalls for a specific subtask
GetSubtaskToolcallsStats(ctx context.Context, subtaskID sql.NullInt64) (GetSubtaskToolcallsStatsRow, error)
GetSubtaskTypeMsgChains(ctx context.Context, arg GetSubtaskTypeMsgChainsParams) ([]Msgchain, error)
GetSubtaskUsageStats(ctx context.Context, subtaskID sql.NullInt64) (GetSubtaskUsageStatsRow, error)
GetSubtaskVectorStoreLogs(ctx context.Context, subtaskID sql.NullInt64) ([]Vecstorelog, error)
// Get all subtasks for multiple tasks
GetSubtasksForTasks(ctx context.Context, taskIds []int64) ([]GetSubtasksForTasksRow, error)
GetTask(ctx context.Context, id int64) (Task, error)
GetTaskAgentLogs(ctx context.Context, taskID sql.NullInt64) ([]Agentlog, error)
GetTaskCompletedSubtasks(ctx context.Context, taskID int64) ([]Subtask, error)
GetTaskMsgChains(ctx context.Context, taskID sql.NullInt64) ([]Msgchain, error)
GetTaskMsgLogs(ctx context.Context, taskID sql.NullInt64) ([]Msglog, error)
GetTaskPlannedSubtasks(ctx context.Context, taskID int64) ([]Subtask, error)
GetTaskPrimaryMsgChainIDs(ctx context.Context, taskID sql.NullInt64) ([]GetTaskPrimaryMsgChainIDsRow, error)
GetTaskPrimaryMsgChains(ctx context.Context, taskID sql.NullInt64) ([]Msgchain, error)
GetTaskScreenshots(ctx context.Context, taskID sql.NullInt64) ([]Screenshot, error)
GetTaskSearchLogs(ctx context.Context, taskID sql.NullInt64) ([]Searchlog, error)
GetTaskSubtasks(ctx context.Context, taskID int64) ([]Subtask, error)
GetTaskTermLogs(ctx context.Context, taskID sql.NullInt64) ([]Termlog, error)
// Get total execution time and count of toolcalls for a specific task
GetTaskToolcallsStats(ctx context.Context, taskID sql.NullInt64) (GetTaskToolcallsStatsRow, error)
GetTaskTypeMsgChains(ctx context.Context, arg GetTaskTypeMsgChainsParams) ([]Msgchain, error)
GetTaskUsageStats(ctx context.Context, taskID sql.NullInt64) (GetTaskUsageStatsRow, error)
GetTaskVectorStoreLogs(ctx context.Context, taskID sql.NullInt64) ([]Vecstorelog, error)
// Get all tasks for a flow
GetTasksForFlow(ctx context.Context, flowID int64) ([]GetTasksForFlowRow, error)
GetTermLog(ctx context.Context, id int64) (Termlog, error)
// Get all toolcalls for a flow
GetToolcallsForFlow(ctx context.Context, flowID int64) ([]GetToolcallsForFlowRow, error)
// Get toolcalls stats by day for the last 3 months
GetToolcallsStatsByDayLast3Months(ctx context.Context, userID int64) ([]GetToolcallsStatsByDayLast3MonthsRow, error)
// Get toolcalls stats by day for the last month
GetToolcallsStatsByDayLastMonth(ctx context.Context, userID int64) ([]GetToolcallsStatsByDayLastMonthRow, error)
// Get toolcalls stats by day for the last week
GetToolcallsStatsByDayLastWeek(ctx context.Context, userID int64) ([]GetToolcallsStatsByDayLastWeekRow, error)
// Get toolcalls stats grouped by function name for a user
GetToolcallsStatsByFunction(ctx context.Context, userID int64) ([]GetToolcallsStatsByFunctionRow, error)
// Get toolcalls stats grouped by function name for a specific flow
GetToolcallsStatsByFunctionForFlow(ctx context.Context, flowID int64) ([]GetToolcallsStatsByFunctionForFlowRow, error)
GetUsageStatsByDayLast3Months(ctx context.Context, userID int64) ([]GetUsageStatsByDayLast3MonthsRow, error)
GetUsageStatsByDayLastMonth(ctx context.Context, userID int64) ([]GetUsageStatsByDayLastMonthRow, error)
GetUsageStatsByDayLastWeek(ctx context.Context, userID int64) ([]GetUsageStatsByDayLastWeekRow, error)
GetUsageStatsByModel(ctx context.Context, userID int64) ([]GetUsageStatsByModelRow, error)
GetUsageStatsByModelAgentsForFlow(ctx context.Context, flowID int64) ([]GetUsageStatsByModelAgentsForFlowRow, error)
GetUsageStatsByProvider(ctx context.Context, userID int64) ([]GetUsageStatsByProviderRow, error)
GetUsageStatsByType(ctx context.Context, userID int64) ([]GetUsageStatsByTypeRow, error)
GetUsageStatsByTypeForFlow(ctx context.Context, flowID int64) ([]GetUsageStatsByTypeForFlowRow, error)
GetUser(ctx context.Context, id int64) (GetUserRow, error)
GetUserAPIToken(ctx context.Context, arg GetUserAPITokenParams) (ApiToken, error)
GetUserAPITokenByTokenID(ctx context.Context, arg GetUserAPITokenByTokenIDParams) (ApiToken, error)
GetUserAPITokens(ctx context.Context, userID int64) ([]ApiToken, error)
GetUserByHash(ctx context.Context, hash string) (GetUserByHashRow, error)
GetUserContainers(ctx context.Context, userID int64) ([]Container, error)
GetUserFlow(ctx context.Context, arg GetUserFlowParams) (Flow, error)
GetUserFlowAgentLogs(ctx context.Context, arg GetUserFlowAgentLogsParams) ([]Agentlog, error)
GetUserFlowAssistant(ctx context.Context, arg GetUserFlowAssistantParams) (Assistant, error)
GetUserFlowAssistantLogs(ctx context.Context, arg GetUserFlowAssistantLogsParams) ([]Assistantlog, error)
GetUserFlowAssistants(ctx context.Context, arg GetUserFlowAssistantsParams) ([]Assistant, error)
GetUserFlowContainers(ctx context.Context, arg GetUserFlowContainersParams) ([]Container, error)
GetUserFlowMsgLogs(ctx context.Context, arg GetUserFlowMsgLogsParams) ([]Msglog, error)
GetUserFlowScreenshots(ctx context.Context, arg GetUserFlowScreenshotsParams) ([]Screenshot, error)
GetUserFlowSearchLogs(ctx context.Context, arg GetUserFlowSearchLogsParams) ([]Searchlog, error)
GetUserFlowSubtasks(ctx context.Context, arg GetUserFlowSubtasksParams) ([]Subtask, error)
GetUserFlowTask(ctx context.Context, arg GetUserFlowTaskParams) (Task, error)
GetUserFlowTaskSubtasks(ctx context.Context, arg GetUserFlowTaskSubtasksParams) ([]Subtask, error)
GetUserFlowTasks(ctx context.Context, arg GetUserFlowTasksParams) ([]Task, error)
GetUserFlowTermLogs(ctx context.Context, arg GetUserFlowTermLogsParams) ([]Termlog, error)
GetUserFlowVectorStoreLogs(ctx context.Context, arg GetUserFlowVectorStoreLogsParams) ([]Vecstorelog, error)
GetUserFlows(ctx context.Context, userID int64) ([]Flow, error)
// Fetch a single knowledge document by UUID, scoped to a specific user.
GetUserKnowledgeDocument(ctx context.Context, arg GetUserKnowledgeDocumentParams) (GetUserKnowledgeDocumentRow, error)
GetUserPreferencesByUserID(ctx context.Context, userID int64) (UserPreference, error)
GetUserPrompt(ctx context.Context, arg GetUserPromptParams) (Prompt, error)
GetUserPromptByType(ctx context.Context, arg GetUserPromptByTypeParams) (Prompt, error)
GetUserPrompts(ctx context.Context, userID int64) ([]Prompt, error)
GetUserProvider(ctx context.Context, arg GetUserProviderParams) (Provider, error)
GetUserProviderByName(ctx context.Context, arg GetUserProviderByNameParams) (Provider, error)
GetUserProviders(ctx context.Context, userID int64) ([]Provider, error)
GetUserProvidersByType(ctx context.Context, arg GetUserProvidersByTypeParams) ([]Provider, error)
GetUserResourceByID(ctx context.Context, id int64) (UserResource, error)
GetUserResourcesAll(ctx context.Context, userID int64) ([]UserResource, error)
GetUserResourcesByIDs(ctx context.Context, ids []int64) ([]UserResource, error)
GetUserResourcesInDir(ctx context.Context, arg GetUserResourcesInDirParams) ([]UserResource, error)
GetUserResourcesRecursive(ctx context.Context, arg GetUserResourcesRecursiveParams) ([]UserResource, error)
GetUserResourcesRoot(ctx context.Context, userID int64) ([]UserResource, error)
// Get total count of flows, tasks, subtasks, and assistants for a user
GetUserTotalFlowsStats(ctx context.Context, userID int64) (GetUserTotalFlowsStatsRow, error)
// Get total toolcalls stats for a user
GetUserTotalToolcallsStats(ctx context.Context, userID int64) (GetUserTotalToolcallsStatsRow, error)
GetUserTotalUsageStats(ctx context.Context, userID int64) (GetUserTotalUsageStatsRow, error)
GetUsers(ctx context.Context) ([]GetUsersRow, error)
// Insert a document with a pre-computed embedding vector and return its UUID.
// embedding must be formatted as a PostgreSQL vector literal: '[f1,f2,...]'
// cmetadata must be valid JSON text.
InsertKnowledgeDocument(ctx context.Context, arg InsertKnowledgeDocumentParams) (string, error)
// List all knowledge documents excluding the noisy memory type (admin view).
ListAllKnowledgeDocuments(ctx context.Context) ([]ListAllKnowledgeDocumentsRow, error)
// List non-memory knowledge documents belonging to a specific flow (admin scoped).
ListFlowKnowledgeDocuments(ctx context.Context, flowID sql.NullString) ([]ListFlowKnowledgeDocumentsRow, error)
// List all non-memory knowledge documents owned by a specific user (user-scoped view).
ListUserKnowledgeDocuments(ctx context.Context, userID sql.NullString) ([]ListUserKnowledgeDocumentsRow, error)
// Vector similarity search over all knowledge documents (admin view, no user filter).
// Returns rows ordered by cosine similarity descending (highest score first).
// embedding query vector as a PostgreSQL vector literal, e.g. '[0.1,0.2,...]'
// max_distance cosine-distance upper bound (exclusive); equals (1 - score_threshold),
// e.g. pass 0.8 to get documents with similarity score > 0.2
// lim maximum number of rows to return
SearchKnowledgeDocuments(ctx context.Context, arg SearchKnowledgeDocumentsParams) ([]SearchKnowledgeDocumentsRow, error)
// Vector similarity search scoped to a specific user (by cmetadata user_id).
// Returns rows ordered by cosine similarity descending (highest score first).
// embedding query vector as a PostgreSQL vector literal, e.g. '[0.1,0.2,...]'
// max_distance cosine-distance upper bound (exclusive); equals (1 - score_threshold)
// lim maximum number of rows to return
// user_id owner filter as a decimal text string (e.g. "42")
SearchUserKnowledgeDocuments(ctx context.Context, arg SearchUserKnowledgeDocumentsParams) ([]SearchUserKnowledgeDocumentsRow, error)
UpdateAPIToken(ctx context.Context, arg UpdateAPITokenParams) (ApiToken, error)
UpdateAssistant(ctx context.Context, arg UpdateAssistantParams) (Assistant, error)
UpdateAssistantLanguage(ctx context.Context, arg UpdateAssistantLanguageParams) (Assistant, error)
UpdateAssistantLog(ctx context.Context, arg UpdateAssistantLogParams) (Assistantlog, error)
UpdateAssistantLogContent(ctx context.Context, arg UpdateAssistantLogContentParams) (Assistantlog, error)
UpdateAssistantLogResult(ctx context.Context, arg UpdateAssistantLogResultParams) (Assistantlog, error)
UpdateAssistantModel(ctx context.Context, arg UpdateAssistantModelParams) (Assistant, error)
UpdateAssistantStatus(ctx context.Context, arg UpdateAssistantStatusParams) (Assistant, error)
UpdateAssistantTitle(ctx context.Context, arg UpdateAssistantTitleParams) (Assistant, error)
UpdateAssistantToolCallIDTemplate(ctx context.Context, arg UpdateAssistantToolCallIDTemplateParams) (Assistant, error)
UpdateAssistantUseAgents(ctx context.Context, arg UpdateAssistantUseAgentsParams) (Assistant, error)
UpdateContainerImage(ctx context.Context, arg UpdateContainerImageParams) (Container, error)
UpdateContainerStatus(ctx context.Context, arg UpdateContainerStatusParams) (Container, error)
UpdateContainerStatusLocalID(ctx context.Context, arg UpdateContainerStatusLocalIDParams) (Container, error)
UpdateFlow(ctx context.Context, arg UpdateFlowParams) (Flow, error)
UpdateFlowLanguage(ctx context.Context, arg UpdateFlowLanguageParams) (Flow, error)
UpdateFlowProvider(ctx context.Context, arg UpdateFlowProviderParams) (Flow, error)
UpdateFlowStatus(ctx context.Context, arg UpdateFlowStatusParams) (Flow, error)
UpdateFlowTemplate(ctx context.Context, arg UpdateFlowTemplateParams) (FlowTemplate, error)
UpdateFlowTitle(ctx context.Context, arg UpdateFlowTitleParams) (Flow, error)
UpdateFlowToolCallIDTemplate(ctx context.Context, arg UpdateFlowToolCallIDTemplateParams) (Flow, error)
// Update an existing document's embedding, text and metadata atomically.
// embedding must be formatted as a PostgreSQL vector literal: '[f1,f2,...]'
// cmetadata must be valid JSON text.
UpdateKnowledgeDocument(ctx context.Context, arg UpdateKnowledgeDocumentParams) (UpdateKnowledgeDocumentRow, error)
UpdateMsgChain(ctx context.Context, arg UpdateMsgChainParams) (Msgchain, error)
UpdateMsgChainUsage(ctx context.Context, arg UpdateMsgChainUsageParams) (Msgchain, error)
UpdateMsgLogResult(ctx context.Context, arg UpdateMsgLogResultParams) (Msglog, error)
UpdatePrompt(ctx context.Context, arg UpdatePromptParams) (Prompt, error)
UpdateProvider(ctx context.Context, arg UpdateProviderParams) (Provider, error)
UpdateSubtaskContext(ctx context.Context, arg UpdateSubtaskContextParams) (Subtask, error)
UpdateSubtaskFailedResult(ctx context.Context, arg UpdateSubtaskFailedResultParams) (Subtask, error)
UpdateSubtaskFinishedResult(ctx context.Context, arg UpdateSubtaskFinishedResultParams) (Subtask, error)
UpdateSubtaskResult(ctx context.Context, arg UpdateSubtaskResultParams) (Subtask, error)
UpdateSubtaskStatus(ctx context.Context, arg UpdateSubtaskStatusParams) (Subtask, error)
UpdateTaskFailedResult(ctx context.Context, arg UpdateTaskFailedResultParams) (Task, error)
UpdateTaskFinishedResult(ctx context.Context, arg UpdateTaskFinishedResultParams) (Task, error)
UpdateTaskResult(ctx context.Context, arg UpdateTaskResultParams) (Task, error)
UpdateTaskStatus(ctx context.Context, arg UpdateTaskStatusParams) (Task, error)
UpdateToolcallFailedResult(ctx context.Context, arg UpdateToolcallFailedResultParams) (Toolcall, error)
UpdateToolcallFinishedResult(ctx context.Context, arg UpdateToolcallFinishedResultParams) (Toolcall, error)
UpdateToolcallStatus(ctx context.Context, arg UpdateToolcallStatusParams) (Toolcall, error)
UpdateUserAPIToken(ctx context.Context, arg UpdateUserAPITokenParams) (ApiToken, error)
UpdateUserName(ctx context.Context, arg UpdateUserNameParams) (User, error)
UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) (User, error)
UpdateUserPasswordChangeRequired(ctx context.Context, arg UpdateUserPasswordChangeRequiredParams) (User, error)
UpdateUserPreferences(ctx context.Context, arg UpdateUserPreferencesParams) (UserPreference, error)
UpdateUserPrompt(ctx context.Context, arg UpdateUserPromptParams) (Prompt, error)
UpdateUserPromptByType(ctx context.Context, arg UpdateUserPromptByTypeParams) (Prompt, error)
UpdateUserProvider(ctx context.Context, arg UpdateUserProviderParams) (Provider, error)
UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (User, error)
UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) (User, error)
UpsertUserPreferences(ctx context.Context, arg UpsertUserPreferencesParams) (UserPreference, error)
}
var _ Querier = (*Queries)(nil)
+427
View File
@@ -0,0 +1,427 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: resources.sql
package database
import (
"context"
"github.com/lib/pq"
)
const getAllResourcesAll = `-- name: GetAllResourcesAll :many
SELECT id, user_id, hash, name, path, size, is_dir, created_at, updated_at
FROM user_resources
ORDER BY updated_at DESC, name ASC
`
func (q *Queries) GetAllResourcesAll(ctx context.Context) ([]UserResource, error) {
rows, err := q.db.QueryContext(ctx, getAllResourcesAll)
if err != nil {
return nil, err
}
defer rows.Close()
var items []UserResource
for rows.Next() {
var i UserResource
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Hash,
&i.Name,
&i.Path,
&i.Size,
&i.IsDir,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getAllResourcesInDir = `-- name: GetAllResourcesInDir :many
SELECT id, user_id, hash, name, path, size, is_dir, created_at, updated_at
FROM user_resources
WHERE (path = $1 AND is_dir = true)
OR (path LIKE $2 AND path NOT LIKE $3)
ORDER BY updated_at DESC, name ASC
`
type GetAllResourcesInDirParams struct {
DirPath string `json:"dir_path"`
ChildPrefix string `json:"child_prefix"`
DeepPrefix string `json:"deep_prefix"`
}
func (q *Queries) GetAllResourcesInDir(ctx context.Context, arg GetAllResourcesInDirParams) ([]UserResource, error) {
rows, err := q.db.QueryContext(ctx, getAllResourcesInDir, arg.DirPath, arg.ChildPrefix, arg.DeepPrefix)
if err != nil {
return nil, err
}
defer rows.Close()
var items []UserResource
for rows.Next() {
var i UserResource
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Hash,
&i.Name,
&i.Path,
&i.Size,
&i.IsDir,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getAllResourcesRecursive = `-- name: GetAllResourcesRecursive :many
SELECT id, user_id, hash, name, path, size, is_dir, created_at, updated_at
FROM user_resources
WHERE path = $1 OR path LIKE $2
ORDER BY updated_at DESC, name ASC
`
type GetAllResourcesRecursiveParams struct {
DirPath string `json:"dir_path"`
ChildPrefix string `json:"child_prefix"`
}
func (q *Queries) GetAllResourcesRecursive(ctx context.Context, arg GetAllResourcesRecursiveParams) ([]UserResource, error) {
rows, err := q.db.QueryContext(ctx, getAllResourcesRecursive, arg.DirPath, arg.ChildPrefix)
if err != nil {
return nil, err
}
defer rows.Close()
var items []UserResource
for rows.Next() {
var i UserResource
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Hash,
&i.Name,
&i.Path,
&i.Size,
&i.IsDir,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getAllResourcesRoot = `-- name: GetAllResourcesRoot :many
SELECT id, user_id, hash, name, path, size, is_dir, created_at, updated_at
FROM user_resources
WHERE path NOT LIKE '%/%'
ORDER BY updated_at DESC, name ASC
`
func (q *Queries) GetAllResourcesRoot(ctx context.Context) ([]UserResource, error) {
rows, err := q.db.QueryContext(ctx, getAllResourcesRoot)
if err != nil {
return nil, err
}
defer rows.Close()
var items []UserResource
for rows.Next() {
var i UserResource
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Hash,
&i.Name,
&i.Path,
&i.Size,
&i.IsDir,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserResourceByID = `-- name: GetUserResourceByID :one
SELECT id, user_id, hash, name, path, size, is_dir, created_at, updated_at
FROM user_resources
WHERE id = $1
`
func (q *Queries) GetUserResourceByID(ctx context.Context, id int64) (UserResource, error) {
row := q.db.QueryRowContext(ctx, getUserResourceByID, id)
var i UserResource
err := row.Scan(
&i.ID,
&i.UserID,
&i.Hash,
&i.Name,
&i.Path,
&i.Size,
&i.IsDir,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getUserResourcesAll = `-- name: GetUserResourcesAll :many
SELECT id, user_id, hash, name, path, size, is_dir, created_at, updated_at
FROM user_resources
WHERE user_id = $1
ORDER BY updated_at DESC, name ASC
`
func (q *Queries) GetUserResourcesAll(ctx context.Context, userID int64) ([]UserResource, error) {
rows, err := q.db.QueryContext(ctx, getUserResourcesAll, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []UserResource
for rows.Next() {
var i UserResource
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Hash,
&i.Name,
&i.Path,
&i.Size,
&i.IsDir,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserResourcesByIDs = `-- name: GetUserResourcesByIDs :many
SELECT id, user_id, hash, name, path, size, is_dir, created_at, updated_at
FROM user_resources
WHERE id = ANY($1::bigint[])
ORDER BY id ASC
`
func (q *Queries) GetUserResourcesByIDs(ctx context.Context, ids []int64) ([]UserResource, error) {
rows, err := q.db.QueryContext(ctx, getUserResourcesByIDs, pq.Array(ids))
if err != nil {
return nil, err
}
defer rows.Close()
var items []UserResource
for rows.Next() {
var i UserResource
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Hash,
&i.Name,
&i.Path,
&i.Size,
&i.IsDir,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserResourcesInDir = `-- name: GetUserResourcesInDir :many
SELECT id, user_id, hash, name, path, size, is_dir, created_at, updated_at
FROM user_resources
WHERE user_id = $1
AND ((path = $2 AND is_dir = true)
OR (path LIKE $3 AND path NOT LIKE $4))
ORDER BY updated_at DESC, name ASC
`
type GetUserResourcesInDirParams struct {
UserID int64 `json:"user_id"`
DirPath string `json:"dir_path"`
ChildPrefix string `json:"child_prefix"`
DeepPrefix string `json:"deep_prefix"`
}
func (q *Queries) GetUserResourcesInDir(ctx context.Context, arg GetUserResourcesInDirParams) ([]UserResource, error) {
rows, err := q.db.QueryContext(ctx, getUserResourcesInDir,
arg.UserID,
arg.DirPath,
arg.ChildPrefix,
arg.DeepPrefix,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []UserResource
for rows.Next() {
var i UserResource
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Hash,
&i.Name,
&i.Path,
&i.Size,
&i.IsDir,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserResourcesRecursive = `-- name: GetUserResourcesRecursive :many
SELECT id, user_id, hash, name, path, size, is_dir, created_at, updated_at
FROM user_resources
WHERE user_id = $1
AND (path = $2 OR path LIKE $3)
ORDER BY updated_at DESC, name ASC
`
type GetUserResourcesRecursiveParams struct {
UserID int64 `json:"user_id"`
DirPath string `json:"dir_path"`
ChildPrefix string `json:"child_prefix"`
}
func (q *Queries) GetUserResourcesRecursive(ctx context.Context, arg GetUserResourcesRecursiveParams) ([]UserResource, error) {
rows, err := q.db.QueryContext(ctx, getUserResourcesRecursive, arg.UserID, arg.DirPath, arg.ChildPrefix)
if err != nil {
return nil, err
}
defer rows.Close()
var items []UserResource
for rows.Next() {
var i UserResource
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Hash,
&i.Name,
&i.Path,
&i.Size,
&i.IsDir,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserResourcesRoot = `-- name: GetUserResourcesRoot :many
SELECT id, user_id, hash, name, path, size, is_dir, created_at, updated_at
FROM user_resources
WHERE user_id = $1 AND path NOT LIKE '%/%'
ORDER BY updated_at DESC, name ASC
`
func (q *Queries) GetUserResourcesRoot(ctx context.Context, userID int64) ([]UserResource, error) {
rows, err := q.db.QueryContext(ctx, getUserResourcesRoot, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []UserResource
for rows.Next() {
var i UserResource
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Hash,
&i.Name,
&i.Path,
&i.Size,
&i.IsDir,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
+106
View File
@@ -0,0 +1,106 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: roles.sql
package database
import (
"context"
"github.com/lib/pq"
)
const getRole = `-- name: GetRole :one
SELECT
r.id,
r.name,
(
SELECT ARRAY_AGG(p.name)
FROM privileges p
WHERE p.role_id = r.id
) AS privileges
FROM roles r
WHERE r.id = $1
`
type GetRoleRow struct {
ID int64 `json:"id"`
Name string `json:"name"`
Privileges []string `json:"privileges"`
}
func (q *Queries) GetRole(ctx context.Context, id int64) (GetRoleRow, error) {
row := q.db.QueryRowContext(ctx, getRole, id)
var i GetRoleRow
err := row.Scan(&i.ID, &i.Name, pq.Array(&i.Privileges))
return i, err
}
const getRoleByName = `-- name: GetRoleByName :one
SELECT
r.id,
r.name,
(
SELECT ARRAY_AGG(p.name)
FROM privileges p
WHERE p.role_id = r.id
) AS privileges
FROM roles r
WHERE r.name = $1
`
type GetRoleByNameRow struct {
ID int64 `json:"id"`
Name string `json:"name"`
Privileges []string `json:"privileges"`
}
func (q *Queries) GetRoleByName(ctx context.Context, name string) (GetRoleByNameRow, error) {
row := q.db.QueryRowContext(ctx, getRoleByName, name)
var i GetRoleByNameRow
err := row.Scan(&i.ID, &i.Name, pq.Array(&i.Privileges))
return i, err
}
const getRoles = `-- name: GetRoles :many
SELECT
r.id,
r.name,
(
SELECT ARRAY_AGG(p.name)
FROM privileges p
WHERE p.role_id = r.id
) AS privileges
FROM roles r
ORDER BY r.id ASC
`
type GetRolesRow struct {
ID int64 `json:"id"`
Name string `json:"name"`
Privileges []string `json:"privileges"`
}
func (q *Queries) GetRoles(ctx context.Context) ([]GetRolesRow, error) {
rows, err := q.db.QueryContext(ctx, getRoles)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetRolesRow
for rows.Next() {
var i GetRolesRow
if err := rows.Scan(&i.ID, &i.Name, pq.Array(&i.Privileges)); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
+244
View File
@@ -0,0 +1,244 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: screenshots.sql
package database
import (
"context"
"database/sql"
)
const createScreenshot = `-- name: CreateScreenshot :one
INSERT INTO screenshots (
name,
url,
flow_id,
task_id,
subtask_id
)
VALUES (
$1, $2, $3, $4, $5
)
RETURNING id, name, url, flow_id, created_at, task_id, subtask_id
`
type CreateScreenshotParams struct {
Name string `json:"name"`
Url string `json:"url"`
FlowID int64 `json:"flow_id"`
TaskID sql.NullInt64 `json:"task_id"`
SubtaskID sql.NullInt64 `json:"subtask_id"`
}
func (q *Queries) CreateScreenshot(ctx context.Context, arg CreateScreenshotParams) (Screenshot, error) {
row := q.db.QueryRowContext(ctx, createScreenshot,
arg.Name,
arg.Url,
arg.FlowID,
arg.TaskID,
arg.SubtaskID,
)
var i Screenshot
err := row.Scan(
&i.ID,
&i.Name,
&i.Url,
&i.FlowID,
&i.CreatedAt,
&i.TaskID,
&i.SubtaskID,
)
return i, err
}
const getFlowScreenshots = `-- name: GetFlowScreenshots :many
SELECT
s.id, s.name, s.url, s.flow_id, s.created_at, s.task_id, s.subtask_id
FROM screenshots s
INNER JOIN flows f ON s.flow_id = f.id
WHERE s.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY s.created_at DESC
`
func (q *Queries) GetFlowScreenshots(ctx context.Context, flowID int64) ([]Screenshot, error) {
rows, err := q.db.QueryContext(ctx, getFlowScreenshots, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Screenshot
for rows.Next() {
var i Screenshot
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Url,
&i.FlowID,
&i.CreatedAt,
&i.TaskID,
&i.SubtaskID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getScreenshot = `-- name: GetScreenshot :one
SELECT
s.id, s.name, s.url, s.flow_id, s.created_at, s.task_id, s.subtask_id
FROM screenshots s
WHERE s.id = $1
`
func (q *Queries) GetScreenshot(ctx context.Context, id int64) (Screenshot, error) {
row := q.db.QueryRowContext(ctx, getScreenshot, id)
var i Screenshot
err := row.Scan(
&i.ID,
&i.Name,
&i.Url,
&i.FlowID,
&i.CreatedAt,
&i.TaskID,
&i.SubtaskID,
)
return i, err
}
const getSubtaskScreenshots = `-- name: GetSubtaskScreenshots :many
SELECT
s.id, s.name, s.url, s.flow_id, s.created_at, s.task_id, s.subtask_id
FROM screenshots s
INNER JOIN flows f ON s.flow_id = f.id
INNER JOIN subtasks st ON s.subtask_id = st.id
WHERE s.subtask_id = $1 AND f.deleted_at IS NULL
ORDER BY s.created_at DESC
`
func (q *Queries) GetSubtaskScreenshots(ctx context.Context, subtaskID sql.NullInt64) ([]Screenshot, error) {
rows, err := q.db.QueryContext(ctx, getSubtaskScreenshots, subtaskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Screenshot
for rows.Next() {
var i Screenshot
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Url,
&i.FlowID,
&i.CreatedAt,
&i.TaskID,
&i.SubtaskID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTaskScreenshots = `-- name: GetTaskScreenshots :many
SELECT
s.id, s.name, s.url, s.flow_id, s.created_at, s.task_id, s.subtask_id
FROM screenshots s
INNER JOIN flows f ON s.flow_id = f.id
INNER JOIN tasks t ON s.task_id = t.id
WHERE s.task_id = $1 AND f.deleted_at IS NULL
ORDER BY s.created_at DESC
`
func (q *Queries) GetTaskScreenshots(ctx context.Context, taskID sql.NullInt64) ([]Screenshot, error) {
rows, err := q.db.QueryContext(ctx, getTaskScreenshots, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Screenshot
for rows.Next() {
var i Screenshot
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Url,
&i.FlowID,
&i.CreatedAt,
&i.TaskID,
&i.SubtaskID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlowScreenshots = `-- name: GetUserFlowScreenshots :many
SELECT
s.id, s.name, s.url, s.flow_id, s.created_at, s.task_id, s.subtask_id
FROM screenshots s
INNER JOIN flows f ON s.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE s.flow_id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL
ORDER BY s.created_at DESC
`
type GetUserFlowScreenshotsParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowScreenshots(ctx context.Context, arg GetUserFlowScreenshotsParams) ([]Screenshot, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowScreenshots, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Screenshot
for rows.Next() {
var i Screenshot
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Url,
&i.FlowID,
&i.CreatedAt,
&i.TaskID,
&i.SubtaskID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
+277
View File
@@ -0,0 +1,277 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: searchlogs.sql
package database
import (
"context"
"database/sql"
)
const createSearchLog = `-- name: CreateSearchLog :one
INSERT INTO searchlogs (
initiator,
executor,
engine,
query,
result,
flow_id,
task_id,
subtask_id
)
VALUES (
$1, $2, $3, $4, $5, $6, $7, $8
)
RETURNING id, initiator, executor, engine, query, result, flow_id, task_id, subtask_id, created_at
`
type CreateSearchLogParams struct {
Initiator MsgchainType `json:"initiator"`
Executor MsgchainType `json:"executor"`
Engine SearchengineType `json:"engine"`
Query string `json:"query"`
Result string `json:"result"`
FlowID int64 `json:"flow_id"`
TaskID sql.NullInt64 `json:"task_id"`
SubtaskID sql.NullInt64 `json:"subtask_id"`
}
func (q *Queries) CreateSearchLog(ctx context.Context, arg CreateSearchLogParams) (Searchlog, error) {
row := q.db.QueryRowContext(ctx, createSearchLog,
arg.Initiator,
arg.Executor,
arg.Engine,
arg.Query,
arg.Result,
arg.FlowID,
arg.TaskID,
arg.SubtaskID,
)
var i Searchlog
err := row.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Engine,
&i.Query,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
)
return i, err
}
const getFlowSearchLog = `-- name: GetFlowSearchLog :one
SELECT
sl.id, sl.initiator, sl.executor, sl.engine, sl.query, sl.result, sl.flow_id, sl.task_id, sl.subtask_id, sl.created_at
FROM searchlogs sl
INNER JOIN flows f ON sl.flow_id = f.id
WHERE sl.id = $1 AND sl.flow_id = $2 AND f.deleted_at IS NULL
`
type GetFlowSearchLogParams struct {
ID int64 `json:"id"`
FlowID int64 `json:"flow_id"`
}
func (q *Queries) GetFlowSearchLog(ctx context.Context, arg GetFlowSearchLogParams) (Searchlog, error) {
row := q.db.QueryRowContext(ctx, getFlowSearchLog, arg.ID, arg.FlowID)
var i Searchlog
err := row.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Engine,
&i.Query,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
)
return i, err
}
const getFlowSearchLogs = `-- name: GetFlowSearchLogs :many
SELECT
sl.id, sl.initiator, sl.executor, sl.engine, sl.query, sl.result, sl.flow_id, sl.task_id, sl.subtask_id, sl.created_at
FROM searchlogs sl
INNER JOIN flows f ON sl.flow_id = f.id
WHERE sl.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY sl.created_at ASC
`
func (q *Queries) GetFlowSearchLogs(ctx context.Context, flowID int64) ([]Searchlog, error) {
rows, err := q.db.QueryContext(ctx, getFlowSearchLogs, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Searchlog
for rows.Next() {
var i Searchlog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Engine,
&i.Query,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getSubtaskSearchLogs = `-- name: GetSubtaskSearchLogs :many
SELECT
sl.id, sl.initiator, sl.executor, sl.engine, sl.query, sl.result, sl.flow_id, sl.task_id, sl.subtask_id, sl.created_at
FROM searchlogs sl
INNER JOIN flows f ON sl.flow_id = f.id
INNER JOIN subtasks s ON sl.subtask_id = s.id
WHERE sl.subtask_id = $1 AND f.deleted_at IS NULL
ORDER BY sl.created_at ASC
`
func (q *Queries) GetSubtaskSearchLogs(ctx context.Context, subtaskID sql.NullInt64) ([]Searchlog, error) {
rows, err := q.db.QueryContext(ctx, getSubtaskSearchLogs, subtaskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Searchlog
for rows.Next() {
var i Searchlog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Engine,
&i.Query,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTaskSearchLogs = `-- name: GetTaskSearchLogs :many
SELECT
sl.id, sl.initiator, sl.executor, sl.engine, sl.query, sl.result, sl.flow_id, sl.task_id, sl.subtask_id, sl.created_at
FROM searchlogs sl
INNER JOIN flows f ON sl.flow_id = f.id
INNER JOIN tasks t ON sl.task_id = t.id
WHERE sl.task_id = $1 AND f.deleted_at IS NULL
ORDER BY sl.created_at ASC
`
func (q *Queries) GetTaskSearchLogs(ctx context.Context, taskID sql.NullInt64) ([]Searchlog, error) {
rows, err := q.db.QueryContext(ctx, getTaskSearchLogs, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Searchlog
for rows.Next() {
var i Searchlog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Engine,
&i.Query,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlowSearchLogs = `-- name: GetUserFlowSearchLogs :many
SELECT
sl.id, sl.initiator, sl.executor, sl.engine, sl.query, sl.result, sl.flow_id, sl.task_id, sl.subtask_id, sl.created_at
FROM searchlogs sl
INNER JOIN flows f ON sl.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE sl.flow_id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL
ORDER BY sl.created_at ASC
`
type GetUserFlowSearchLogsParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowSearchLogs(ctx context.Context, arg GetUserFlowSearchLogsParams) ([]Searchlog, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowSearchLogs, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Searchlog
for rows.Next() {
var i Searchlog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Engine,
&i.Query,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
+592
View File
@@ -0,0 +1,592 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: subtasks.sql
package database
import (
"context"
"github.com/lib/pq"
)
const createSubtask = `-- name: CreateSubtask :one
INSERT INTO subtasks (
status,
title,
description,
task_id
) VALUES (
$1, $2, $3, $4
)
RETURNING id, status, title, description, result, task_id, created_at, updated_at, context
`
type CreateSubtaskParams struct {
Status SubtaskStatus `json:"status"`
Title string `json:"title"`
Description string `json:"description"`
TaskID int64 `json:"task_id"`
}
func (q *Queries) CreateSubtask(ctx context.Context, arg CreateSubtaskParams) (Subtask, error) {
row := q.db.QueryRowContext(ctx, createSubtask,
arg.Status,
arg.Title,
arg.Description,
arg.TaskID,
)
var i Subtask
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
)
return i, err
}
const deleteSubtask = `-- name: DeleteSubtask :exec
DELETE FROM subtasks
WHERE id = $1
`
func (q *Queries) DeleteSubtask(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, deleteSubtask, id)
return err
}
const deleteSubtasks = `-- name: DeleteSubtasks :exec
DELETE FROM subtasks
WHERE id = ANY($1::BIGINT[])
`
func (q *Queries) DeleteSubtasks(ctx context.Context, ids []int64) error {
_, err := q.db.ExecContext(ctx, deleteSubtasks, pq.Array(ids))
return err
}
const getFlowSubtask = `-- name: GetFlowSubtask :one
SELECT
s.id, s.status, s.title, s.description, s.result, s.task_id, s.created_at, s.updated_at, s.context
FROM subtasks s
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE s.id = $1 AND t.flow_id = $2 AND f.deleted_at IS NULL
`
type GetFlowSubtaskParams struct {
ID int64 `json:"id"`
FlowID int64 `json:"flow_id"`
}
func (q *Queries) GetFlowSubtask(ctx context.Context, arg GetFlowSubtaskParams) (Subtask, error) {
row := q.db.QueryRowContext(ctx, getFlowSubtask, arg.ID, arg.FlowID)
var i Subtask
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
)
return i, err
}
const getFlowSubtasks = `-- name: GetFlowSubtasks :many
SELECT
s.id, s.status, s.title, s.description, s.result, s.task_id, s.created_at, s.updated_at, s.context
FROM subtasks s
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE t.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY s.created_at ASC
`
func (q *Queries) GetFlowSubtasks(ctx context.Context, flowID int64) ([]Subtask, error) {
rows, err := q.db.QueryContext(ctx, getFlowSubtasks, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Subtask
for rows.Next() {
var i Subtask
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFlowTaskSubtasks = `-- name: GetFlowTaskSubtasks :many
SELECT
s.id, s.status, s.title, s.description, s.result, s.task_id, s.created_at, s.updated_at, s.context
FROM subtasks s
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE s.task_id = $1 AND t.flow_id = $2 AND f.deleted_at IS NULL
ORDER BY s.created_at ASC
`
type GetFlowTaskSubtasksParams struct {
TaskID int64 `json:"task_id"`
FlowID int64 `json:"flow_id"`
}
func (q *Queries) GetFlowTaskSubtasks(ctx context.Context, arg GetFlowTaskSubtasksParams) ([]Subtask, error) {
rows, err := q.db.QueryContext(ctx, getFlowTaskSubtasks, arg.TaskID, arg.FlowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Subtask
for rows.Next() {
var i Subtask
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getSubtask = `-- name: GetSubtask :one
SELECT
s.id, s.status, s.title, s.description, s.result, s.task_id, s.created_at, s.updated_at, s.context
FROM subtasks s
WHERE s.id = $1
`
func (q *Queries) GetSubtask(ctx context.Context, id int64) (Subtask, error) {
row := q.db.QueryRowContext(ctx, getSubtask, id)
var i Subtask
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
)
return i, err
}
const getTaskCompletedSubtasks = `-- name: GetTaskCompletedSubtasks :many
SELECT
s.id, s.status, s.title, s.description, s.result, s.task_id, s.created_at, s.updated_at, s.context
FROM subtasks s
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE s.task_id = $1 AND (s.status != 'created' AND s.status != 'waiting') AND f.deleted_at IS NULL
ORDER BY s.id ASC
`
func (q *Queries) GetTaskCompletedSubtasks(ctx context.Context, taskID int64) ([]Subtask, error) {
rows, err := q.db.QueryContext(ctx, getTaskCompletedSubtasks, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Subtask
for rows.Next() {
var i Subtask
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTaskPlannedSubtasks = `-- name: GetTaskPlannedSubtasks :many
SELECT
s.id, s.status, s.title, s.description, s.result, s.task_id, s.created_at, s.updated_at, s.context
FROM subtasks s
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE s.task_id = $1 AND (s.status = 'created' OR s.status = 'waiting') AND f.deleted_at IS NULL
ORDER BY s.id ASC
`
func (q *Queries) GetTaskPlannedSubtasks(ctx context.Context, taskID int64) ([]Subtask, error) {
rows, err := q.db.QueryContext(ctx, getTaskPlannedSubtasks, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Subtask
for rows.Next() {
var i Subtask
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTaskSubtasks = `-- name: GetTaskSubtasks :many
SELECT
s.id, s.status, s.title, s.description, s.result, s.task_id, s.created_at, s.updated_at, s.context
FROM subtasks s
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE s.task_id = $1 AND f.deleted_at IS NULL
ORDER BY s.created_at DESC
`
func (q *Queries) GetTaskSubtasks(ctx context.Context, taskID int64) ([]Subtask, error) {
rows, err := q.db.QueryContext(ctx, getTaskSubtasks, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Subtask
for rows.Next() {
var i Subtask
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlowSubtasks = `-- name: GetUserFlowSubtasks :many
SELECT
s.id, s.status, s.title, s.description, s.result, s.task_id, s.created_at, s.updated_at, s.context
FROM subtasks s
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE t.flow_id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL
ORDER BY s.created_at ASC
`
type GetUserFlowSubtasksParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowSubtasks(ctx context.Context, arg GetUserFlowSubtasksParams) ([]Subtask, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowSubtasks, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Subtask
for rows.Next() {
var i Subtask
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlowTaskSubtasks = `-- name: GetUserFlowTaskSubtasks :many
SELECT
s.id, s.status, s.title, s.description, s.result, s.task_id, s.created_at, s.updated_at, s.context
FROM subtasks s
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE s.task_id = $1 AND t.flow_id = $2 AND f.user_id = $3 AND f.deleted_at IS NULL
ORDER BY s.created_at ASC
`
type GetUserFlowTaskSubtasksParams struct {
TaskID int64 `json:"task_id"`
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowTaskSubtasks(ctx context.Context, arg GetUserFlowTaskSubtasksParams) ([]Subtask, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowTaskSubtasks, arg.TaskID, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Subtask
for rows.Next() {
var i Subtask
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateSubtaskContext = `-- name: UpdateSubtaskContext :one
UPDATE subtasks
SET context = $1
WHERE id = $2
RETURNING id, status, title, description, result, task_id, created_at, updated_at, context
`
type UpdateSubtaskContextParams struct {
Context string `json:"context"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateSubtaskContext(ctx context.Context, arg UpdateSubtaskContextParams) (Subtask, error) {
row := q.db.QueryRowContext(ctx, updateSubtaskContext, arg.Context, arg.ID)
var i Subtask
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
)
return i, err
}
const updateSubtaskFailedResult = `-- name: UpdateSubtaskFailedResult :one
UPDATE subtasks
SET status = 'failed', result = $1
WHERE id = $2
RETURNING id, status, title, description, result, task_id, created_at, updated_at, context
`
type UpdateSubtaskFailedResultParams struct {
Result string `json:"result"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateSubtaskFailedResult(ctx context.Context, arg UpdateSubtaskFailedResultParams) (Subtask, error) {
row := q.db.QueryRowContext(ctx, updateSubtaskFailedResult, arg.Result, arg.ID)
var i Subtask
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
)
return i, err
}
const updateSubtaskFinishedResult = `-- name: UpdateSubtaskFinishedResult :one
UPDATE subtasks
SET status = 'finished', result = $1
WHERE id = $2
RETURNING id, status, title, description, result, task_id, created_at, updated_at, context
`
type UpdateSubtaskFinishedResultParams struct {
Result string `json:"result"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateSubtaskFinishedResult(ctx context.Context, arg UpdateSubtaskFinishedResultParams) (Subtask, error) {
row := q.db.QueryRowContext(ctx, updateSubtaskFinishedResult, arg.Result, arg.ID)
var i Subtask
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
)
return i, err
}
const updateSubtaskResult = `-- name: UpdateSubtaskResult :one
UPDATE subtasks
SET result = $1
WHERE id = $2
RETURNING id, status, title, description, result, task_id, created_at, updated_at, context
`
type UpdateSubtaskResultParams struct {
Result string `json:"result"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateSubtaskResult(ctx context.Context, arg UpdateSubtaskResultParams) (Subtask, error) {
row := q.db.QueryRowContext(ctx, updateSubtaskResult, arg.Result, arg.ID)
var i Subtask
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
)
return i, err
}
const updateSubtaskStatus = `-- name: UpdateSubtaskStatus :one
UPDATE subtasks
SET status = $1
WHERE id = $2
RETURNING id, status, title, description, result, task_id, created_at, updated_at, context
`
type UpdateSubtaskStatusParams struct {
Status SubtaskStatus `json:"status"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateSubtaskStatus(ctx context.Context, arg UpdateSubtaskStatusParams) (Subtask, error) {
row := q.db.QueryRowContext(ctx, updateSubtaskStatus, arg.Status, arg.ID)
var i Subtask
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Description,
&i.Result,
&i.TaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Context,
)
return i, err
}
+333
View File
@@ -0,0 +1,333 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: tasks.sql
package database
import (
"context"
)
const createTask = `-- name: CreateTask :one
INSERT INTO tasks (
status,
title,
input,
flow_id
) VALUES (
$1, $2, $3, $4
)
RETURNING id, status, title, input, result, flow_id, created_at, updated_at
`
type CreateTaskParams struct {
Status TaskStatus `json:"status"`
Title string `json:"title"`
Input string `json:"input"`
FlowID int64 `json:"flow_id"`
}
func (q *Queries) CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error) {
row := q.db.QueryRowContext(ctx, createTask,
arg.Status,
arg.Title,
arg.Input,
arg.FlowID,
)
var i Task
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Input,
&i.Result,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getFlowTask = `-- name: GetFlowTask :one
SELECT
t.id, t.status, t.title, t.input, t.result, t.flow_id, t.created_at, t.updated_at
FROM tasks t
INNER JOIN flows f ON t.flow_id = f.id
WHERE t.id = $1 AND t.flow_id = $2 AND f.deleted_at IS NULL
`
type GetFlowTaskParams struct {
ID int64 `json:"id"`
FlowID int64 `json:"flow_id"`
}
func (q *Queries) GetFlowTask(ctx context.Context, arg GetFlowTaskParams) (Task, error) {
row := q.db.QueryRowContext(ctx, getFlowTask, arg.ID, arg.FlowID)
var i Task
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Input,
&i.Result,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getFlowTasks = `-- name: GetFlowTasks :many
SELECT
t.id, t.status, t.title, t.input, t.result, t.flow_id, t.created_at, t.updated_at
FROM tasks t
INNER JOIN flows f ON t.flow_id = f.id
WHERE t.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY t.created_at ASC
`
func (q *Queries) GetFlowTasks(ctx context.Context, flowID int64) ([]Task, error) {
rows, err := q.db.QueryContext(ctx, getFlowTasks, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Task
for rows.Next() {
var i Task
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Input,
&i.Result,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTask = `-- name: GetTask :one
SELECT
t.id, t.status, t.title, t.input, t.result, t.flow_id, t.created_at, t.updated_at
FROM tasks t
WHERE t.id = $1
`
func (q *Queries) GetTask(ctx context.Context, id int64) (Task, error) {
row := q.db.QueryRowContext(ctx, getTask, id)
var i Task
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Input,
&i.Result,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getUserFlowTask = `-- name: GetUserFlowTask :one
SELECT
t.id, t.status, t.title, t.input, t.result, t.flow_id, t.created_at, t.updated_at
FROM tasks t
INNER JOIN flows f ON t.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE t.id = $1 AND t.flow_id = $2 AND f.user_id = $3 AND f.deleted_at IS NULL
`
type GetUserFlowTaskParams struct {
ID int64 `json:"id"`
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowTask(ctx context.Context, arg GetUserFlowTaskParams) (Task, error) {
row := q.db.QueryRowContext(ctx, getUserFlowTask, arg.ID, arg.FlowID, arg.UserID)
var i Task
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Input,
&i.Result,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getUserFlowTasks = `-- name: GetUserFlowTasks :many
SELECT
t.id, t.status, t.title, t.input, t.result, t.flow_id, t.created_at, t.updated_at
FROM tasks t
INNER JOIN flows f ON t.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE t.flow_id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL
ORDER BY t.created_at ASC
`
type GetUserFlowTasksParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowTasks(ctx context.Context, arg GetUserFlowTasksParams) ([]Task, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowTasks, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Task
for rows.Next() {
var i Task
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Input,
&i.Result,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateTaskFailedResult = `-- name: UpdateTaskFailedResult :one
UPDATE tasks
SET status = 'failed', result = $1
WHERE id = $2
RETURNING id, status, title, input, result, flow_id, created_at, updated_at
`
type UpdateTaskFailedResultParams struct {
Result string `json:"result"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateTaskFailedResult(ctx context.Context, arg UpdateTaskFailedResultParams) (Task, error) {
row := q.db.QueryRowContext(ctx, updateTaskFailedResult, arg.Result, arg.ID)
var i Task
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Input,
&i.Result,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const updateTaskFinishedResult = `-- name: UpdateTaskFinishedResult :one
UPDATE tasks
SET status = 'finished', result = $1
WHERE id = $2
RETURNING id, status, title, input, result, flow_id, created_at, updated_at
`
type UpdateTaskFinishedResultParams struct {
Result string `json:"result"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateTaskFinishedResult(ctx context.Context, arg UpdateTaskFinishedResultParams) (Task, error) {
row := q.db.QueryRowContext(ctx, updateTaskFinishedResult, arg.Result, arg.ID)
var i Task
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Input,
&i.Result,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const updateTaskResult = `-- name: UpdateTaskResult :one
UPDATE tasks
SET result = $1
WHERE id = $2
RETURNING id, status, title, input, result, flow_id, created_at, updated_at
`
type UpdateTaskResultParams struct {
Result string `json:"result"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateTaskResult(ctx context.Context, arg UpdateTaskResultParams) (Task, error) {
row := q.db.QueryRowContext(ctx, updateTaskResult, arg.Result, arg.ID)
var i Task
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Input,
&i.Result,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const updateTaskStatus = `-- name: UpdateTaskStatus :one
UPDATE tasks
SET status = $1
WHERE id = $2
RETURNING id, status, title, input, result, flow_id, created_at, updated_at
`
type UpdateTaskStatusParams struct {
Status TaskStatus `json:"status"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateTaskStatus(ctx context.Context, arg UpdateTaskStatusParams) (Task, error) {
row := q.db.QueryRowContext(ctx, updateTaskStatus, arg.Status, arg.ID)
var i Task
err := row.Scan(
&i.ID,
&i.Status,
&i.Title,
&i.Input,
&i.Result,
&i.FlowID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
+292
View File
@@ -0,0 +1,292 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: termlogs.sql
package database
import (
"context"
"database/sql"
)
const createTermLog = `-- name: CreateTermLog :one
INSERT INTO termlogs (
type,
text,
container_id,
flow_id,
task_id,
subtask_id
)
VALUES (
$1, $2, $3, $4, $5, $6
)
RETURNING id, type, text, container_id, created_at, flow_id, task_id, subtask_id
`
type CreateTermLogParams struct {
Type TermlogType `json:"type"`
Text string `json:"text"`
ContainerID int64 `json:"container_id"`
FlowID int64 `json:"flow_id"`
TaskID sql.NullInt64 `json:"task_id"`
SubtaskID sql.NullInt64 `json:"subtask_id"`
}
func (q *Queries) CreateTermLog(ctx context.Context, arg CreateTermLogParams) (Termlog, error) {
row := q.db.QueryRowContext(ctx, createTermLog,
arg.Type,
arg.Text,
arg.ContainerID,
arg.FlowID,
arg.TaskID,
arg.SubtaskID,
)
var i Termlog
err := row.Scan(
&i.ID,
&i.Type,
&i.Text,
&i.ContainerID,
&i.CreatedAt,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
)
return i, err
}
const getContainerTermLogs = `-- name: GetContainerTermLogs :many
SELECT
tl.id, tl.type, tl.text, tl.container_id, tl.created_at, tl.flow_id, tl.task_id, tl.subtask_id
FROM termlogs tl
INNER JOIN flows f ON tl.flow_id = f.id
WHERE tl.container_id = $1 AND f.deleted_at IS NULL
ORDER BY tl.created_at ASC
`
func (q *Queries) GetContainerTermLogs(ctx context.Context, containerID int64) ([]Termlog, error) {
rows, err := q.db.QueryContext(ctx, getContainerTermLogs, containerID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Termlog
for rows.Next() {
var i Termlog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Text,
&i.ContainerID,
&i.CreatedAt,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFlowTermLogs = `-- name: GetFlowTermLogs :many
SELECT
tl.id, tl.type, tl.text, tl.container_id, tl.created_at, tl.flow_id, tl.task_id, tl.subtask_id
FROM termlogs tl
INNER JOIN flows f ON tl.flow_id = f.id
WHERE tl.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY tl.created_at ASC
`
func (q *Queries) GetFlowTermLogs(ctx context.Context, flowID int64) ([]Termlog, error) {
rows, err := q.db.QueryContext(ctx, getFlowTermLogs, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Termlog
for rows.Next() {
var i Termlog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Text,
&i.ContainerID,
&i.CreatedAt,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getSubtaskTermLogs = `-- name: GetSubtaskTermLogs :many
SELECT
tl.id, tl.type, tl.text, tl.container_id, tl.created_at, tl.flow_id, tl.task_id, tl.subtask_id
FROM termlogs tl
INNER JOIN flows f ON tl.flow_id = f.id
WHERE tl.subtask_id = $1 AND f.deleted_at IS NULL
ORDER BY tl.created_at ASC
`
func (q *Queries) GetSubtaskTermLogs(ctx context.Context, subtaskID sql.NullInt64) ([]Termlog, error) {
rows, err := q.db.QueryContext(ctx, getSubtaskTermLogs, subtaskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Termlog
for rows.Next() {
var i Termlog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Text,
&i.ContainerID,
&i.CreatedAt,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTaskTermLogs = `-- name: GetTaskTermLogs :many
SELECT
tl.id, tl.type, tl.text, tl.container_id, tl.created_at, tl.flow_id, tl.task_id, tl.subtask_id
FROM termlogs tl
INNER JOIN flows f ON tl.flow_id = f.id
WHERE tl.task_id = $1 AND f.deleted_at IS NULL
ORDER BY tl.created_at ASC
`
func (q *Queries) GetTaskTermLogs(ctx context.Context, taskID sql.NullInt64) ([]Termlog, error) {
rows, err := q.db.QueryContext(ctx, getTaskTermLogs, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Termlog
for rows.Next() {
var i Termlog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Text,
&i.ContainerID,
&i.CreatedAt,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTermLog = `-- name: GetTermLog :one
SELECT
tl.id, tl.type, tl.text, tl.container_id, tl.created_at, tl.flow_id, tl.task_id, tl.subtask_id
FROM termlogs tl
WHERE tl.id = $1
`
func (q *Queries) GetTermLog(ctx context.Context, id int64) (Termlog, error) {
row := q.db.QueryRowContext(ctx, getTermLog, id)
var i Termlog
err := row.Scan(
&i.ID,
&i.Type,
&i.Text,
&i.ContainerID,
&i.CreatedAt,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
)
return i, err
}
const getUserFlowTermLogs = `-- name: GetUserFlowTermLogs :many
SELECT
tl.id, tl.type, tl.text, tl.container_id, tl.created_at, tl.flow_id, tl.task_id, tl.subtask_id
FROM termlogs tl
INNER JOIN flows f ON tl.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE tl.flow_id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL
ORDER BY tl.created_at ASC
`
type GetUserFlowTermLogsParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowTermLogs(ctx context.Context, arg GetUserFlowTermLogsParams) ([]Termlog, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowTermLogs, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Termlog
for rows.Next() {
var i Termlog
if err := rows.Scan(
&i.ID,
&i.Type,
&i.Text,
&i.ContainerID,
&i.CreatedAt,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
+706
View File
@@ -0,0 +1,706 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: toolcalls.sql
package database
import (
"context"
"database/sql"
"encoding/json"
"time"
)
const createToolcall = `-- name: CreateToolcall :one
INSERT INTO toolcalls (
call_id,
status,
name,
args,
flow_id,
task_id,
subtask_id
) VALUES (
$1, $2, $3, $4, $5, $6, $7
)
RETURNING id, call_id, status, name, args, result, flow_id, task_id, subtask_id, created_at, updated_at, duration_seconds
`
type CreateToolcallParams struct {
CallID string `json:"call_id"`
Status ToolcallStatus `json:"status"`
Name string `json:"name"`
Args json.RawMessage `json:"args"`
FlowID int64 `json:"flow_id"`
TaskID sql.NullInt64 `json:"task_id"`
SubtaskID sql.NullInt64 `json:"subtask_id"`
}
func (q *Queries) CreateToolcall(ctx context.Context, arg CreateToolcallParams) (Toolcall, error) {
row := q.db.QueryRowContext(ctx, createToolcall,
arg.CallID,
arg.Status,
arg.Name,
arg.Args,
arg.FlowID,
arg.TaskID,
arg.SubtaskID,
)
var i Toolcall
err := row.Scan(
&i.ID,
&i.CallID,
&i.Status,
&i.Name,
&i.Args,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DurationSeconds,
)
return i, err
}
const getAllFlowsToolcallsStats = `-- name: GetAllFlowsToolcallsStats :many
SELECT
COALESCE(tc.flow_id, t.flow_id) AS flow_id,
COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
LEFT JOIN subtasks s ON tc.subtask_id = s.id
LEFT JOIN tasks t ON s.task_id = t.id OR tc.task_id = t.id
INNER JOIN flows f ON (tc.flow_id = f.id OR t.flow_id = f.id)
WHERE f.deleted_at IS NULL
GROUP BY COALESCE(tc.flow_id, t.flow_id)
ORDER BY COALESCE(tc.flow_id, t.flow_id)
`
type GetAllFlowsToolcallsStatsRow struct {
FlowID int64 `json:"flow_id"`
TotalCount int64 `json:"total_count"`
TotalDurationSeconds float64 `json:"total_duration_seconds"`
}
// Get toolcalls stats for all flows
func (q *Queries) GetAllFlowsToolcallsStats(ctx context.Context) ([]GetAllFlowsToolcallsStatsRow, error) {
rows, err := q.db.QueryContext(ctx, getAllFlowsToolcallsStats)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetAllFlowsToolcallsStatsRow
for rows.Next() {
var i GetAllFlowsToolcallsStatsRow
if err := rows.Scan(&i.FlowID, &i.TotalCount, &i.TotalDurationSeconds); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getCallToolcall = `-- name: GetCallToolcall :one
SELECT
tc.id, tc.call_id, tc.status, tc.name, tc.args, tc.result, tc.flow_id, tc.task_id, tc.subtask_id, tc.created_at, tc.updated_at, tc.duration_seconds
FROM toolcalls tc
WHERE tc.call_id = $1
`
func (q *Queries) GetCallToolcall(ctx context.Context, callID string) (Toolcall, error) {
row := q.db.QueryRowContext(ctx, getCallToolcall, callID)
var i Toolcall
err := row.Scan(
&i.ID,
&i.CallID,
&i.Status,
&i.Name,
&i.Args,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DurationSeconds,
)
return i, err
}
const getFlowToolcall = `-- name: GetFlowToolcall :one
SELECT
tc.id, tc.call_id, tc.status, tc.name, tc.args, tc.result, tc.flow_id, tc.task_id, tc.subtask_id, tc.created_at, tc.updated_at, tc.duration_seconds
FROM toolcalls tc
INNER JOIN flows f ON tc.flow_id = f.id
WHERE tc.id = $1 AND tc.flow_id = $2 AND f.deleted_at IS NULL
`
type GetFlowToolcallParams struct {
ID int64 `json:"id"`
FlowID int64 `json:"flow_id"`
}
func (q *Queries) GetFlowToolcall(ctx context.Context, arg GetFlowToolcallParams) (Toolcall, error) {
row := q.db.QueryRowContext(ctx, getFlowToolcall, arg.ID, arg.FlowID)
var i Toolcall
err := row.Scan(
&i.ID,
&i.CallID,
&i.Status,
&i.Name,
&i.Args,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DurationSeconds,
)
return i, err
}
const getFlowToolcalls = `-- name: GetFlowToolcalls :many
SELECT
tc.id, tc.call_id, tc.status, tc.name, tc.args, tc.result, tc.flow_id, tc.task_id, tc.subtask_id, tc.created_at, tc.updated_at, tc.duration_seconds
FROM toolcalls tc
INNER JOIN flows f ON tc.flow_id = f.id
WHERE tc.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY tc.created_at ASC
`
func (q *Queries) GetFlowToolcalls(ctx context.Context, flowID int64) ([]Toolcall, error) {
rows, err := q.db.QueryContext(ctx, getFlowToolcalls, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Toolcall
for rows.Next() {
var i Toolcall
if err := rows.Scan(
&i.ID,
&i.CallID,
&i.Status,
&i.Name,
&i.Args,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DurationSeconds,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFlowToolcallsStats = `-- name: GetFlowToolcallsStats :one
SELECT
COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
LEFT JOIN tasks t ON tc.task_id = t.id
LEFT JOIN subtasks s ON tc.subtask_id = s.id
INNER JOIN flows f ON tc.flow_id = f.id
WHERE tc.flow_id = $1 AND f.deleted_at IS NULL
AND (tc.task_id IS NULL OR t.id IS NOT NULL)
AND (tc.subtask_id IS NULL OR s.id IS NOT NULL)
`
type GetFlowToolcallsStatsRow struct {
TotalCount int64 `json:"total_count"`
TotalDurationSeconds float64 `json:"total_duration_seconds"`
}
// ==================== Toolcalls Analytics Queries ====================
// Get total execution time and count of toolcalls for a specific flow
func (q *Queries) GetFlowToolcallsStats(ctx context.Context, flowID int64) (GetFlowToolcallsStatsRow, error) {
row := q.db.QueryRowContext(ctx, getFlowToolcallsStats, flowID)
var i GetFlowToolcallsStatsRow
err := row.Scan(&i.TotalCount, &i.TotalDurationSeconds)
return i, err
}
const getSubtaskToolcalls = `-- name: GetSubtaskToolcalls :many
SELECT
tc.id, tc.call_id, tc.status, tc.name, tc.args, tc.result, tc.flow_id, tc.task_id, tc.subtask_id, tc.created_at, tc.updated_at, tc.duration_seconds
FROM toolcalls tc
INNER JOIN subtasks s ON tc.subtask_id = s.id
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE tc.subtask_id = $1 AND f.deleted_at IS NULL
ORDER BY tc.created_at DESC
`
func (q *Queries) GetSubtaskToolcalls(ctx context.Context, subtaskID sql.NullInt64) ([]Toolcall, error) {
rows, err := q.db.QueryContext(ctx, getSubtaskToolcalls, subtaskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Toolcall
for rows.Next() {
var i Toolcall
if err := rows.Scan(
&i.ID,
&i.CallID,
&i.Status,
&i.Name,
&i.Args,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DurationSeconds,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getSubtaskToolcallsStats = `-- name: GetSubtaskToolcallsStats :one
SELECT
COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
INNER JOIN subtasks s ON tc.subtask_id = s.id
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE tc.subtask_id = $1 AND f.deleted_at IS NULL AND s.id IS NOT NULL AND t.id IS NOT NULL
`
type GetSubtaskToolcallsStatsRow struct {
TotalCount int64 `json:"total_count"`
TotalDurationSeconds float64 `json:"total_duration_seconds"`
}
// Get total execution time and count of toolcalls for a specific subtask
func (q *Queries) GetSubtaskToolcallsStats(ctx context.Context, subtaskID sql.NullInt64) (GetSubtaskToolcallsStatsRow, error) {
row := q.db.QueryRowContext(ctx, getSubtaskToolcallsStats, subtaskID)
var i GetSubtaskToolcallsStatsRow
err := row.Scan(&i.TotalCount, &i.TotalDurationSeconds)
return i, err
}
const getTaskToolcallsStats = `-- name: GetTaskToolcallsStats :one
SELECT
COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
LEFT JOIN subtasks s ON tc.subtask_id = s.id
INNER JOIN tasks t ON tc.task_id = t.id OR s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE (tc.task_id = $1 OR s.task_id = $1) AND f.deleted_at IS NULL
AND (tc.subtask_id IS NULL OR s.id IS NOT NULL)
`
type GetTaskToolcallsStatsRow struct {
TotalCount int64 `json:"total_count"`
TotalDurationSeconds float64 `json:"total_duration_seconds"`
}
// Get total execution time and count of toolcalls for a specific task
func (q *Queries) GetTaskToolcallsStats(ctx context.Context, taskID sql.NullInt64) (GetTaskToolcallsStatsRow, error) {
row := q.db.QueryRowContext(ctx, getTaskToolcallsStats, taskID)
var i GetTaskToolcallsStatsRow
err := row.Scan(&i.TotalCount, &i.TotalDurationSeconds)
return i, err
}
const getToolcallsStatsByDayLast3Months = `-- name: GetToolcallsStatsByDayLast3Months :many
SELECT
DATE(tc.created_at) AS date,
COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
LEFT JOIN subtasks s ON tc.subtask_id = s.id
LEFT JOIN tasks t ON s.task_id = t.id OR tc.task_id = t.id
INNER JOIN flows f ON (tc.flow_id = f.id OR t.flow_id = f.id)
WHERE tc.created_at >= NOW() - INTERVAL '90 days' AND f.deleted_at IS NULL AND f.user_id = $1
GROUP BY DATE(tc.created_at)
ORDER BY date DESC
`
type GetToolcallsStatsByDayLast3MonthsRow struct {
Date time.Time `json:"date"`
TotalCount int64 `json:"total_count"`
TotalDurationSeconds float64 `json:"total_duration_seconds"`
}
// Get toolcalls stats by day for the last 3 months
func (q *Queries) GetToolcallsStatsByDayLast3Months(ctx context.Context, userID int64) ([]GetToolcallsStatsByDayLast3MonthsRow, error) {
rows, err := q.db.QueryContext(ctx, getToolcallsStatsByDayLast3Months, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetToolcallsStatsByDayLast3MonthsRow
for rows.Next() {
var i GetToolcallsStatsByDayLast3MonthsRow
if err := rows.Scan(&i.Date, &i.TotalCount, &i.TotalDurationSeconds); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getToolcallsStatsByDayLastMonth = `-- name: GetToolcallsStatsByDayLastMonth :many
SELECT
DATE(tc.created_at) AS date,
COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
LEFT JOIN subtasks s ON tc.subtask_id = s.id
LEFT JOIN tasks t ON s.task_id = t.id OR tc.task_id = t.id
INNER JOIN flows f ON (tc.flow_id = f.id OR t.flow_id = f.id)
WHERE tc.created_at >= NOW() - INTERVAL '30 days' AND f.deleted_at IS NULL AND f.user_id = $1
GROUP BY DATE(tc.created_at)
ORDER BY date DESC
`
type GetToolcallsStatsByDayLastMonthRow struct {
Date time.Time `json:"date"`
TotalCount int64 `json:"total_count"`
TotalDurationSeconds float64 `json:"total_duration_seconds"`
}
// Get toolcalls stats by day for the last month
func (q *Queries) GetToolcallsStatsByDayLastMonth(ctx context.Context, userID int64) ([]GetToolcallsStatsByDayLastMonthRow, error) {
rows, err := q.db.QueryContext(ctx, getToolcallsStatsByDayLastMonth, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetToolcallsStatsByDayLastMonthRow
for rows.Next() {
var i GetToolcallsStatsByDayLastMonthRow
if err := rows.Scan(&i.Date, &i.TotalCount, &i.TotalDurationSeconds); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getToolcallsStatsByDayLastWeek = `-- name: GetToolcallsStatsByDayLastWeek :many
SELECT
DATE(tc.created_at) AS date,
COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
LEFT JOIN subtasks s ON tc.subtask_id = s.id
LEFT JOIN tasks t ON s.task_id = t.id OR tc.task_id = t.id
INNER JOIN flows f ON (tc.flow_id = f.id OR t.flow_id = f.id)
WHERE tc.created_at >= NOW() - INTERVAL '7 days' AND f.deleted_at IS NULL AND f.user_id = $1
GROUP BY DATE(tc.created_at)
ORDER BY date DESC
`
type GetToolcallsStatsByDayLastWeekRow struct {
Date time.Time `json:"date"`
TotalCount int64 `json:"total_count"`
TotalDurationSeconds float64 `json:"total_duration_seconds"`
}
// Get toolcalls stats by day for the last week
func (q *Queries) GetToolcallsStatsByDayLastWeek(ctx context.Context, userID int64) ([]GetToolcallsStatsByDayLastWeekRow, error) {
rows, err := q.db.QueryContext(ctx, getToolcallsStatsByDayLastWeek, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetToolcallsStatsByDayLastWeekRow
for rows.Next() {
var i GetToolcallsStatsByDayLastWeekRow
if err := rows.Scan(&i.Date, &i.TotalCount, &i.TotalDurationSeconds); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getToolcallsStatsByFunction = `-- name: GetToolcallsStatsByFunction :many
SELECT
tc.name AS function_name,
COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds,
COALESCE(AVG(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE NULL END), 0.0)::double precision AS avg_duration_seconds
FROM toolcalls tc
LEFT JOIN subtasks s ON tc.subtask_id = s.id
LEFT JOIN tasks t ON s.task_id = t.id OR tc.task_id = t.id
INNER JOIN flows f ON (tc.flow_id = f.id OR t.flow_id = f.id)
WHERE f.deleted_at IS NULL AND f.user_id = $1
GROUP BY tc.name
ORDER BY total_duration_seconds DESC
`
type GetToolcallsStatsByFunctionRow struct {
FunctionName string `json:"function_name"`
TotalCount int64 `json:"total_count"`
TotalDurationSeconds float64 `json:"total_duration_seconds"`
AvgDurationSeconds float64 `json:"avg_duration_seconds"`
}
// Get toolcalls stats grouped by function name for a user
func (q *Queries) GetToolcallsStatsByFunction(ctx context.Context, userID int64) ([]GetToolcallsStatsByFunctionRow, error) {
rows, err := q.db.QueryContext(ctx, getToolcallsStatsByFunction, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetToolcallsStatsByFunctionRow
for rows.Next() {
var i GetToolcallsStatsByFunctionRow
if err := rows.Scan(
&i.FunctionName,
&i.TotalCount,
&i.TotalDurationSeconds,
&i.AvgDurationSeconds,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getToolcallsStatsByFunctionForFlow = `-- name: GetToolcallsStatsByFunctionForFlow :many
SELECT
tc.name AS function_name,
COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds,
COALESCE(AVG(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE NULL END), 0.0)::double precision AS avg_duration_seconds
FROM toolcalls tc
LEFT JOIN subtasks s ON tc.subtask_id = s.id
LEFT JOIN tasks t ON s.task_id = t.id OR tc.task_id = t.id
INNER JOIN flows f ON (tc.flow_id = f.id OR t.flow_id = f.id)
WHERE (tc.flow_id = $1 OR t.flow_id = $1) AND f.deleted_at IS NULL
GROUP BY tc.name
ORDER BY total_duration_seconds DESC
`
type GetToolcallsStatsByFunctionForFlowRow struct {
FunctionName string `json:"function_name"`
TotalCount int64 `json:"total_count"`
TotalDurationSeconds float64 `json:"total_duration_seconds"`
AvgDurationSeconds float64 `json:"avg_duration_seconds"`
}
// Get toolcalls stats grouped by function name for a specific flow
func (q *Queries) GetToolcallsStatsByFunctionForFlow(ctx context.Context, flowID int64) ([]GetToolcallsStatsByFunctionForFlowRow, error) {
rows, err := q.db.QueryContext(ctx, getToolcallsStatsByFunctionForFlow, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetToolcallsStatsByFunctionForFlowRow
for rows.Next() {
var i GetToolcallsStatsByFunctionForFlowRow
if err := rows.Scan(
&i.FunctionName,
&i.TotalCount,
&i.TotalDurationSeconds,
&i.AvgDurationSeconds,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserTotalToolcallsStats = `-- name: GetUserTotalToolcallsStats :one
SELECT
COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
LEFT JOIN subtasks s ON tc.subtask_id = s.id
LEFT JOIN tasks t ON s.task_id = t.id OR tc.task_id = t.id
INNER JOIN flows f ON (tc.flow_id = f.id OR t.flow_id = f.id)
WHERE f.deleted_at IS NULL AND f.user_id = $1
AND (tc.task_id IS NULL OR t.id IS NOT NULL)
AND (tc.subtask_id IS NULL OR s.id IS NOT NULL)
`
type GetUserTotalToolcallsStatsRow struct {
TotalCount int64 `json:"total_count"`
TotalDurationSeconds float64 `json:"total_duration_seconds"`
}
// Get total toolcalls stats for a user
func (q *Queries) GetUserTotalToolcallsStats(ctx context.Context, userID int64) (GetUserTotalToolcallsStatsRow, error) {
row := q.db.QueryRowContext(ctx, getUserTotalToolcallsStats, userID)
var i GetUserTotalToolcallsStatsRow
err := row.Scan(&i.TotalCount, &i.TotalDurationSeconds)
return i, err
}
const updateToolcallFailedResult = `-- name: UpdateToolcallFailedResult :one
UPDATE toolcalls
SET
status = 'failed',
result = $1,
duration_seconds = duration_seconds + $2
WHERE id = $3
RETURNING id, call_id, status, name, args, result, flow_id, task_id, subtask_id, created_at, updated_at, duration_seconds
`
type UpdateToolcallFailedResultParams struct {
Result string `json:"result"`
DurationSeconds float64 `json:"duration_seconds"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateToolcallFailedResult(ctx context.Context, arg UpdateToolcallFailedResultParams) (Toolcall, error) {
row := q.db.QueryRowContext(ctx, updateToolcallFailedResult, arg.Result, arg.DurationSeconds, arg.ID)
var i Toolcall
err := row.Scan(
&i.ID,
&i.CallID,
&i.Status,
&i.Name,
&i.Args,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DurationSeconds,
)
return i, err
}
const updateToolcallFinishedResult = `-- name: UpdateToolcallFinishedResult :one
UPDATE toolcalls
SET
status = 'finished',
result = $1,
duration_seconds = duration_seconds + $2
WHERE id = $3
RETURNING id, call_id, status, name, args, result, flow_id, task_id, subtask_id, created_at, updated_at, duration_seconds
`
type UpdateToolcallFinishedResultParams struct {
Result string `json:"result"`
DurationSeconds float64 `json:"duration_seconds"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateToolcallFinishedResult(ctx context.Context, arg UpdateToolcallFinishedResultParams) (Toolcall, error) {
row := q.db.QueryRowContext(ctx, updateToolcallFinishedResult, arg.Result, arg.DurationSeconds, arg.ID)
var i Toolcall
err := row.Scan(
&i.ID,
&i.CallID,
&i.Status,
&i.Name,
&i.Args,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DurationSeconds,
)
return i, err
}
const updateToolcallStatus = `-- name: UpdateToolcallStatus :one
UPDATE toolcalls
SET
status = $1,
duration_seconds = duration_seconds + $2
WHERE id = $3
RETURNING id, call_id, status, name, args, result, flow_id, task_id, subtask_id, created_at, updated_at, duration_seconds
`
type UpdateToolcallStatusParams struct {
Status ToolcallStatus `json:"status"`
DurationSeconds float64 `json:"duration_seconds"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateToolcallStatus(ctx context.Context, arg UpdateToolcallStatusParams) (Toolcall, error) {
row := q.db.QueryRowContext(ctx, updateToolcallStatus, arg.Status, arg.DurationSeconds, arg.ID)
var i Toolcall
err := row.Scan(
&i.ID,
&i.CallID,
&i.Status,
&i.Name,
&i.Args,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DurationSeconds,
)
return i, err
}
@@ -0,0 +1,195 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: user_preferences.sql
package database
import (
"context"
"encoding/json"
)
const addFavoriteFlow = `-- name: AddFavoriteFlow :one
INSERT INTO user_preferences (user_id, preferences)
VALUES (
$1::bigint,
jsonb_build_object('favoriteFlows', jsonb_build_array($2::bigint))
)
ON CONFLICT (user_id) DO UPDATE
SET preferences = jsonb_set(
user_preferences.preferences,
'{favoriteFlows}',
CASE
WHEN user_preferences.preferences->'favoriteFlows' @> to_jsonb($2::bigint) THEN
user_preferences.preferences->'favoriteFlows'
ELSE
user_preferences.preferences->'favoriteFlows' || to_jsonb($2::bigint)
END
)
RETURNING id, user_id, preferences, created_at, updated_at
`
type AddFavoriteFlowParams struct {
UserID int64 `json:"user_id"`
FlowID int64 `json:"flow_id"`
}
func (q *Queries) AddFavoriteFlow(ctx context.Context, arg AddFavoriteFlowParams) (UserPreference, error) {
row := q.db.QueryRowContext(ctx, addFavoriteFlow, arg.UserID, arg.FlowID)
var i UserPreference
err := row.Scan(
&i.ID,
&i.UserID,
&i.Preferences,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const createUserPreferences = `-- name: CreateUserPreferences :one
INSERT INTO user_preferences (
user_id,
preferences
) VALUES (
$1,
$2
)
RETURNING id, user_id, preferences, created_at, updated_at
`
type CreateUserPreferencesParams struct {
UserID int64 `json:"user_id"`
Preferences json.RawMessage `json:"preferences"`
}
func (q *Queries) CreateUserPreferences(ctx context.Context, arg CreateUserPreferencesParams) (UserPreference, error) {
row := q.db.QueryRowContext(ctx, createUserPreferences, arg.UserID, arg.Preferences)
var i UserPreference
err := row.Scan(
&i.ID,
&i.UserID,
&i.Preferences,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const deleteFavoriteFlow = `-- name: DeleteFavoriteFlow :one
UPDATE user_preferences
SET preferences = jsonb_set(
preferences,
'{favoriteFlows}',
(
SELECT COALESCE(jsonb_agg(elem), '[]'::jsonb)
FROM jsonb_array_elements(preferences->'favoriteFlows') elem
WHERE elem::text::bigint != $1::bigint
)
)
WHERE user_id = $2::bigint
RETURNING id, user_id, preferences, created_at, updated_at
`
type DeleteFavoriteFlowParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) DeleteFavoriteFlow(ctx context.Context, arg DeleteFavoriteFlowParams) (UserPreference, error) {
row := q.db.QueryRowContext(ctx, deleteFavoriteFlow, arg.FlowID, arg.UserID)
var i UserPreference
err := row.Scan(
&i.ID,
&i.UserID,
&i.Preferences,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const deleteUserPreferences = `-- name: DeleteUserPreferences :exec
DELETE FROM user_preferences
WHERE user_id = $1
`
func (q *Queries) DeleteUserPreferences(ctx context.Context, userID int64) error {
_, err := q.db.ExecContext(ctx, deleteUserPreferences, userID)
return err
}
const getUserPreferencesByUserID = `-- name: GetUserPreferencesByUserID :one
SELECT id, user_id, preferences, created_at, updated_at FROM user_preferences
WHERE user_id = $1 LIMIT 1
`
func (q *Queries) GetUserPreferencesByUserID(ctx context.Context, userID int64) (UserPreference, error) {
row := q.db.QueryRowContext(ctx, getUserPreferencesByUserID, userID)
var i UserPreference
err := row.Scan(
&i.ID,
&i.UserID,
&i.Preferences,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const updateUserPreferences = `-- name: UpdateUserPreferences :one
UPDATE user_preferences
SET preferences = $2
WHERE user_id = $1
RETURNING id, user_id, preferences, created_at, updated_at
`
type UpdateUserPreferencesParams struct {
UserID int64 `json:"user_id"`
Preferences json.RawMessage `json:"preferences"`
}
func (q *Queries) UpdateUserPreferences(ctx context.Context, arg UpdateUserPreferencesParams) (UserPreference, error) {
row := q.db.QueryRowContext(ctx, updateUserPreferences, arg.UserID, arg.Preferences)
var i UserPreference
err := row.Scan(
&i.ID,
&i.UserID,
&i.Preferences,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const upsertUserPreferences = `-- name: UpsertUserPreferences :one
INSERT INTO user_preferences (
user_id,
preferences
) VALUES (
$1,
$2
)
ON CONFLICT (user_id) DO UPDATE
SET preferences = EXCLUDED.preferences
RETURNING id, user_id, preferences, created_at, updated_at
`
type UpsertUserPreferencesParams struct {
UserID int64 `json:"user_id"`
Preferences json.RawMessage `json:"preferences"`
}
func (q *Queries) UpsertUserPreferences(ctx context.Context, arg UpsertUserPreferencesParams) (UserPreference, error) {
row := q.db.QueryRowContext(ctx, upsertUserPreferences, arg.UserID, arg.Preferences)
var i UserPreference
err := row.Scan(
&i.ID,
&i.UserID,
&i.Preferences,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
+400
View File
@@ -0,0 +1,400 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: users.sql
package database
import (
"context"
"database/sql"
"github.com/lib/pq"
)
const createUser = `-- name: CreateUser :one
INSERT INTO users (
type,
mail,
name,
password,
status,
role_id,
password_change_required
)
VALUES (
$1, $2, $3, $4, $5, $6, $7
)
RETURNING id, hash, type, mail, name, password, status, role_id, password_change_required, provider, created_at
`
type CreateUserParams struct {
Type UserType `json:"type"`
Mail string `json:"mail"`
Name string `json:"name"`
Password sql.NullString `json:"password"`
Status UserStatus `json:"status"`
RoleID int64 `json:"role_id"`
PasswordChangeRequired bool `json:"password_change_required"`
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
row := q.db.QueryRowContext(ctx, createUser,
arg.Type,
arg.Mail,
arg.Name,
arg.Password,
arg.Status,
arg.RoleID,
arg.PasswordChangeRequired,
)
var i User
err := row.Scan(
&i.ID,
&i.Hash,
&i.Type,
&i.Mail,
&i.Name,
&i.Password,
&i.Status,
&i.RoleID,
&i.PasswordChangeRequired,
&i.Provider,
&i.CreatedAt,
)
return i, err
}
const deleteUser = `-- name: DeleteUser :exec
DELETE FROM users
WHERE id = $1
`
func (q *Queries) DeleteUser(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, deleteUser, id)
return err
}
const getUser = `-- name: GetUser :one
SELECT
u.id, u.hash, u.type, u.mail, u.name, u.password, u.status, u.role_id, u.password_change_required, u.provider, u.created_at,
r.name AS role_name,
(
SELECT ARRAY_AGG(p.name)
FROM privileges p
WHERE p.role_id = r.id
) AS privileges
FROM users u
INNER JOIN roles r ON u.role_id = r.id
WHERE u.id = $1
`
type GetUserRow struct {
ID int64 `json:"id"`
Hash string `json:"hash"`
Type UserType `json:"type"`
Mail string `json:"mail"`
Name string `json:"name"`
Password sql.NullString `json:"password"`
Status UserStatus `json:"status"`
RoleID int64 `json:"role_id"`
PasswordChangeRequired bool `json:"password_change_required"`
Provider sql.NullString `json:"provider"`
CreatedAt sql.NullTime `json:"created_at"`
RoleName string `json:"role_name"`
Privileges []string `json:"privileges"`
}
func (q *Queries) GetUser(ctx context.Context, id int64) (GetUserRow, error) {
row := q.db.QueryRowContext(ctx, getUser, id)
var i GetUserRow
err := row.Scan(
&i.ID,
&i.Hash,
&i.Type,
&i.Mail,
&i.Name,
&i.Password,
&i.Status,
&i.RoleID,
&i.PasswordChangeRequired,
&i.Provider,
&i.CreatedAt,
&i.RoleName,
pq.Array(&i.Privileges),
)
return i, err
}
const getUserByHash = `-- name: GetUserByHash :one
SELECT
u.id, u.hash, u.type, u.mail, u.name, u.password, u.status, u.role_id, u.password_change_required, u.provider, u.created_at,
r.name AS role_name,
(
SELECT ARRAY_AGG(p.name)
FROM privileges p
WHERE p.role_id = r.id
) AS privileges
FROM users u
INNER JOIN roles r ON u.role_id = r.id
WHERE u.hash = $1
`
type GetUserByHashRow struct {
ID int64 `json:"id"`
Hash string `json:"hash"`
Type UserType `json:"type"`
Mail string `json:"mail"`
Name string `json:"name"`
Password sql.NullString `json:"password"`
Status UserStatus `json:"status"`
RoleID int64 `json:"role_id"`
PasswordChangeRequired bool `json:"password_change_required"`
Provider sql.NullString `json:"provider"`
CreatedAt sql.NullTime `json:"created_at"`
RoleName string `json:"role_name"`
Privileges []string `json:"privileges"`
}
func (q *Queries) GetUserByHash(ctx context.Context, hash string) (GetUserByHashRow, error) {
row := q.db.QueryRowContext(ctx, getUserByHash, hash)
var i GetUserByHashRow
err := row.Scan(
&i.ID,
&i.Hash,
&i.Type,
&i.Mail,
&i.Name,
&i.Password,
&i.Status,
&i.RoleID,
&i.PasswordChangeRequired,
&i.Provider,
&i.CreatedAt,
&i.RoleName,
pq.Array(&i.Privileges),
)
return i, err
}
const getUsers = `-- name: GetUsers :many
SELECT
u.id, u.hash, u.type, u.mail, u.name, u.password, u.status, u.role_id, u.password_change_required, u.provider, u.created_at,
r.name AS role_name,
(
SELECT ARRAY_AGG(p.name)
FROM privileges p
WHERE p.role_id = r.id
) AS privileges
FROM users u
INNER JOIN roles r ON u.role_id = r.id
ORDER BY u.created_at DESC
`
type GetUsersRow struct {
ID int64 `json:"id"`
Hash string `json:"hash"`
Type UserType `json:"type"`
Mail string `json:"mail"`
Name string `json:"name"`
Password sql.NullString `json:"password"`
Status UserStatus `json:"status"`
RoleID int64 `json:"role_id"`
PasswordChangeRequired bool `json:"password_change_required"`
Provider sql.NullString `json:"provider"`
CreatedAt sql.NullTime `json:"created_at"`
RoleName string `json:"role_name"`
Privileges []string `json:"privileges"`
}
func (q *Queries) GetUsers(ctx context.Context) ([]GetUsersRow, error) {
rows, err := q.db.QueryContext(ctx, getUsers)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetUsersRow
for rows.Next() {
var i GetUsersRow
if err := rows.Scan(
&i.ID,
&i.Hash,
&i.Type,
&i.Mail,
&i.Name,
&i.Password,
&i.Status,
&i.RoleID,
&i.PasswordChangeRequired,
&i.Provider,
&i.CreatedAt,
&i.RoleName,
pq.Array(&i.Privileges),
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateUserName = `-- name: UpdateUserName :one
UPDATE users
SET name = $1
WHERE id = $2
RETURNING id, hash, type, mail, name, password, status, role_id, password_change_required, provider, created_at
`
type UpdateUserNameParams struct {
Name string `json:"name"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateUserName(ctx context.Context, arg UpdateUserNameParams) (User, error) {
row := q.db.QueryRowContext(ctx, updateUserName, arg.Name, arg.ID)
var i User
err := row.Scan(
&i.ID,
&i.Hash,
&i.Type,
&i.Mail,
&i.Name,
&i.Password,
&i.Status,
&i.RoleID,
&i.PasswordChangeRequired,
&i.Provider,
&i.CreatedAt,
)
return i, err
}
const updateUserPassword = `-- name: UpdateUserPassword :one
UPDATE users
SET password = $1
WHERE id = $2
RETURNING id, hash, type, mail, name, password, status, role_id, password_change_required, provider, created_at
`
type UpdateUserPasswordParams struct {
Password sql.NullString `json:"password"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) (User, error) {
row := q.db.QueryRowContext(ctx, updateUserPassword, arg.Password, arg.ID)
var i User
err := row.Scan(
&i.ID,
&i.Hash,
&i.Type,
&i.Mail,
&i.Name,
&i.Password,
&i.Status,
&i.RoleID,
&i.PasswordChangeRequired,
&i.Provider,
&i.CreatedAt,
)
return i, err
}
const updateUserPasswordChangeRequired = `-- name: UpdateUserPasswordChangeRequired :one
UPDATE users
SET password_change_required = $1
WHERE id = $2
RETURNING id, hash, type, mail, name, password, status, role_id, password_change_required, provider, created_at
`
type UpdateUserPasswordChangeRequiredParams struct {
PasswordChangeRequired bool `json:"password_change_required"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateUserPasswordChangeRequired(ctx context.Context, arg UpdateUserPasswordChangeRequiredParams) (User, error) {
row := q.db.QueryRowContext(ctx, updateUserPasswordChangeRequired, arg.PasswordChangeRequired, arg.ID)
var i User
err := row.Scan(
&i.ID,
&i.Hash,
&i.Type,
&i.Mail,
&i.Name,
&i.Password,
&i.Status,
&i.RoleID,
&i.PasswordChangeRequired,
&i.Provider,
&i.CreatedAt,
)
return i, err
}
const updateUserRole = `-- name: UpdateUserRole :one
UPDATE users
SET role_id = $1
WHERE id = $2
RETURNING id, hash, type, mail, name, password, status, role_id, password_change_required, provider, created_at
`
type UpdateUserRoleParams struct {
RoleID int64 `json:"role_id"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (User, error) {
row := q.db.QueryRowContext(ctx, updateUserRole, arg.RoleID, arg.ID)
var i User
err := row.Scan(
&i.ID,
&i.Hash,
&i.Type,
&i.Mail,
&i.Name,
&i.Password,
&i.Status,
&i.RoleID,
&i.PasswordChangeRequired,
&i.Provider,
&i.CreatedAt,
)
return i, err
}
const updateUserStatus = `-- name: UpdateUserStatus :one
UPDATE users
SET status = $1
WHERE id = $2
RETURNING id, hash, type, mail, name, password, status, role_id, password_change_required, provider, created_at
`
type UpdateUserStatusParams struct {
Status UserStatus `json:"status"`
ID int64 `json:"id"`
}
func (q *Queries) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) (User, error) {
row := q.db.QueryRowContext(ctx, updateUserStatus, arg.Status, arg.ID)
var i User
err := row.Scan(
&i.ID,
&i.Hash,
&i.Type,
&i.Mail,
&i.Name,
&i.Password,
&i.Status,
&i.RoleID,
&i.PasswordChangeRequired,
&i.Provider,
&i.CreatedAt,
)
return i, err
}
+287
View File
@@ -0,0 +1,287 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: vecstorelogs.sql
package database
import (
"context"
"database/sql"
"encoding/json"
)
const createVectorStoreLog = `-- name: CreateVectorStoreLog :one
INSERT INTO vecstorelogs (
initiator,
executor,
filter,
query,
action,
result,
flow_id,
task_id,
subtask_id
)
VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9
)
RETURNING id, initiator, executor, filter, query, action, result, flow_id, task_id, subtask_id, created_at
`
type CreateVectorStoreLogParams struct {
Initiator MsgchainType `json:"initiator"`
Executor MsgchainType `json:"executor"`
Filter json.RawMessage `json:"filter"`
Query string `json:"query"`
Action VecstoreActionType `json:"action"`
Result string `json:"result"`
FlowID int64 `json:"flow_id"`
TaskID sql.NullInt64 `json:"task_id"`
SubtaskID sql.NullInt64 `json:"subtask_id"`
}
func (q *Queries) CreateVectorStoreLog(ctx context.Context, arg CreateVectorStoreLogParams) (Vecstorelog, error) {
row := q.db.QueryRowContext(ctx, createVectorStoreLog,
arg.Initiator,
arg.Executor,
arg.Filter,
arg.Query,
arg.Action,
arg.Result,
arg.FlowID,
arg.TaskID,
arg.SubtaskID,
)
var i Vecstorelog
err := row.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Filter,
&i.Query,
&i.Action,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
)
return i, err
}
const getFlowVectorStoreLog = `-- name: GetFlowVectorStoreLog :one
SELECT
vl.id, vl.initiator, vl.executor, vl.filter, vl.query, vl.action, vl.result, vl.flow_id, vl.task_id, vl.subtask_id, vl.created_at
FROM vecstorelogs vl
INNER JOIN flows f ON vl.flow_id = f.id
WHERE vl.id = $1 AND vl.flow_id = $2 AND f.deleted_at IS NULL
`
type GetFlowVectorStoreLogParams struct {
ID int64 `json:"id"`
FlowID int64 `json:"flow_id"`
}
func (q *Queries) GetFlowVectorStoreLog(ctx context.Context, arg GetFlowVectorStoreLogParams) (Vecstorelog, error) {
row := q.db.QueryRowContext(ctx, getFlowVectorStoreLog, arg.ID, arg.FlowID)
var i Vecstorelog
err := row.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Filter,
&i.Query,
&i.Action,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
)
return i, err
}
const getFlowVectorStoreLogs = `-- name: GetFlowVectorStoreLogs :many
SELECT
vl.id, vl.initiator, vl.executor, vl.filter, vl.query, vl.action, vl.result, vl.flow_id, vl.task_id, vl.subtask_id, vl.created_at
FROM vecstorelogs vl
INNER JOIN flows f ON vl.flow_id = f.id
WHERE vl.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY vl.created_at ASC
`
func (q *Queries) GetFlowVectorStoreLogs(ctx context.Context, flowID int64) ([]Vecstorelog, error) {
rows, err := q.db.QueryContext(ctx, getFlowVectorStoreLogs, flowID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Vecstorelog
for rows.Next() {
var i Vecstorelog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Filter,
&i.Query,
&i.Action,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getSubtaskVectorStoreLogs = `-- name: GetSubtaskVectorStoreLogs :many
SELECT
vl.id, vl.initiator, vl.executor, vl.filter, vl.query, vl.action, vl.result, vl.flow_id, vl.task_id, vl.subtask_id, vl.created_at
FROM vecstorelogs vl
INNER JOIN flows f ON vl.flow_id = f.id
INNER JOIN subtasks s ON vl.subtask_id = s.id
WHERE vl.subtask_id = $1 AND f.deleted_at IS NULL
ORDER BY vl.created_at ASC
`
func (q *Queries) GetSubtaskVectorStoreLogs(ctx context.Context, subtaskID sql.NullInt64) ([]Vecstorelog, error) {
rows, err := q.db.QueryContext(ctx, getSubtaskVectorStoreLogs, subtaskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Vecstorelog
for rows.Next() {
var i Vecstorelog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Filter,
&i.Query,
&i.Action,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTaskVectorStoreLogs = `-- name: GetTaskVectorStoreLogs :many
SELECT
vl.id, vl.initiator, vl.executor, vl.filter, vl.query, vl.action, vl.result, vl.flow_id, vl.task_id, vl.subtask_id, vl.created_at
FROM vecstorelogs vl
INNER JOIN flows f ON vl.flow_id = f.id
INNER JOIN tasks t ON vl.task_id = t.id
WHERE vl.task_id = $1 AND f.deleted_at IS NULL
ORDER BY vl.created_at ASC
`
func (q *Queries) GetTaskVectorStoreLogs(ctx context.Context, taskID sql.NullInt64) ([]Vecstorelog, error) {
rows, err := q.db.QueryContext(ctx, getTaskVectorStoreLogs, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Vecstorelog
for rows.Next() {
var i Vecstorelog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Filter,
&i.Query,
&i.Action,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getUserFlowVectorStoreLogs = `-- name: GetUserFlowVectorStoreLogs :many
SELECT
vl.id, vl.initiator, vl.executor, vl.filter, vl.query, vl.action, vl.result, vl.flow_id, vl.task_id, vl.subtask_id, vl.created_at
FROM vecstorelogs vl
INNER JOIN flows f ON vl.flow_id = f.id
INNER JOIN users u ON f.user_id = u.id
WHERE vl.flow_id = $1 AND f.user_id = $2 AND f.deleted_at IS NULL
ORDER BY vl.created_at ASC
`
type GetUserFlowVectorStoreLogsParams struct {
FlowID int64 `json:"flow_id"`
UserID int64 `json:"user_id"`
}
func (q *Queries) GetUserFlowVectorStoreLogs(ctx context.Context, arg GetUserFlowVectorStoreLogsParams) ([]Vecstorelog, error) {
rows, err := q.db.QueryContext(ctx, getUserFlowVectorStoreLogs, arg.FlowID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Vecstorelog
for rows.Next() {
var i Vecstorelog
if err := rows.Scan(
&i.ID,
&i.Initiator,
&i.Executor,
&i.Filter,
&i.Query,
&i.Action,
&i.Result,
&i.FlowID,
&i.TaskID,
&i.SubtaskID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}