使用 SQLX、Squirrel 执行 JOIN 的最佳实践

问题描述

我有这个模型。

// Incident is a security incident.
type Incident struct {
    ID          string                 `json:"id" bson:"_id"`
    Title       string                 `json:"title" bson:"title"`
    Description string                 `json:"description" bson:"description"`
    Issue       *Issue                 `json:"issue" bson:"issue"`
    CreatedAt   time.Time              `json:"created_at" bson:"created_at"`
    ModifiedAt  time.Time              `json:"modified_at" bson:"modified_at"`
}

// Issue is a security issue.
type Issue struct {
    ID                         string                 `json:"id" bson:"_id"`
    Title                      string                 `json:"title" bson:"title"`
    IncidentID                 string                 `json:"incident_id"`
    Description                string                 `json:"description" bson:"description"`
}

每个事件都有一个问题

当我在 Postgres 中插入一个事件时,我只添加issue_id

type incident struct {
    ID          string    `db:"id"`
    CustomerID  string    `db:"customer_id"`
    InternalID  string    `db:"internal_id"`
    Title       string    `db:"title"`
    IssueID     string    `db:"issue_id"`
    Description string    `db:"description"`
    CreatedAt   time.Time `db:"created_at"`
    ModifiedAt  time.Time `db:"modified_at"`
}

func toIncident(model *models.Incident) (*incident,error) {
    // Create the sql
    incident := &sqlIncident{
        ID:          model.ID,CustomerID:  model.CustomerID,InternalID:  model.InternalID,Title:       model.Title,Description: model.Description,IssueID:     "",CreatedAt:   model.CreatedAt,ModifiedAt:  model.ModifiedAt,}

    // Add the issue ID
    if model.Issue != nil {
        incident.IssueID = model.Issue.ID
    }

    return incident,nil
}

当我发生get()list()事件时,我希望能够对问题使用JOIN进行反向操作。

我正在使用 "github.com/Masterminds/squirrel""github.com/jmoiron/sqlx"

下面的代码将是获取事件的代码

    // Prepare query
    query := squirrel.Select(*).
        From(r.GetTableName()).
        PlaceholderFormat(squirrel.Dollar).
        Join("????????")

    // Build the sql query
    q,args,err := query.Tosql()
    if err != nil {
        return fmt.Errorf("postgresql: unable to build query: %w",err)
    }

    // Get the session repo
    session := r.GetSession().(*sqlx.DB)

    // Prepare the statement
    stmt,err := session.PreparexContext(ctx,q)
    if err != nil {
        return fmt.Errorf("postgresql: unable to prepapre query: %w",err)
    }

    // Do the query
    err = stmt.SelectContext(ctx,result,args...)
    if err == sql.Errnorows {
        return repositories.Errnoresult
    } else if err != nil {
        return fmt.Errorf("postgresql: unable to execute query: %w",err)
    }

我该如何正确执行此操作?

我觉得我对似乎无用的 issue_id 字段做错了,我应该在我的 incident添加 Issue 的定义sql 结构,如下所示。

type incident struct {
    ID          string    `db:"id"`
    CustomerID  string    `db:"customer_id"`
    InternalID  string    `db:"internal_id"`
    Title       string    `db:"title"`
    Issue       issue     `db:"issue"`
    Description string    `db:"description"`
    CreatedAt   time.Time `db:"created_at"`
    ModifiedAt  time.Time `db:"modified_at"`
}

但我看不到接下来的步骤。

解决方法

我认为您可以编写如下查询:

query := squirrel.Select("*").
    From("incident").
    LeftJoin("issue as i on incident.issue_id=i.id")