chore: import upstream snapshot with attribution
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 = >
|
||||
}
|
||||
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
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user