feat(migrations): Harden task audit tracking and optimize article templates
- Added migration to harden task audit tracking by modifying audit_logs and related tables. - Introduced operator_id to several tables for better tracking of actions. - Updated article_templates with new prompt templates for various article types, enhancing content generation. - Created prompt_rules and schedule_tasks tables to manage content generation rules and scheduling. - Added foreign key constraints to articles for better data integrity.
This commit is contained in:
@@ -8,16 +8,21 @@ import (
|
||||
)
|
||||
|
||||
type AuditLogInput struct {
|
||||
OperatorID int64
|
||||
TenantID *int64
|
||||
Module string
|
||||
Action string
|
||||
BeforeJSON []byte
|
||||
AfterJSON []byte
|
||||
Result *string
|
||||
OperatorID int64
|
||||
TenantID *int64
|
||||
Module string
|
||||
Action string
|
||||
ResourceType *string
|
||||
ResourceID *int64
|
||||
RequestID *string
|
||||
BeforeJSON []byte
|
||||
AfterJSON []byte
|
||||
Result *string
|
||||
ErrorMessage *string
|
||||
}
|
||||
|
||||
type GenerationTaskInput struct {
|
||||
OperatorID int64
|
||||
TenantID int64
|
||||
ArticleID *int64
|
||||
QuotaReservationID *int64
|
||||
@@ -50,18 +55,24 @@ func NewAuditRepository(db generated.DBTX) AuditRepository {
|
||||
|
||||
func (r *auditRepository) CreateAuditLog(ctx context.Context, input AuditLogInput) error {
|
||||
return r.q.CreateAuditLog(ctx, generated.CreateAuditLogParams{
|
||||
OperatorID: input.OperatorID,
|
||||
TenantID: pgInt8(input.TenantID),
|
||||
Module: input.Module,
|
||||
Action: input.Action,
|
||||
BeforeJson: input.BeforeJSON,
|
||||
AfterJson: input.AfterJSON,
|
||||
Result: pgText(input.Result),
|
||||
OperatorID: input.OperatorID,
|
||||
TenantID: pgInt8(input.TenantID),
|
||||
Module: input.Module,
|
||||
Action: input.Action,
|
||||
ResourceType: pgText(input.ResourceType),
|
||||
ResourceID: pgInt8(input.ResourceID),
|
||||
RequestID: pgText(input.RequestID),
|
||||
BeforeJson: input.BeforeJSON,
|
||||
AfterJson: input.AfterJSON,
|
||||
Result: pgText(input.Result),
|
||||
ErrorMessage: pgText(input.ErrorMessage),
|
||||
})
|
||||
}
|
||||
|
||||
func (r *auditRepository) CreateGenerationTask(ctx context.Context, input GenerationTaskInput) (int64, error) {
|
||||
operatorID := input.OperatorID
|
||||
return r.q.CreateGenerationTask(ctx, generated.CreateGenerationTaskParams{
|
||||
OperatorID: pgInt8(&operatorID),
|
||||
TenantID: input.TenantID,
|
||||
ArticleID: pgInt8(input.ArticleID),
|
||||
QuotaReservationID: pgInt8(input.QuotaReservationID),
|
||||
|
||||
@@ -12,19 +12,36 @@ import (
|
||||
)
|
||||
|
||||
const createAuditLog = `-- name: CreateAuditLog :exec
|
||||
INSERT INTO audit_logs (operator_id, tenant_id, module, action, before_json, after_json, result)
|
||||
INSERT INTO audit_logs (
|
||||
operator_id,
|
||||
tenant_id,
|
||||
module,
|
||||
action,
|
||||
resource_type,
|
||||
resource_id,
|
||||
request_id,
|
||||
before_json,
|
||||
after_json,
|
||||
result,
|
||||
error_message
|
||||
)
|
||||
VALUES ($1, $2, $3, $4,
|
||||
$5, $6, $7)
|
||||
$5, $6, $7,
|
||||
$8, $9, $10, $11)
|
||||
`
|
||||
|
||||
type CreateAuditLogParams struct {
|
||||
OperatorID int64 `json:"operator_id"`
|
||||
TenantID pgtype.Int8 `json:"tenant_id"`
|
||||
Module string `json:"module"`
|
||||
Action string `json:"action"`
|
||||
BeforeJson []byte `json:"before_json"`
|
||||
AfterJson []byte `json:"after_json"`
|
||||
Result pgtype.Text `json:"result"`
|
||||
OperatorID int64 `json:"operator_id"`
|
||||
TenantID pgtype.Int8 `json:"tenant_id"`
|
||||
Module string `json:"module"`
|
||||
Action string `json:"action"`
|
||||
ResourceType pgtype.Text `json:"resource_type"`
|
||||
ResourceID pgtype.Int8 `json:"resource_id"`
|
||||
RequestID pgtype.Text `json:"request_id"`
|
||||
BeforeJson []byte `json:"before_json"`
|
||||
AfterJson []byte `json:"after_json"`
|
||||
Result pgtype.Text `json:"result"`
|
||||
ErrorMessage pgtype.Text `json:"error_message"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateAuditLog(ctx context.Context, arg CreateAuditLogParams) error {
|
||||
@@ -33,22 +50,27 @@ func (q *Queries) CreateAuditLog(ctx context.Context, arg CreateAuditLogParams)
|
||||
arg.TenantID,
|
||||
arg.Module,
|
||||
arg.Action,
|
||||
arg.ResourceType,
|
||||
arg.ResourceID,
|
||||
arg.RequestID,
|
||||
arg.BeforeJson,
|
||||
arg.AfterJson,
|
||||
arg.Result,
|
||||
arg.ErrorMessage,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const createGenerationTask = `-- name: CreateGenerationTask :one
|
||||
INSERT INTO generation_tasks (tenant_id, article_id, quota_reservation_id, task_type, input_params_json, status)
|
||||
VALUES ($1, $2, $3,
|
||||
$4, $5, 'queued')
|
||||
INSERT INTO generation_tasks (tenant_id, operator_id, article_id, quota_reservation_id, task_type, input_params_json, status)
|
||||
VALUES ($1, $2, $3, $4,
|
||||
$5, $6, 'queued')
|
||||
RETURNING id
|
||||
`
|
||||
|
||||
type CreateGenerationTaskParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
OperatorID pgtype.Int8 `json:"operator_id"`
|
||||
ArticleID pgtype.Int8 `json:"article_id"`
|
||||
QuotaReservationID pgtype.Int8 `json:"quota_reservation_id"`
|
||||
TaskType string `json:"task_type"`
|
||||
@@ -58,6 +80,7 @@ type CreateGenerationTaskParams struct {
|
||||
func (q *Queries) CreateGenerationTask(ctx context.Context, arg CreateGenerationTaskParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, createGenerationTask,
|
||||
arg.TenantID,
|
||||
arg.OperatorID,
|
||||
arg.ArticleID,
|
||||
arg.QuotaReservationID,
|
||||
arg.TaskType,
|
||||
|
||||
@@ -20,6 +20,7 @@ type Article struct {
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
|
||||
WizardStateJson []byte `json:"wizard_state_json"`
|
||||
}
|
||||
|
||||
type ArticleTemplate struct {
|
||||
@@ -55,15 +56,19 @@ type ArticleVersion struct {
|
||||
}
|
||||
|
||||
type AuditLog struct {
|
||||
ID int64 `json:"id"`
|
||||
OperatorID int64 `json:"operator_id"`
|
||||
TenantID pgtype.Int8 `json:"tenant_id"`
|
||||
Module string `json:"module"`
|
||||
Action string `json:"action"`
|
||||
BeforeJson []byte `json:"before_json"`
|
||||
AfterJson []byte `json:"after_json"`
|
||||
Result pgtype.Text `json:"result"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
ID int64 `json:"id"`
|
||||
OperatorID int64 `json:"operator_id"`
|
||||
TenantID pgtype.Int8 `json:"tenant_id"`
|
||||
Module string `json:"module"`
|
||||
Action string `json:"action"`
|
||||
BeforeJson []byte `json:"before_json"`
|
||||
AfterJson []byte `json:"after_json"`
|
||||
Result pgtype.Text `json:"result"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
ResourceType pgtype.Text `json:"resource_type"`
|
||||
ResourceID pgtype.Int8 `json:"resource_id"`
|
||||
RequestID pgtype.Text `json:"request_id"`
|
||||
ErrorMessage pgtype.Text `json:"error_message"`
|
||||
}
|
||||
|
||||
type Brand struct {
|
||||
@@ -138,6 +143,7 @@ type GenerationTask struct {
|
||||
CompletedAt pgtype.Timestamptz `json:"completed_at"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
OperatorID pgtype.Int8 `json:"operator_id"`
|
||||
}
|
||||
|
||||
type Plan struct {
|
||||
@@ -160,12 +166,37 @@ type PlatformUserRole struct {
|
||||
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
|
||||
}
|
||||
|
||||
type PromptRule struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
GroupID pgtype.Int8 `json:"group_id"`
|
||||
Name string `json:"name"`
|
||||
PromptContent string `json:"prompt_content"`
|
||||
Scene pgtype.Text `json:"scene"`
|
||||
DefaultTone pgtype.Text `json:"default_tone"`
|
||||
DefaultWordCount pgtype.Int4 `json:"default_word_count"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
|
||||
}
|
||||
|
||||
type PromptRuleGroup struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
Name string `json:"name"`
|
||||
SortOrder int32 `json:"sort_order"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
|
||||
}
|
||||
|
||||
type QuotaReservation struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
QuotaType string `json:"quota_type"`
|
||||
ResourceType string `json:"resource_type"`
|
||||
ResourceID int64 `json:"resource_id"`
|
||||
ResourceID pgtype.Int8 `json:"resource_id"`
|
||||
ReservedAmount int32 `json:"reserved_amount"`
|
||||
ConsumedAmount int32 `json:"consumed_amount"`
|
||||
RefundedAmount int32 `json:"refunded_amount"`
|
||||
@@ -173,6 +204,24 @@ type QuotaReservation struct {
|
||||
ExpireAt pgtype.Timestamptz `json:"expire_at"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
OperatorID pgtype.Int8 `json:"operator_id"`
|
||||
}
|
||||
|
||||
type ScheduleTask struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
TargetPlatform pgtype.Text `json:"target_platform"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
|
||||
}
|
||||
|
||||
type TaskRecord struct {
|
||||
@@ -187,6 +236,23 @@ type TaskRecord struct {
|
||||
ErrorMessage pgtype.Text `json:"error_message"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
OperatorID pgtype.Int8 `json:"operator_id"`
|
||||
}
|
||||
|
||||
type TemplateAssistTask struct {
|
||||
ID string `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
TemplateID int64 `json:"template_id"`
|
||||
Status string `json:"status"`
|
||||
RequestJson []byte `json:"request_json"`
|
||||
ResultJson []byte `json:"result_json"`
|
||||
ErrorMessage pgtype.Text `json:"error_message"`
|
||||
StartedAt pgtype.Timestamptz `json:"started_at"`
|
||||
CompletedAt pgtype.Timestamptz `json:"completed_at"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
TaskType string `json:"task_type"`
|
||||
OperatorID pgtype.Int8 `json:"operator_id"`
|
||||
}
|
||||
|
||||
type Tenant struct {
|
||||
@@ -231,6 +297,7 @@ type TenantQuotaLedger struct {
|
||||
ReferenceType pgtype.Text `json:"reference_type"`
|
||||
ReferenceID pgtype.Int8 `json:"reference_id"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
OperatorID pgtype.Int8 `json:"operator_id"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
|
||||
@@ -0,0 +1,499 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
// source: prompt_rule.sql
|
||||
|
||||
package generated
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const countPromptRules = `-- name: CountPromptRules :one
|
||||
SELECT COUNT(*)
|
||||
FROM prompt_rules
|
||||
WHERE tenant_id = $1
|
||||
AND deleted_at IS NULL
|
||||
AND ($2::bigint IS NULL OR group_id = $2)
|
||||
AND ($3::text IS NULL OR status = $3)
|
||||
AND ($4::text IS NULL OR name ILIKE '%' || $4 || '%')
|
||||
`
|
||||
|
||||
type CountPromptRulesParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
GroupID pgtype.Int8 `json:"group_id"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
Keyword pgtype.Text `json:"keyword"`
|
||||
}
|
||||
|
||||
func (q *Queries) CountPromptRules(ctx context.Context, arg CountPromptRulesParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, countPromptRules,
|
||||
arg.TenantID,
|
||||
arg.GroupID,
|
||||
arg.Status,
|
||||
arg.Keyword,
|
||||
)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
const countPromptRulesUngrouped = `-- name: CountPromptRulesUngrouped :one
|
||||
SELECT COUNT(*)
|
||||
FROM prompt_rules
|
||||
WHERE tenant_id = $1
|
||||
AND deleted_at IS NULL
|
||||
AND group_id IS NULL
|
||||
`
|
||||
|
||||
func (q *Queries) CountPromptRulesUngrouped(ctx context.Context, tenantID int64) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, countPromptRulesUngrouped, tenantID)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
const createPromptRule = `-- name: CreatePromptRule :one
|
||||
INSERT INTO prompt_rules (tenant_id, group_id, name, prompt_content, scene, default_tone, default_word_count)
|
||||
VALUES ($1, $2, $3, $4,
|
||||
$5, $6, $7)
|
||||
RETURNING id, created_at
|
||||
`
|
||||
|
||||
type CreatePromptRuleParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
GroupID pgtype.Int8 `json:"group_id"`
|
||||
Name string `json:"name"`
|
||||
PromptContent string `json:"prompt_content"`
|
||||
Scene pgtype.Text `json:"scene"`
|
||||
DefaultTone pgtype.Text `json:"default_tone"`
|
||||
DefaultWordCount pgtype.Int4 `json:"default_word_count"`
|
||||
}
|
||||
|
||||
type CreatePromptRuleRow struct {
|
||||
ID int64 `json:"id"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreatePromptRule(ctx context.Context, arg CreatePromptRuleParams) (CreatePromptRuleRow, error) {
|
||||
row := q.db.QueryRow(ctx, createPromptRule,
|
||||
arg.TenantID,
|
||||
arg.GroupID,
|
||||
arg.Name,
|
||||
arg.PromptContent,
|
||||
arg.Scene,
|
||||
arg.DefaultTone,
|
||||
arg.DefaultWordCount,
|
||||
)
|
||||
var i CreatePromptRuleRow
|
||||
err := row.Scan(&i.ID, &i.CreatedAt)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createPromptRuleGroup = `-- name: CreatePromptRuleGroup :one
|
||||
INSERT INTO prompt_rule_groups (tenant_id, name, sort_order)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING id, created_at
|
||||
`
|
||||
|
||||
type CreatePromptRuleGroupParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
Name string `json:"name"`
|
||||
SortOrder int32 `json:"sort_order"`
|
||||
}
|
||||
|
||||
type CreatePromptRuleGroupRow struct {
|
||||
ID int64 `json:"id"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreatePromptRuleGroup(ctx context.Context, arg CreatePromptRuleGroupParams) (CreatePromptRuleGroupRow, error) {
|
||||
row := q.db.QueryRow(ctx, createPromptRuleGroup, arg.TenantID, arg.Name, arg.SortOrder)
|
||||
var i CreatePromptRuleGroupRow
|
||||
err := row.Scan(&i.ID, &i.CreatedAt)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getPromptRuleByID = `-- name: GetPromptRuleByID :one
|
||||
SELECT id, tenant_id, group_id, name, prompt_content,
|
||||
scene, default_tone, default_word_count, status,
|
||||
created_at, updated_at
|
||||
FROM prompt_rules
|
||||
WHERE id = $1 AND tenant_id = $2 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
type GetPromptRuleByIDParams struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
type GetPromptRuleByIDRow struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
GroupID pgtype.Int8 `json:"group_id"`
|
||||
Name string `json:"name"`
|
||||
PromptContent string `json:"prompt_content"`
|
||||
Scene pgtype.Text `json:"scene"`
|
||||
DefaultTone pgtype.Text `json:"default_tone"`
|
||||
DefaultWordCount pgtype.Int4 `json:"default_word_count"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetPromptRuleByID(ctx context.Context, arg GetPromptRuleByIDParams) (GetPromptRuleByIDRow, error) {
|
||||
row := q.db.QueryRow(ctx, getPromptRuleByID, arg.ID, arg.TenantID)
|
||||
var i GetPromptRuleByIDRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.TenantID,
|
||||
&i.GroupID,
|
||||
&i.Name,
|
||||
&i.PromptContent,
|
||||
&i.Scene,
|
||||
&i.DefaultTone,
|
||||
&i.DefaultWordCount,
|
||||
&i.Status,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const listAllPromptRulesSimple = `-- name: ListAllPromptRulesSimple :many
|
||||
SELECT id, name, status
|
||||
FROM prompt_rules
|
||||
WHERE tenant_id = $1 AND deleted_at IS NULL AND status = 'enabled'
|
||||
ORDER BY name
|
||||
`
|
||||
|
||||
type ListAllPromptRulesSimpleRow struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListAllPromptRulesSimple(ctx context.Context, tenantID int64) ([]ListAllPromptRulesSimpleRow, error) {
|
||||
rows, err := q.db.Query(ctx, listAllPromptRulesSimple, tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListAllPromptRulesSimpleRow
|
||||
for rows.Next() {
|
||||
var i ListAllPromptRulesSimpleRow
|
||||
if err := rows.Scan(&i.ID, &i.Name, &i.Status); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listPromptRuleGroups = `-- name: ListPromptRuleGroups :many
|
||||
|
||||
SELECT id, tenant_id, name, sort_order, created_at, updated_at
|
||||
FROM prompt_rule_groups
|
||||
WHERE tenant_id = $1 AND deleted_at IS NULL
|
||||
ORDER BY sort_order, created_at
|
||||
`
|
||||
|
||||
type ListPromptRuleGroupsRow struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
Name string `json:"name"`
|
||||
SortOrder int32 `json:"sort_order"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Prompt Rule Groups
|
||||
// ============================================================
|
||||
func (q *Queries) ListPromptRuleGroups(ctx context.Context, tenantID int64) ([]ListPromptRuleGroupsRow, error) {
|
||||
rows, err := q.db.Query(ctx, listPromptRuleGroups, tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListPromptRuleGroupsRow
|
||||
for rows.Next() {
|
||||
var i ListPromptRuleGroupsRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.TenantID,
|
||||
&i.Name,
|
||||
&i.SortOrder,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listPromptRules = `-- name: ListPromptRules :many
|
||||
|
||||
SELECT pr.id, pr.tenant_id, pr.group_id, pr.name, pr.prompt_content,
|
||||
pr.scene, pr.default_tone, pr.default_word_count, pr.status,
|
||||
pr.created_at, pr.updated_at,
|
||||
COUNT(a.id)::INT AS article_count
|
||||
FROM prompt_rules pr
|
||||
LEFT JOIN articles a ON a.prompt_rule_id = pr.id AND a.deleted_at IS NULL
|
||||
WHERE pr.tenant_id = $1
|
||||
AND pr.deleted_at IS NULL
|
||||
AND ($2::bigint IS NULL OR pr.group_id = $2)
|
||||
AND ($3::text IS NULL OR pr.status = $3)
|
||||
AND ($4::text IS NULL OR pr.name ILIKE '%' || $4 || '%')
|
||||
GROUP BY pr.id
|
||||
ORDER BY pr.created_at DESC
|
||||
LIMIT $6 OFFSET $5
|
||||
`
|
||||
|
||||
type ListPromptRulesParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
GroupID pgtype.Int8 `json:"group_id"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
Keyword pgtype.Text `json:"keyword"`
|
||||
PageOffset int32 `json:"page_offset"`
|
||||
PageSize int32 `json:"page_size"`
|
||||
}
|
||||
|
||||
type ListPromptRulesRow struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
GroupID pgtype.Int8 `json:"group_id"`
|
||||
Name string `json:"name"`
|
||||
PromptContent string `json:"prompt_content"`
|
||||
Scene pgtype.Text `json:"scene"`
|
||||
DefaultTone pgtype.Text `json:"default_tone"`
|
||||
DefaultWordCount pgtype.Int4 `json:"default_word_count"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
ArticleCount int32 `json:"article_count"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Prompt Rules
|
||||
// ============================================================
|
||||
func (q *Queries) ListPromptRules(ctx context.Context, arg ListPromptRulesParams) ([]ListPromptRulesRow, error) {
|
||||
rows, err := q.db.Query(ctx, listPromptRules,
|
||||
arg.TenantID,
|
||||
arg.GroupID,
|
||||
arg.Status,
|
||||
arg.Keyword,
|
||||
arg.PageOffset,
|
||||
arg.PageSize,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListPromptRulesRow
|
||||
for rows.Next() {
|
||||
var i ListPromptRulesRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.TenantID,
|
||||
&i.GroupID,
|
||||
&i.Name,
|
||||
&i.PromptContent,
|
||||
&i.Scene,
|
||||
&i.DefaultTone,
|
||||
&i.DefaultWordCount,
|
||||
&i.Status,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.ArticleCount,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listPromptRulesUngrouped = `-- name: ListPromptRulesUngrouped :many
|
||||
SELECT pr.id, pr.tenant_id, pr.group_id, pr.name, pr.prompt_content,
|
||||
pr.scene, pr.default_tone, pr.default_word_count, pr.status,
|
||||
pr.created_at, pr.updated_at,
|
||||
COUNT(a.id)::INT AS article_count
|
||||
FROM prompt_rules pr
|
||||
LEFT JOIN articles a ON a.prompt_rule_id = pr.id AND a.deleted_at IS NULL
|
||||
WHERE pr.tenant_id = $1
|
||||
AND pr.deleted_at IS NULL
|
||||
AND pr.group_id IS NULL
|
||||
GROUP BY pr.id
|
||||
ORDER BY pr.created_at DESC
|
||||
LIMIT $3 OFFSET $2
|
||||
`
|
||||
|
||||
type ListPromptRulesUngroupedParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
PageOffset int32 `json:"page_offset"`
|
||||
PageSize int32 `json:"page_size"`
|
||||
}
|
||||
|
||||
type ListPromptRulesUngroupedRow struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
GroupID pgtype.Int8 `json:"group_id"`
|
||||
Name string `json:"name"`
|
||||
PromptContent string `json:"prompt_content"`
|
||||
Scene pgtype.Text `json:"scene"`
|
||||
DefaultTone pgtype.Text `json:"default_tone"`
|
||||
DefaultWordCount pgtype.Int4 `json:"default_word_count"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
ArticleCount int32 `json:"article_count"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListPromptRulesUngrouped(ctx context.Context, arg ListPromptRulesUngroupedParams) ([]ListPromptRulesUngroupedRow, error) {
|
||||
rows, err := q.db.Query(ctx, listPromptRulesUngrouped, arg.TenantID, arg.PageOffset, arg.PageSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListPromptRulesUngroupedRow
|
||||
for rows.Next() {
|
||||
var i ListPromptRulesUngroupedRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.TenantID,
|
||||
&i.GroupID,
|
||||
&i.Name,
|
||||
&i.PromptContent,
|
||||
&i.Scene,
|
||||
&i.DefaultTone,
|
||||
&i.DefaultWordCount,
|
||||
&i.Status,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.ArticleCount,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const softDeletePromptRule = `-- name: SoftDeletePromptRule :exec
|
||||
UPDATE prompt_rules SET deleted_at = NOW(), updated_at = NOW()
|
||||
WHERE id = $1 AND tenant_id = $2 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
type SoftDeletePromptRuleParams struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) SoftDeletePromptRule(ctx context.Context, arg SoftDeletePromptRuleParams) error {
|
||||
_, err := q.db.Exec(ctx, softDeletePromptRule, arg.ID, arg.TenantID)
|
||||
return err
|
||||
}
|
||||
|
||||
const softDeletePromptRuleGroup = `-- name: SoftDeletePromptRuleGroup :exec
|
||||
UPDATE prompt_rule_groups SET deleted_at = NOW(), updated_at = NOW()
|
||||
WHERE id = $1 AND tenant_id = $2 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
type SoftDeletePromptRuleGroupParams struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) SoftDeletePromptRuleGroup(ctx context.Context, arg SoftDeletePromptRuleGroupParams) error {
|
||||
_, err := q.db.Exec(ctx, softDeletePromptRuleGroup, arg.ID, arg.TenantID)
|
||||
return err
|
||||
}
|
||||
|
||||
const updatePromptRule = `-- name: UpdatePromptRule :exec
|
||||
UPDATE prompt_rules
|
||||
SET name = $1, group_id = $2,
|
||||
prompt_content = $3,
|
||||
scene = $4, default_tone = $5,
|
||||
default_word_count = $6, updated_at = NOW()
|
||||
WHERE id = $7 AND tenant_id = $8 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
type UpdatePromptRuleParams struct {
|
||||
Name string `json:"name"`
|
||||
GroupID pgtype.Int8 `json:"group_id"`
|
||||
PromptContent string `json:"prompt_content"`
|
||||
Scene pgtype.Text `json:"scene"`
|
||||
DefaultTone pgtype.Text `json:"default_tone"`
|
||||
DefaultWordCount pgtype.Int4 `json:"default_word_count"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdatePromptRule(ctx context.Context, arg UpdatePromptRuleParams) error {
|
||||
_, err := q.db.Exec(ctx, updatePromptRule,
|
||||
arg.Name,
|
||||
arg.GroupID,
|
||||
arg.PromptContent,
|
||||
arg.Scene,
|
||||
arg.DefaultTone,
|
||||
arg.DefaultWordCount,
|
||||
arg.ID,
|
||||
arg.TenantID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const updatePromptRuleGroup = `-- name: UpdatePromptRuleGroup :exec
|
||||
UPDATE prompt_rule_groups SET name = $1, sort_order = $2, updated_at = NOW()
|
||||
WHERE id = $3 AND tenant_id = $4 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
type UpdatePromptRuleGroupParams struct {
|
||||
Name string `json:"name"`
|
||||
SortOrder int32 `json:"sort_order"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdatePromptRuleGroup(ctx context.Context, arg UpdatePromptRuleGroupParams) error {
|
||||
_, err := q.db.Exec(ctx, updatePromptRuleGroup,
|
||||
arg.Name,
|
||||
arg.SortOrder,
|
||||
arg.ID,
|
||||
arg.TenantID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const updatePromptRuleStatus = `-- name: UpdatePromptRuleStatus :exec
|
||||
UPDATE prompt_rules SET status = $1, updated_at = NOW()
|
||||
WHERE id = $2 AND tenant_id = $3 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
type UpdatePromptRuleStatusParams struct {
|
||||
Status string `json:"status"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdatePromptRuleStatus(ctx context.Context, arg UpdatePromptRuleStatusParams) error {
|
||||
_, err := q.db.Exec(ctx, updatePromptRuleStatus, arg.Status, arg.ID, arg.TenantID)
|
||||
return err
|
||||
}
|
||||
@@ -13,7 +13,10 @@ type Querier interface {
|
||||
CountArticles(ctx context.Context, arg CountArticlesParams) (int64, error)
|
||||
CountArticlesByTenant(ctx context.Context, tenantID int64) (int64, error)
|
||||
CountBrandsByTenant(ctx context.Context, tenantID int64) (int64, error)
|
||||
CountPromptRules(ctx context.Context, arg CountPromptRulesParams) (int64, error)
|
||||
CountPromptRulesUngrouped(ctx context.Context, tenantID int64) (int64, error)
|
||||
CountPublishedArticlesByTenant(ctx context.Context, tenantID int64) (int64, error)
|
||||
CountScheduleTasks(ctx context.Context, arg CountScheduleTasksParams) (int64, error)
|
||||
CreateArticle(ctx context.Context, arg CreateArticleParams) (int64, error)
|
||||
CreateArticleVersion(ctx context.Context, arg CreateArticleVersionParams) (int64, error)
|
||||
CreateAuditLog(ctx context.Context, arg CreateAuditLogParams) error
|
||||
@@ -21,9 +24,12 @@ type Querier interface {
|
||||
CreateCompetitor(ctx context.Context, arg CreateCompetitorParams) (CreateCompetitorRow, error)
|
||||
CreateGenerationTask(ctx context.Context, arg CreateGenerationTaskParams) (int64, error)
|
||||
CreateKeyword(ctx context.Context, arg CreateKeywordParams) (CreateKeywordRow, error)
|
||||
CreatePromptRule(ctx context.Context, arg CreatePromptRuleParams) (CreatePromptRuleRow, error)
|
||||
CreatePromptRuleGroup(ctx context.Context, arg CreatePromptRuleGroupParams) (CreatePromptRuleGroupRow, error)
|
||||
CreateQuestion(ctx context.Context, arg CreateQuestionParams) (int64, error)
|
||||
CreateQuestionVersion(ctx context.Context, arg CreateQuestionVersionParams) (int64, error)
|
||||
CreateQuotaReservation(ctx context.Context, arg CreateQuotaReservationParams) (int64, error)
|
||||
CreateScheduleTask(ctx context.Context, arg CreateScheduleTaskParams) (CreateScheduleTaskRow, error)
|
||||
DeactivateQuestionVersion(ctx context.Context, questionID int64) error
|
||||
GetActivePlanForTenant(ctx context.Context, tenantID int64) (GetActivePlanForTenantRow, error)
|
||||
GetArticleByID(ctx context.Context, arg GetArticleByIDParams) (GetArticleByIDRow, error)
|
||||
@@ -31,8 +37,10 @@ type Querier interface {
|
||||
GetBrandByID(ctx context.Context, arg GetBrandByIDParams) (GetBrandByIDRow, error)
|
||||
GetCurrentBalance(ctx context.Context, arg GetCurrentBalanceParams) (int32, error)
|
||||
GetLatestQuestionVersionNo(ctx context.Context, questionID int64) (int32, error)
|
||||
GetPromptRuleByID(ctx context.Context, arg GetPromptRuleByIDParams) (GetPromptRuleByIDRow, error)
|
||||
GetQuotaSummary(ctx context.Context, tenantID int64) (int32, error)
|
||||
GetRecentArticles(ctx context.Context, tenantID int64) ([]GetRecentArticlesRow, error)
|
||||
GetScheduleTaskByID(ctx context.Context, arg GetScheduleTaskByIDParams) (GetScheduleTaskByIDRow, error)
|
||||
GetTemplateByID(ctx context.Context, arg GetTemplateByIDParams) (GetTemplateByIDRow, error)
|
||||
GetTemplateSchema(ctx context.Context, id int64) (GetTemplateSchemaRow, error)
|
||||
GetTenantMembership(ctx context.Context, userID int64) (GetTenantMembershipRow, error)
|
||||
@@ -40,12 +48,23 @@ type Querier interface {
|
||||
GetUserByEmail(ctx context.Context, email string) (GetUserByEmailRow, error)
|
||||
GetUserByID(ctx context.Context, id int64) (GetUserByIDRow, error)
|
||||
InsertQuotaLedger(ctx context.Context, arg InsertQuotaLedgerParams) (int64, error)
|
||||
ListAllPromptRulesSimple(ctx context.Context, tenantID int64) ([]ListAllPromptRulesSimpleRow, error)
|
||||
ListArticles(ctx context.Context, arg ListArticlesParams) ([]ListArticlesRow, error)
|
||||
ListBrands(ctx context.Context, tenantID int64) ([]ListBrandsRow, error)
|
||||
ListCompetitors(ctx context.Context, arg ListCompetitorsParams) ([]ListCompetitorsRow, error)
|
||||
ListKeywords(ctx context.Context, arg ListKeywordsParams) ([]ListKeywordsRow, error)
|
||||
// ============================================================
|
||||
// Prompt Rule Groups
|
||||
// ============================================================
|
||||
ListPromptRuleGroups(ctx context.Context, tenantID int64) ([]ListPromptRuleGroupsRow, error)
|
||||
// ============================================================
|
||||
// Prompt Rules
|
||||
// ============================================================
|
||||
ListPromptRules(ctx context.Context, arg ListPromptRulesParams) ([]ListPromptRulesRow, error)
|
||||
ListPromptRulesUngrouped(ctx context.Context, arg ListPromptRulesUngroupedParams) ([]ListPromptRulesUngroupedRow, error)
|
||||
ListQuestionVersions(ctx context.Context, arg ListQuestionVersionsParams) ([]BrandQuestionVersion, error)
|
||||
ListQuestions(ctx context.Context, arg ListQuestionsParams) ([]ListQuestionsRow, error)
|
||||
ListScheduleTasks(ctx context.Context, arg ListScheduleTasksParams) ([]ListScheduleTasksRow, error)
|
||||
ListTemplates(ctx context.Context, tenantID int64) ([]ListTemplatesRow, error)
|
||||
RefundReservation(ctx context.Context, arg RefundReservationParams) error
|
||||
SoftDeleteArticle(ctx context.Context, arg SoftDeleteArticleParams) error
|
||||
@@ -54,16 +73,24 @@ type Querier interface {
|
||||
SoftDeleteCompetitorsByBrand(ctx context.Context, arg SoftDeleteCompetitorsByBrandParams) error
|
||||
SoftDeleteKeyword(ctx context.Context, arg SoftDeleteKeywordParams) error
|
||||
SoftDeleteKeywordsByBrand(ctx context.Context, arg SoftDeleteKeywordsByBrandParams) error
|
||||
SoftDeletePromptRule(ctx context.Context, arg SoftDeletePromptRuleParams) error
|
||||
SoftDeletePromptRuleGroup(ctx context.Context, arg SoftDeletePromptRuleGroupParams) error
|
||||
SoftDeleteQuestion(ctx context.Context, arg SoftDeleteQuestionParams) error
|
||||
SoftDeleteQuestionsByBrand(ctx context.Context, arg SoftDeleteQuestionsByBrandParams) error
|
||||
SoftDeleteScheduleTask(ctx context.Context, arg SoftDeleteScheduleTaskParams) error
|
||||
UpdateArticleCurrentVersion(ctx context.Context, arg UpdateArticleCurrentVersionParams) error
|
||||
UpdateArticleGenerateStatus(ctx context.Context, arg UpdateArticleGenerateStatusParams) error
|
||||
UpdateBrand(ctx context.Context, arg UpdateBrandParams) error
|
||||
UpdateCompetitor(ctx context.Context, arg UpdateCompetitorParams) error
|
||||
UpdateGenerationTaskStatus(ctx context.Context, arg UpdateGenerationTaskStatusParams) error
|
||||
UpdateKeyword(ctx context.Context, arg UpdateKeywordParams) error
|
||||
UpdatePromptRule(ctx context.Context, arg UpdatePromptRuleParams) error
|
||||
UpdatePromptRuleGroup(ctx context.Context, arg UpdatePromptRuleGroupParams) error
|
||||
UpdatePromptRuleStatus(ctx context.Context, arg UpdatePromptRuleStatusParams) error
|
||||
UpdateQuestionCurrentVersion(ctx context.Context, arg UpdateQuestionCurrentVersionParams) error
|
||||
UpdateQuotaReservationResource(ctx context.Context, arg UpdateQuotaReservationResourceParams) error
|
||||
UpdateScheduleTask(ctx context.Context, arg UpdateScheduleTaskParams) error
|
||||
UpdateScheduleTaskStatus(ctx context.Context, arg UpdateScheduleTaskStatusParams) error
|
||||
}
|
||||
|
||||
var _ Querier = (*Queries)(nil)
|
||||
|
||||
@@ -27,17 +27,18 @@ func (q *Queries) ConfirmReservation(ctx context.Context, arg ConfirmReservation
|
||||
}
|
||||
|
||||
const createQuotaReservation = `-- name: CreateQuotaReservation :one
|
||||
INSERT INTO quota_reservations (tenant_id, quota_type, resource_type, resource_id, reserved_amount, status, expire_at)
|
||||
VALUES ($1, $2, $3, $4,
|
||||
$5, 'pending', $6)
|
||||
INSERT INTO quota_reservations (tenant_id, operator_id, quota_type, resource_type, resource_id, reserved_amount, status, expire_at)
|
||||
VALUES ($1, $2, $3, $4, $5,
|
||||
$6, 'pending', $7)
|
||||
RETURNING id
|
||||
`
|
||||
|
||||
type CreateQuotaReservationParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
OperatorID pgtype.Int8 `json:"operator_id"`
|
||||
QuotaType string `json:"quota_type"`
|
||||
ResourceType string `json:"resource_type"`
|
||||
ResourceID int64 `json:"resource_id"`
|
||||
ResourceID pgtype.Int8 `json:"resource_id"`
|
||||
ReservedAmount int32 `json:"reserved_amount"`
|
||||
ExpireAt pgtype.Timestamptz `json:"expire_at"`
|
||||
}
|
||||
@@ -45,6 +46,7 @@ type CreateQuotaReservationParams struct {
|
||||
func (q *Queries) CreateQuotaReservation(ctx context.Context, arg CreateQuotaReservationParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, createQuotaReservation,
|
||||
arg.TenantID,
|
||||
arg.OperatorID,
|
||||
arg.QuotaType,
|
||||
arg.ResourceType,
|
||||
arg.ResourceID,
|
||||
@@ -77,14 +79,15 @@ func (q *Queries) GetCurrentBalance(ctx context.Context, arg GetCurrentBalancePa
|
||||
}
|
||||
|
||||
const insertQuotaLedger = `-- name: InsertQuotaLedger :one
|
||||
INSERT INTO tenant_quota_ledgers (tenant_id, quota_type, delta, balance_after, reason, reference_type, reference_id)
|
||||
VALUES ($1, $2, $3, $4,
|
||||
$5, $6, $7)
|
||||
INSERT INTO tenant_quota_ledgers (tenant_id, operator_id, quota_type, delta, balance_after, reason, reference_type, reference_id)
|
||||
VALUES ($1, $2, $3, $4, $5,
|
||||
$6, $7, $8)
|
||||
RETURNING id
|
||||
`
|
||||
|
||||
type InsertQuotaLedgerParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
OperatorID pgtype.Int8 `json:"operator_id"`
|
||||
QuotaType string `json:"quota_type"`
|
||||
Delta int32 `json:"delta"`
|
||||
BalanceAfter int32 `json:"balance_after"`
|
||||
@@ -96,6 +99,7 @@ type InsertQuotaLedgerParams struct {
|
||||
func (q *Queries) InsertQuotaLedger(ctx context.Context, arg InsertQuotaLedgerParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, insertQuotaLedger,
|
||||
arg.TenantID,
|
||||
arg.OperatorID,
|
||||
arg.QuotaType,
|
||||
arg.Delta,
|
||||
arg.BalanceAfter,
|
||||
@@ -129,9 +133,9 @@ WHERE id = $2 AND tenant_id = $3
|
||||
`
|
||||
|
||||
type UpdateQuotaReservationResourceParams struct {
|
||||
ResourceID int64 `json:"resource_id"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
ResourceID pgtype.Int8 `json:"resource_id"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateQuotaReservationResource(ctx context.Context, arg UpdateQuotaReservationResourceParams) error {
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
// source: schedule_task.sql
|
||||
|
||||
package generated
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const countScheduleTasks = `-- name: CountScheduleTasks :one
|
||||
SELECT COUNT(*)
|
||||
FROM schedule_tasks
|
||||
WHERE tenant_id = $1
|
||||
AND deleted_at IS NULL
|
||||
AND ($2::text IS NULL OR status = $2)
|
||||
AND ($3::bigint IS NULL OR prompt_rule_id = $3)
|
||||
`
|
||||
|
||||
type CountScheduleTasksParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
PromptRuleID pgtype.Int8 `json:"prompt_rule_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CountScheduleTasks(ctx context.Context, arg CountScheduleTasksParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, countScheduleTasks, arg.TenantID, arg.Status, arg.PromptRuleID)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
const createScheduleTask = `-- name: CreateScheduleTask :one
|
||||
INSERT INTO schedule_tasks (tenant_id, prompt_rule_id, brand_id, name, cron_expr,
|
||||
target_platform, start_at, end_at, next_run_at)
|
||||
VALUES ($1, $2, $3, $4,
|
||||
$5, $6, $7, $8,
|
||||
$9)
|
||||
RETURNING id, created_at
|
||||
`
|
||||
|
||||
type CreateScheduleTaskParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
TargetPlatform pgtype.Text `json:"target_platform"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
}
|
||||
|
||||
type CreateScheduleTaskRow struct {
|
||||
ID int64 `json:"id"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateScheduleTask(ctx context.Context, arg CreateScheduleTaskParams) (CreateScheduleTaskRow, error) {
|
||||
row := q.db.QueryRow(ctx, createScheduleTask,
|
||||
arg.TenantID,
|
||||
arg.PromptRuleID,
|
||||
arg.BrandID,
|
||||
arg.Name,
|
||||
arg.CronExpr,
|
||||
arg.TargetPlatform,
|
||||
arg.StartAt,
|
||||
arg.EndAt,
|
||||
arg.NextRunAt,
|
||||
)
|
||||
var i CreateScheduleTaskRow
|
||||
err := row.Scan(&i.ID, &i.CreatedAt)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getScheduleTaskByID = `-- name: GetScheduleTaskByID :one
|
||||
SELECT st.id, st.tenant_id, st.prompt_rule_id, st.brand_id, st.name,
|
||||
st.cron_expr, st.target_platform, st.start_at, st.end_at,
|
||||
st.next_run_at, st.status, st.created_at, st.updated_at,
|
||||
pr.name AS prompt_rule_name,
|
||||
b.name AS brand_name
|
||||
FROM schedule_tasks st
|
||||
LEFT JOIN prompt_rules pr ON pr.id = st.prompt_rule_id
|
||||
LEFT JOIN brands b ON b.id = st.brand_id
|
||||
WHERE st.id = $1 AND st.tenant_id = $2 AND st.deleted_at IS NULL
|
||||
`
|
||||
|
||||
type GetScheduleTaskByIDParams struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
type GetScheduleTaskByIDRow struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
TargetPlatform pgtype.Text `json:"target_platform"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
PromptRuleName pgtype.Text `json:"prompt_rule_name"`
|
||||
BrandName pgtype.Text `json:"brand_name"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetScheduleTaskByID(ctx context.Context, arg GetScheduleTaskByIDParams) (GetScheduleTaskByIDRow, error) {
|
||||
row := q.db.QueryRow(ctx, getScheduleTaskByID, arg.ID, arg.TenantID)
|
||||
var i GetScheduleTaskByIDRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.TenantID,
|
||||
&i.PromptRuleID,
|
||||
&i.BrandID,
|
||||
&i.Name,
|
||||
&i.CronExpr,
|
||||
&i.TargetPlatform,
|
||||
&i.StartAt,
|
||||
&i.EndAt,
|
||||
&i.NextRunAt,
|
||||
&i.Status,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.PromptRuleName,
|
||||
&i.BrandName,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const listScheduleTasks = `-- name: ListScheduleTasks :many
|
||||
SELECT st.id, st.tenant_id, st.prompt_rule_id, st.brand_id, st.name,
|
||||
st.cron_expr, st.target_platform, st.start_at, st.end_at,
|
||||
st.next_run_at, st.status, st.created_at, st.updated_at,
|
||||
pr.name AS prompt_rule_name,
|
||||
b.name AS brand_name
|
||||
FROM schedule_tasks st
|
||||
LEFT JOIN prompt_rules pr ON pr.id = st.prompt_rule_id
|
||||
LEFT JOIN brands b ON b.id = st.brand_id
|
||||
WHERE st.tenant_id = $1
|
||||
AND st.deleted_at IS NULL
|
||||
AND ($2::text IS NULL OR st.status = $2)
|
||||
AND ($3::bigint IS NULL OR st.prompt_rule_id = $3)
|
||||
ORDER BY st.created_at DESC
|
||||
LIMIT $5 OFFSET $4
|
||||
`
|
||||
|
||||
type ListScheduleTasksParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
PromptRuleID pgtype.Int8 `json:"prompt_rule_id"`
|
||||
PageOffset int32 `json:"page_offset"`
|
||||
PageSize int32 `json:"page_size"`
|
||||
}
|
||||
|
||||
type ListScheduleTasksRow struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
TargetPlatform pgtype.Text `json:"target_platform"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
PromptRuleName pgtype.Text `json:"prompt_rule_name"`
|
||||
BrandName pgtype.Text `json:"brand_name"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListScheduleTasks(ctx context.Context, arg ListScheduleTasksParams) ([]ListScheduleTasksRow, error) {
|
||||
rows, err := q.db.Query(ctx, listScheduleTasks,
|
||||
arg.TenantID,
|
||||
arg.Status,
|
||||
arg.PromptRuleID,
|
||||
arg.PageOffset,
|
||||
arg.PageSize,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListScheduleTasksRow
|
||||
for rows.Next() {
|
||||
var i ListScheduleTasksRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.TenantID,
|
||||
&i.PromptRuleID,
|
||||
&i.BrandID,
|
||||
&i.Name,
|
||||
&i.CronExpr,
|
||||
&i.TargetPlatform,
|
||||
&i.StartAt,
|
||||
&i.EndAt,
|
||||
&i.NextRunAt,
|
||||
&i.Status,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.PromptRuleName,
|
||||
&i.BrandName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const softDeleteScheduleTask = `-- name: SoftDeleteScheduleTask :exec
|
||||
UPDATE schedule_tasks SET deleted_at = NOW(), updated_at = NOW()
|
||||
WHERE id = $1 AND tenant_id = $2 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
type SoftDeleteScheduleTaskParams struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) SoftDeleteScheduleTask(ctx context.Context, arg SoftDeleteScheduleTaskParams) error {
|
||||
_, err := q.db.Exec(ctx, softDeleteScheduleTask, arg.ID, arg.TenantID)
|
||||
return err
|
||||
}
|
||||
|
||||
const updateScheduleTask = `-- name: UpdateScheduleTask :exec
|
||||
UPDATE schedule_tasks
|
||||
SET prompt_rule_id = $1, brand_id = $2,
|
||||
name = $3, cron_expr = $4,
|
||||
target_platform = $5,
|
||||
start_at = $6, end_at = $7,
|
||||
next_run_at = $8, updated_at = NOW()
|
||||
WHERE id = $9 AND tenant_id = $10 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
type UpdateScheduleTaskParams struct {
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
TargetPlatform pgtype.Text `json:"target_platform"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateScheduleTask(ctx context.Context, arg UpdateScheduleTaskParams) error {
|
||||
_, err := q.db.Exec(ctx, updateScheduleTask,
|
||||
arg.PromptRuleID,
|
||||
arg.BrandID,
|
||||
arg.Name,
|
||||
arg.CronExpr,
|
||||
arg.TargetPlatform,
|
||||
arg.StartAt,
|
||||
arg.EndAt,
|
||||
arg.NextRunAt,
|
||||
arg.ID,
|
||||
arg.TenantID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const updateScheduleTaskStatus = `-- name: UpdateScheduleTaskStatus :exec
|
||||
UPDATE schedule_tasks SET status = $1, updated_at = NOW()
|
||||
WHERE id = $2 AND tenant_id = $3 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
type UpdateScheduleTaskStatusParams struct {
|
||||
Status string `json:"status"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateScheduleTaskStatus(ctx context.Context, arg UpdateScheduleTaskStatusParams) error {
|
||||
_, err := q.db.Exec(ctx, updateScheduleTaskStatus, arg.Status, arg.ID, arg.TenantID)
|
||||
return err
|
||||
}
|
||||
@@ -94,7 +94,7 @@ func (q *Queries) GetQuotaSummary(ctx context.Context, tenantID int64) (int32, e
|
||||
|
||||
const getRecentArticles = `-- name: GetRecentArticles :many
|
||||
SELECT a.id, a.generate_status, a.publish_status, a.source_type, a.created_at,
|
||||
av.title, av.word_count, av.source_label,
|
||||
av.title, av.markdown_content, av.word_count, av.source_label,
|
||||
t.template_name
|
||||
FROM articles a
|
||||
LEFT JOIN article_versions av ON av.id = a.current_version_id
|
||||
@@ -105,15 +105,16 @@ LIMIT 10
|
||||
`
|
||||
|
||||
type GetRecentArticlesRow struct {
|
||||
ID int64 `json:"id"`
|
||||
GenerateStatus string `json:"generate_status"`
|
||||
PublishStatus string `json:"publish_status"`
|
||||
SourceType string `json:"source_type"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
Title pgtype.Text `json:"title"`
|
||||
WordCount pgtype.Int4 `json:"word_count"`
|
||||
SourceLabel pgtype.Text `json:"source_label"`
|
||||
TemplateName pgtype.Text `json:"template_name"`
|
||||
ID int64 `json:"id"`
|
||||
GenerateStatus string `json:"generate_status"`
|
||||
PublishStatus string `json:"publish_status"`
|
||||
SourceType string `json:"source_type"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
Title pgtype.Text `json:"title"`
|
||||
MarkdownContent pgtype.Text `json:"markdown_content"`
|
||||
WordCount pgtype.Int4 `json:"word_count"`
|
||||
SourceLabel pgtype.Text `json:"source_label"`
|
||||
TemplateName pgtype.Text `json:"template_name"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetRecentArticles(ctx context.Context, tenantID int64) ([]GetRecentArticlesRow, error) {
|
||||
@@ -132,6 +133,7 @@ func (q *Queries) GetRecentArticles(ctx context.Context, tenantID int64) ([]GetR
|
||||
&i.SourceType,
|
||||
&i.CreatedAt,
|
||||
&i.Title,
|
||||
&i.MarkdownContent,
|
||||
&i.WordCount,
|
||||
&i.SourceLabel,
|
||||
&i.TemplateName,
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
-- name: CreateAuditLog :exec
|
||||
INSERT INTO audit_logs (operator_id, tenant_id, module, action, before_json, after_json, result)
|
||||
INSERT INTO audit_logs (
|
||||
operator_id,
|
||||
tenant_id,
|
||||
module,
|
||||
action,
|
||||
resource_type,
|
||||
resource_id,
|
||||
request_id,
|
||||
before_json,
|
||||
after_json,
|
||||
result,
|
||||
error_message
|
||||
)
|
||||
VALUES (sqlc.arg(operator_id), sqlc.arg(tenant_id), sqlc.arg(module), sqlc.arg(action),
|
||||
sqlc.arg(before_json), sqlc.arg(after_json), sqlc.arg(result));
|
||||
sqlc.arg(resource_type), sqlc.arg(resource_id), sqlc.arg(request_id),
|
||||
sqlc.arg(before_json), sqlc.arg(after_json), sqlc.arg(result), sqlc.arg(error_message));
|
||||
|
||||
-- name: CreateGenerationTask :one
|
||||
INSERT INTO generation_tasks (tenant_id, article_id, quota_reservation_id, task_type, input_params_json, status)
|
||||
VALUES (sqlc.arg(tenant_id), sqlc.arg(article_id), sqlc.arg(quota_reservation_id),
|
||||
INSERT INTO generation_tasks (tenant_id, operator_id, article_id, quota_reservation_id, task_type, input_params_json, status)
|
||||
VALUES (sqlc.arg(tenant_id), sqlc.arg(operator_id), sqlc.arg(article_id), sqlc.arg(quota_reservation_id),
|
||||
sqlc.arg(task_type), sqlc.arg(input_params_json), 'queued')
|
||||
RETURNING id;
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
-- ============================================================
|
||||
-- Prompt Rule Groups
|
||||
-- ============================================================
|
||||
|
||||
-- name: ListPromptRuleGroups :many
|
||||
SELECT id, tenant_id, name, sort_order, created_at, updated_at
|
||||
FROM prompt_rule_groups
|
||||
WHERE tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL
|
||||
ORDER BY sort_order, created_at;
|
||||
|
||||
-- name: CreatePromptRuleGroup :one
|
||||
INSERT INTO prompt_rule_groups (tenant_id, name, sort_order)
|
||||
VALUES (sqlc.arg(tenant_id), sqlc.arg(name), sqlc.arg(sort_order))
|
||||
RETURNING id, created_at;
|
||||
|
||||
-- name: UpdatePromptRuleGroup :exec
|
||||
UPDATE prompt_rule_groups SET name = sqlc.arg(name), sort_order = sqlc.arg(sort_order), updated_at = NOW()
|
||||
WHERE id = sqlc.arg(id) AND tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
|
||||
-- name: SoftDeletePromptRuleGroup :exec
|
||||
UPDATE prompt_rule_groups SET deleted_at = NOW(), updated_at = NOW()
|
||||
WHERE id = sqlc.arg(id) AND tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
|
||||
-- ============================================================
|
||||
-- Prompt Rules
|
||||
-- ============================================================
|
||||
|
||||
-- name: ListPromptRules :many
|
||||
SELECT pr.id, pr.tenant_id, pr.group_id, pr.name, pr.prompt_content,
|
||||
pr.scene, pr.default_tone, pr.default_word_count, pr.status,
|
||||
pr.created_at, pr.updated_at,
|
||||
COUNT(a.id)::INT AS article_count
|
||||
FROM prompt_rules pr
|
||||
LEFT JOIN articles a ON a.prompt_rule_id = pr.id AND a.deleted_at IS NULL
|
||||
WHERE pr.tenant_id = sqlc.arg(tenant_id)
|
||||
AND pr.deleted_at IS NULL
|
||||
AND (sqlc.narg(group_id)::bigint IS NULL OR pr.group_id = sqlc.narg(group_id))
|
||||
AND (sqlc.narg(status)::text IS NULL OR pr.status = sqlc.narg(status))
|
||||
AND (sqlc.narg(keyword)::text IS NULL OR pr.name ILIKE '%' || sqlc.narg(keyword) || '%')
|
||||
GROUP BY pr.id
|
||||
ORDER BY pr.created_at DESC
|
||||
LIMIT sqlc.arg(page_size) OFFSET sqlc.arg(page_offset);
|
||||
|
||||
-- name: CountPromptRules :one
|
||||
SELECT COUNT(*)
|
||||
FROM prompt_rules
|
||||
WHERE tenant_id = sqlc.arg(tenant_id)
|
||||
AND deleted_at IS NULL
|
||||
AND (sqlc.narg(group_id)::bigint IS NULL OR group_id = sqlc.narg(group_id))
|
||||
AND (sqlc.narg(status)::text IS NULL OR status = sqlc.narg(status))
|
||||
AND (sqlc.narg(keyword)::text IS NULL OR name ILIKE '%' || sqlc.narg(keyword) || '%');
|
||||
|
||||
-- name: ListPromptRulesUngrouped :many
|
||||
SELECT pr.id, pr.tenant_id, pr.group_id, pr.name, pr.prompt_content,
|
||||
pr.scene, pr.default_tone, pr.default_word_count, pr.status,
|
||||
pr.created_at, pr.updated_at,
|
||||
COUNT(a.id)::INT AS article_count
|
||||
FROM prompt_rules pr
|
||||
LEFT JOIN articles a ON a.prompt_rule_id = pr.id AND a.deleted_at IS NULL
|
||||
WHERE pr.tenant_id = sqlc.arg(tenant_id)
|
||||
AND pr.deleted_at IS NULL
|
||||
AND pr.group_id IS NULL
|
||||
GROUP BY pr.id
|
||||
ORDER BY pr.created_at DESC
|
||||
LIMIT sqlc.arg(page_size) OFFSET sqlc.arg(page_offset);
|
||||
|
||||
-- name: CountPromptRulesUngrouped :one
|
||||
SELECT COUNT(*)
|
||||
FROM prompt_rules
|
||||
WHERE tenant_id = sqlc.arg(tenant_id)
|
||||
AND deleted_at IS NULL
|
||||
AND group_id IS NULL;
|
||||
|
||||
-- name: GetPromptRuleByID :one
|
||||
SELECT id, tenant_id, group_id, name, prompt_content,
|
||||
scene, default_tone, default_word_count, status,
|
||||
created_at, updated_at
|
||||
FROM prompt_rules
|
||||
WHERE id = sqlc.arg(id) AND tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
|
||||
-- name: CreatePromptRule :one
|
||||
INSERT INTO prompt_rules (tenant_id, group_id, name, prompt_content, scene, default_tone, default_word_count)
|
||||
VALUES (sqlc.arg(tenant_id), sqlc.narg(group_id), sqlc.arg(name), sqlc.arg(prompt_content),
|
||||
sqlc.narg(scene), sqlc.narg(default_tone), sqlc.narg(default_word_count))
|
||||
RETURNING id, created_at;
|
||||
|
||||
-- name: UpdatePromptRule :exec
|
||||
UPDATE prompt_rules
|
||||
SET name = sqlc.arg(name), group_id = sqlc.narg(group_id),
|
||||
prompt_content = sqlc.arg(prompt_content),
|
||||
scene = sqlc.narg(scene), default_tone = sqlc.narg(default_tone),
|
||||
default_word_count = sqlc.narg(default_word_count), updated_at = NOW()
|
||||
WHERE id = sqlc.arg(id) AND tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
|
||||
-- name: UpdatePromptRuleStatus :exec
|
||||
UPDATE prompt_rules SET status = sqlc.arg(status), updated_at = NOW()
|
||||
WHERE id = sqlc.arg(id) AND tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
|
||||
-- name: SoftDeletePromptRule :exec
|
||||
UPDATE prompt_rules SET deleted_at = NOW(), updated_at = NOW()
|
||||
WHERE id = sqlc.arg(id) AND tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
|
||||
-- name: ListAllPromptRulesSimple :many
|
||||
SELECT id, name, status
|
||||
FROM prompt_rules
|
||||
WHERE tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL AND status = 'enabled'
|
||||
ORDER BY name;
|
||||
@@ -6,14 +6,14 @@ SELECT COALESCE(
|
||||
)::INT AS balance;
|
||||
|
||||
-- name: InsertQuotaLedger :one
|
||||
INSERT INTO tenant_quota_ledgers (tenant_id, quota_type, delta, balance_after, reason, reference_type, reference_id)
|
||||
VALUES (sqlc.arg(tenant_id), sqlc.arg(quota_type), sqlc.arg(delta), sqlc.arg(balance_after),
|
||||
INSERT INTO tenant_quota_ledgers (tenant_id, operator_id, quota_type, delta, balance_after, reason, reference_type, reference_id)
|
||||
VALUES (sqlc.arg(tenant_id), sqlc.arg(operator_id), sqlc.arg(quota_type), sqlc.arg(delta), sqlc.arg(balance_after),
|
||||
sqlc.arg(reason), sqlc.arg(reference_type), sqlc.arg(reference_id))
|
||||
RETURNING id;
|
||||
|
||||
-- name: CreateQuotaReservation :one
|
||||
INSERT INTO quota_reservations (tenant_id, quota_type, resource_type, resource_id, reserved_amount, status, expire_at)
|
||||
VALUES (sqlc.arg(tenant_id), sqlc.arg(quota_type), sqlc.arg(resource_type), sqlc.arg(resource_id),
|
||||
INSERT INTO quota_reservations (tenant_id, operator_id, quota_type, resource_type, resource_id, reserved_amount, status, expire_at)
|
||||
VALUES (sqlc.arg(tenant_id), sqlc.arg(operator_id), sqlc.arg(quota_type), sqlc.arg(resource_type), sqlc.arg(resource_id),
|
||||
sqlc.arg(reserved_amount), 'pending', sqlc.arg(expire_at))
|
||||
RETURNING id;
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
-- name: ListScheduleTasks :many
|
||||
SELECT st.id, st.tenant_id, st.prompt_rule_id, st.brand_id, st.name,
|
||||
st.cron_expr, st.target_platform, st.start_at, st.end_at,
|
||||
st.next_run_at, st.status, st.created_at, st.updated_at,
|
||||
pr.name AS prompt_rule_name,
|
||||
b.name AS brand_name
|
||||
FROM schedule_tasks st
|
||||
LEFT JOIN prompt_rules pr ON pr.id = st.prompt_rule_id
|
||||
LEFT JOIN brands b ON b.id = st.brand_id
|
||||
WHERE st.tenant_id = sqlc.arg(tenant_id)
|
||||
AND st.deleted_at IS NULL
|
||||
AND (sqlc.narg(status)::text IS NULL OR st.status = sqlc.narg(status))
|
||||
AND (sqlc.narg(prompt_rule_id)::bigint IS NULL OR st.prompt_rule_id = sqlc.narg(prompt_rule_id))
|
||||
ORDER BY st.created_at DESC
|
||||
LIMIT sqlc.arg(page_size) OFFSET sqlc.arg(page_offset);
|
||||
|
||||
-- name: CountScheduleTasks :one
|
||||
SELECT COUNT(*)
|
||||
FROM schedule_tasks
|
||||
WHERE tenant_id = sqlc.arg(tenant_id)
|
||||
AND deleted_at IS NULL
|
||||
AND (sqlc.narg(status)::text IS NULL OR status = sqlc.narg(status))
|
||||
AND (sqlc.narg(prompt_rule_id)::bigint IS NULL OR prompt_rule_id = sqlc.narg(prompt_rule_id));
|
||||
|
||||
-- name: GetScheduleTaskByID :one
|
||||
SELECT st.id, st.tenant_id, st.prompt_rule_id, st.brand_id, st.name,
|
||||
st.cron_expr, st.target_platform, st.start_at, st.end_at,
|
||||
st.next_run_at, st.status, st.created_at, st.updated_at,
|
||||
pr.name AS prompt_rule_name,
|
||||
b.name AS brand_name
|
||||
FROM schedule_tasks st
|
||||
LEFT JOIN prompt_rules pr ON pr.id = st.prompt_rule_id
|
||||
LEFT JOIN brands b ON b.id = st.brand_id
|
||||
WHERE st.id = sqlc.arg(id) AND st.tenant_id = sqlc.arg(tenant_id) AND st.deleted_at IS NULL;
|
||||
|
||||
-- name: CreateScheduleTask :one
|
||||
INSERT INTO schedule_tasks (tenant_id, prompt_rule_id, brand_id, name, cron_expr,
|
||||
target_platform, start_at, end_at, next_run_at)
|
||||
VALUES (sqlc.arg(tenant_id), sqlc.arg(prompt_rule_id), sqlc.narg(brand_id), sqlc.arg(name),
|
||||
sqlc.arg(cron_expr), sqlc.narg(target_platform), sqlc.narg(start_at), sqlc.narg(end_at),
|
||||
sqlc.narg(next_run_at))
|
||||
RETURNING id, created_at;
|
||||
|
||||
-- name: UpdateScheduleTask :exec
|
||||
UPDATE schedule_tasks
|
||||
SET prompt_rule_id = sqlc.arg(prompt_rule_id), brand_id = sqlc.narg(brand_id),
|
||||
name = sqlc.arg(name), cron_expr = sqlc.arg(cron_expr),
|
||||
target_platform = sqlc.narg(target_platform),
|
||||
start_at = sqlc.narg(start_at), end_at = sqlc.narg(end_at),
|
||||
next_run_at = sqlc.narg(next_run_at), updated_at = NOW()
|
||||
WHERE id = sqlc.arg(id) AND tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
|
||||
-- name: UpdateScheduleTaskStatus :exec
|
||||
UPDATE schedule_tasks SET status = sqlc.arg(status), updated_at = NOW()
|
||||
WHERE id = sqlc.arg(id) AND tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
|
||||
-- name: SoftDeleteScheduleTask :exec
|
||||
UPDATE schedule_tasks SET deleted_at = NOW(), updated_at = NOW()
|
||||
WHERE id = sqlc.arg(id) AND tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
@@ -12,7 +12,7 @@ WHERE tenant_id = sqlc.arg(tenant_id) AND deleted_at IS NULL;
|
||||
|
||||
-- name: GetRecentArticles :many
|
||||
SELECT a.id, a.generate_status, a.publish_status, a.source_type, a.created_at,
|
||||
av.title, av.word_count, av.source_label,
|
||||
av.title, av.markdown_content, av.word_count, av.source_label,
|
||||
t.template_name
|
||||
FROM articles a
|
||||
LEFT JOIN article_versions av ON av.id = a.current_version_id
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
type QuotaLedgerInput struct {
|
||||
TenantID int64
|
||||
OperatorID int64
|
||||
QuotaType string
|
||||
Delta int
|
||||
BalanceAfter int
|
||||
@@ -19,9 +20,10 @@ type QuotaLedgerInput struct {
|
||||
|
||||
type QuotaReservationInput struct {
|
||||
TenantID int64
|
||||
OperatorID int64
|
||||
QuotaType string
|
||||
ResourceType string
|
||||
ResourceID int64
|
||||
ResourceID *int64
|
||||
ReservedAmount int
|
||||
ExpireAt time.Time
|
||||
}
|
||||
@@ -55,8 +57,10 @@ func (r *quotaRepository) GetCurrentBalance(ctx context.Context, tenantID int64,
|
||||
}
|
||||
|
||||
func (r *quotaRepository) InsertQuotaLedger(ctx context.Context, input QuotaLedgerInput) (int64, error) {
|
||||
operatorID := input.OperatorID
|
||||
return r.q.InsertQuotaLedger(ctx, generated.InsertQuotaLedgerParams{
|
||||
TenantID: input.TenantID,
|
||||
OperatorID: pgInt8(&operatorID),
|
||||
QuotaType: input.QuotaType,
|
||||
Delta: int32(input.Delta),
|
||||
BalanceAfter: int32(input.BalanceAfter),
|
||||
@@ -68,19 +72,22 @@ func (r *quotaRepository) InsertQuotaLedger(ctx context.Context, input QuotaLedg
|
||||
|
||||
func (r *quotaRepository) CreateQuotaReservation(ctx context.Context, input QuotaReservationInput) (int64, error) {
|
||||
expireAt := input.ExpireAt
|
||||
operatorID := input.OperatorID
|
||||
return r.q.CreateQuotaReservation(ctx, generated.CreateQuotaReservationParams{
|
||||
TenantID: input.TenantID,
|
||||
OperatorID: pgInt8(&operatorID),
|
||||
QuotaType: input.QuotaType,
|
||||
ResourceType: input.ResourceType,
|
||||
ResourceID: input.ResourceID,
|
||||
ResourceID: pgInt8(input.ResourceID),
|
||||
ReservedAmount: int32(input.ReservedAmount),
|
||||
ExpireAt: pgTimestamp(&expireAt),
|
||||
})
|
||||
}
|
||||
|
||||
func (r *quotaRepository) UpdateQuotaReservationResource(ctx context.Context, reservationID, tenantID, resourceID int64) error {
|
||||
resourceIDValue := resourceID
|
||||
return r.q.UpdateQuotaReservationResource(ctx, generated.UpdateQuotaReservationResourceParams{
|
||||
ResourceID: resourceID,
|
||||
ResourceID: pgInt8(&resourceIDValue),
|
||||
ID: reservationID,
|
||||
TenantID: tenantID,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
|
||||
"github.com/geo-platform/tenant-api/internal/tenant/repository/generated"
|
||||
)
|
||||
|
||||
var ErrTemplateAssistTaskNotFound = errors.New("template assist task not found")
|
||||
|
||||
type TemplateAssistTaskRecord struct {
|
||||
ID string
|
||||
Status string
|
||||
ResultJSON []byte
|
||||
ErrorMessage *string
|
||||
}
|
||||
|
||||
type CreateTemplateAssistTaskInput struct {
|
||||
ID string
|
||||
TaskType string
|
||||
TenantID int64
|
||||
OperatorID int64
|
||||
TemplateID int64
|
||||
RequestJSON []byte
|
||||
}
|
||||
|
||||
type TemplateAssistTaskRepository interface {
|
||||
CreateTask(ctx context.Context, input CreateTemplateAssistTaskInput) error
|
||||
GetTask(ctx context.Context, id, taskType string, tenantID, templateID int64) (*TemplateAssistTaskRecord, error)
|
||||
MarkRunning(ctx context.Context, id, taskType string, tenantID int64, startedAt time.Time) error
|
||||
CompleteTask(ctx context.Context, id, taskType string, tenantID int64, resultJSON []byte, completedAt time.Time) error
|
||||
FailTask(ctx context.Context, id, taskType string, tenantID int64, errorMessage string, completedAt time.Time) error
|
||||
}
|
||||
|
||||
type templateAssistTaskRepository struct {
|
||||
db generated.DBTX
|
||||
}
|
||||
|
||||
func NewTemplateAssistTaskRepository(db generated.DBTX) TemplateAssistTaskRepository {
|
||||
return &templateAssistTaskRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *templateAssistTaskRepository) CreateTask(ctx context.Context, input CreateTemplateAssistTaskInput) error {
|
||||
_, err := r.db.Exec(ctx, `
|
||||
INSERT INTO template_assist_tasks (id, task_type, tenant_id, operator_id, template_id, request_json, status)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, 'queued')
|
||||
`, input.ID, input.TaskType, input.TenantID, input.OperatorID, input.TemplateID, input.RequestJSON)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *templateAssistTaskRepository) GetTask(ctx context.Context, id, taskType string, tenantID, templateID int64) (*TemplateAssistTaskRecord, error) {
|
||||
var record TemplateAssistTaskRecord
|
||||
err := r.db.QueryRow(ctx, `
|
||||
SELECT id, status, result_json, error_message
|
||||
FROM template_assist_tasks
|
||||
WHERE id = $1 AND task_type = $2 AND tenant_id = $3 AND template_id = $4
|
||||
`, id, taskType, tenantID, templateID).Scan(&record.ID, &record.Status, &record.ResultJSON, &record.ErrorMessage)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, ErrTemplateAssistTaskNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
func (r *templateAssistTaskRepository) MarkRunning(ctx context.Context, id, taskType string, tenantID int64, startedAt time.Time) error {
|
||||
_, err := r.db.Exec(ctx, `
|
||||
UPDATE template_assist_tasks
|
||||
SET status = 'running', started_at = $1, updated_at = NOW()
|
||||
WHERE id = $2 AND task_type = $3 AND tenant_id = $4
|
||||
`, startedAt, id, taskType, tenantID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *templateAssistTaskRepository) CompleteTask(ctx context.Context, id, taskType string, tenantID int64, resultJSON []byte, completedAt time.Time) error {
|
||||
_, err := r.db.Exec(ctx, `
|
||||
UPDATE template_assist_tasks
|
||||
SET status = 'completed',
|
||||
result_json = $1,
|
||||
error_message = NULL,
|
||||
completed_at = $2,
|
||||
updated_at = NOW()
|
||||
WHERE id = $3 AND task_type = $4 AND tenant_id = $5
|
||||
`, resultJSON, completedAt, id, taskType, tenantID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *templateAssistTaskRepository) FailTask(ctx context.Context, id, taskType string, tenantID int64, errorMessage string, completedAt time.Time) error {
|
||||
_, err := r.db.Exec(ctx, `
|
||||
UPDATE template_assist_tasks
|
||||
SET status = 'failed',
|
||||
error_message = $1,
|
||||
completed_at = $2,
|
||||
updated_at = NOW()
|
||||
WHERE id = $3 AND task_type = $4 AND tenant_id = $5
|
||||
`, errorMessage, completedAt, id, taskType, tenantID)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/geo-platform/tenant-api/internal/shared/cache"
|
||||
)
|
||||
|
||||
const templateCacheTTL = 5 * time.Minute
|
||||
|
||||
type cachedTemplateRepository struct {
|
||||
inner TemplateRepository
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
func NewCachedTemplateRepository(inner TemplateRepository, c cache.Cache) TemplateRepository {
|
||||
return &cachedTemplateRepository{inner: inner, cache: c}
|
||||
}
|
||||
|
||||
func (r *cachedTemplateRepository) ListTemplates(ctx context.Context, tenantID int64) ([]TemplateRecord, error) {
|
||||
key := fmt.Sprintf("tmpl_list:%d", tenantID)
|
||||
|
||||
if data, err := r.cache.Get(ctx, key); err == nil {
|
||||
var records []TemplateRecord
|
||||
if err := json.Unmarshal(data, &records); err == nil {
|
||||
return records, nil
|
||||
}
|
||||
}
|
||||
|
||||
records, err := r.inner.ListTemplates(ctx, tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if data, err := json.Marshal(records); err == nil {
|
||||
_ = r.cache.Set(ctx, key, data, templateCacheTTL)
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (r *cachedTemplateRepository) GetTemplateByID(ctx context.Context, id, tenantID int64) (*TemplateRecord, error) {
|
||||
key := fmt.Sprintf("tmpl:%d:%d", tenantID, id)
|
||||
|
||||
if data, err := r.cache.Get(ctx, key); err == nil {
|
||||
var record TemplateRecord
|
||||
if err := json.Unmarshal(data, &record); err == nil {
|
||||
return &record, nil
|
||||
}
|
||||
}
|
||||
|
||||
record, err := r.inner.GetTemplateByID(ctx, id, tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if data, err := json.Marshal(record); err == nil {
|
||||
_ = r.cache.Set(ctx, key, data, templateCacheTTL)
|
||||
}
|
||||
return record, nil
|
||||
}
|
||||
|
||||
func (r *cachedTemplateRepository) GetTemplateSchema(ctx context.Context, id int64) (*TemplateSchemaRecord, error) {
|
||||
return r.inner.GetTemplateSchema(ctx, id)
|
||||
}
|
||||
@@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
|
||||
"github.com/geo-platform/tenant-api/internal/shared/contentstats"
|
||||
"github.com/geo-platform/tenant-api/internal/tenant/repository/generated"
|
||||
)
|
||||
|
||||
@@ -71,7 +74,7 @@ func (r *workspaceRepository) GetRecentArticles(ctx context.Context, tenantID in
|
||||
SourceType: row.SourceType,
|
||||
CreatedAt: timeFromTimestamp(row.CreatedAt),
|
||||
Title: nullableText(row.Title),
|
||||
WordCount: intFromInt4(row.WordCount),
|
||||
WordCount: resolveWorkspaceWordCount(row.MarkdownContent, intFromInt4(row.WordCount)),
|
||||
SourceLabel: nullableText(row.SourceLabel),
|
||||
TemplateName: nullableText(row.TemplateName),
|
||||
})
|
||||
@@ -102,3 +105,12 @@ func (r *workspaceRepository) GetActivePlanForTenant(ctx context.Context, tenant
|
||||
EndAt: timeFromTimestamp(row.EndAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func resolveWorkspaceWordCount(markdown pgtype.Text, stored int) int {
|
||||
if markdown.Valid {
|
||||
if counted := contentstats.CountWords(markdown.String); counted > 0 {
|
||||
return counted
|
||||
}
|
||||
}
|
||||
return stored
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user