У меня возникли проблемы с созданием правильного запроса выбора с соединениями с использованием go-pg orm, где одна запись таблицы может быть удалена, а две другие - нет.
Таблицы БД:
go-pg Модели:
type pipelineTriggerEvent struct {
tableName struct{} `pg:"pipeline_trigger_events,alias:pte"`
Trigger *pipelineTrigger `pg:"rel:has-one,join_fk:id"`
PipelineInstance *pipelineInstance `pg:"rel:has-one,join_fk:event_id"`
*TriggerEvent
}
type pipelineTrigger struct {
tableName struct{} `pg:"pipeline_triggers,alias:pt"`
*Trigger
}
type pipelineInstance struct {
tableName struct{} `pg:"pipeline_pipeline_instances,alias:ppi"`
*PipelineInstance
}
Запрос, который я пытаюсь создать:
SELECT
pte.*, trigger.*, pipeline_instance.*
FROM
pipeline_trigger_events AS pte
LEFT JOIN pipeline_triggers AS trigger ON (trigger.id = pte.trigger_id)
LEFT JOIN pipeline_pipeline_instances AS pipeline_instance ON pipeline_instance.event_id = pte.event_id AND trigger.pipeline_id = pipeline_instance.pipeline_id
Запрос генерируется go-pg orm:
SELECT
pte.*, trigger.*, pipeline_instance.*
FROM
pipeline_trigger_events AS pte
LEFT JOIN pipeline_triggers AS trigger ON (trigger.id = pte.trigger_id)
AND trigger.deleted_at IS NULL -- this is the unwanted line.
LEFT JOIN pipeline_pipeline_instances AS pipeline_instance ON pipeline_instance.event_id = pte.event_id AND trigger.pipeline_id = pipeline_instance.pipeline_id
var triggerevents []pipelineTriggerEvent
q := db.Model(&triggerevents).
Column("pte.*").
Relation("Trigger").
Relation("PipelineInstance", func(q *orm.Query) (*orm.Query, error) {
q = q.Join(" AND trigger.pipeline_id = pipeline_instance.pipeline_id")
return q, nil
})
Из всех трех таблиц/моделей, упомянутых выше, только таблица pipe_triggers имеет столбец deleted_at, который используется для обратимого удаления. Мое требование состоит в том, чтобы включить обратимо удаленные строки pipe_triggers также в набор результатов. Но go-pg orm автоматически добавляет условие trigger.deleted_at IS NULL в предложение join. Как я могу удалить это условие и получить все строки, включая обратимо удаленные.
Я пытался использовать функцию AllWithDeleted, но она работает с основной моделью, то есть с pipe_trigger_events (и в этой таблице в любом случае нет столбца delete_at), а не с pipeline_triggers, и поэтому сбой с этой ошибкой:
pg: model=PipelineTriggerEvent does not support soft deletes
@kimbo Пробовал изменить Relation("Trigger"), после Relation("PipelineInstance") и после q.Join("..."). Все они дают ту же ошибку, что у pipeTriggerEvent нет столбца delete_at
Поскольку вы знаете, какой sql вам нужен, вы можете просто передать его в db.Query или db.QueryWithContext.





Немного просмотрев код pg-go, я не знаю, поддерживается ли то, что вы пытаетесь сделать. Чтобы знать наверняка, вы, вероятно, захотите выполнить приведенный ниже код в отладчике.
Когда запрос строится для соединений, он имеет этот раздел:
https://github.com/go-pg/pg/blob/c9ee578a38d6866649072df18a3dbb36ff369747/orm/join.go#L283
if isSoftDelete {
b = append(b, " AND "...)
b = j.appendAlias(b)
b = j.appendSoftDelete(b, q.flags)
}
Строка j.appendAlias(b) вызывает функцию appendAlias() ниже:
https://github.com/go-pg/pg/blob/c9ee578a38d6866649072df18a3dbb36ff369747/orm/join.go#L200
func appendAlias(b []byte, j *join) []byte {
if j.hasParent() {
b = appendAlias(b, j.Parent)
b = append(b, "__"...)
}
b = append(b, j.Rel.Field.SQLName...)
return b
}
Поскольку оба соединения имеют отношение has-one parent, оно добавляется для всех таблиц: https://github.com/go-pg/pg/blob/c9ee578a38d6866649072df18a3dbb36ff369747/orm/join.go#L153
func (j *join) hasParent() bool {
if j.Parent != nil {
switch j.Parent.Rel.Type {
case HasOneRelation, BelongsToRelation:
return true
}
}
return false
}
Я думаю, что вы могли бы исправить это, если бы вызывали appendAlias() только для родительского отношения, а не для двух других, но похоже, что это не поддерживается pg-go.
Что вы можете сделать для этого, так это просто вызвать pg.Query() или pg.QueryWithContext() и передать оператор sql, который вы включили выше.
Также стоит упомянуть, что pg-go/pg находится в режиме обслуживания, поэтому маловероятно, что они когда-либо будут его поддерживать. В зависимости от того, насколько этот проект укоренился в pg-go, вы можете рассмотреть возможность использования Bun, который активно разрабатывается.
Приложение
Вот функция appendSoftDelete(), которая вызывается в первом фрагменте выше:
https://github.com/go-pg/pg/blob/c9ee578a38d6866649072df18a3dbb36ff369747/orm/join.go#L189
func (j *join) appendSoftDelete(b []byte, flags queryFlag) []byte {
b = append(b, '.')
b = append(b, j.JoinModel.Table().SoftDeleteField.Column...)
if hasFlag(flags, deletedFlag) {
b = append(b, " IS NOT NULL"...)
} else {
b = append(b, " IS NULL"...)
}
return b
}
Где в вашем коде вы пытались добавить AllWithDeleted()? Будет ли это работать, если вы добавите его после вызова q.join? то есть
q.join(...).AllWithDeleted()