diff --git a/server/codegen/assets/templates/gocode/store/rdbms/rdbms.go.tpl b/server/codegen/assets/templates/gocode/store/rdbms/rdbms.go.tpl index 4685a9f07..afb6889ce 100644 --- a/server/codegen/assets/templates/gocode/store/rdbms/rdbms.go.tpl +++ b/server/codegen/assets/templates/gocode/store/rdbms/rdbms.go.tpl @@ -80,8 +80,29 @@ func (s *Store) Upsert{{ .expIdent }}(ctx context.Context, {{ template "extraArg return } - if err = s.Exec(ctx, {{ .ident }}UpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, {{ .ident }}UpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, {{ .ident }}InsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, {{ .ident }}UpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } diff --git a/server/store/adapters/rdbms/drivers/dialect.go b/server/store/adapters/rdbms/drivers/dialect.go index 9a26b1755..2b611310a 100644 --- a/server/store/adapters/rdbms/drivers/dialect.go +++ b/server/store/adapters/rdbms/drivers/dialect.go @@ -3,6 +3,7 @@ package drivers import ( "encoding/json" "fmt" + "github.com/cortezaproject/corteza/server/pkg/dal" "github.com/cortezaproject/corteza/server/pkg/ql" "github.com/cortezaproject/corteza/server/store/adapters/rdbms/ddl" @@ -17,6 +18,13 @@ type ( // use of aliases inside HAVING clause and // MySQL does not. HavingClauseMustUseAlias bool + + // TwoStepUpsert allows support for databases which don't have an upsert + // or we simply couldn't figure out how to make work. + // + // TwoStepUpsert uses the context from the update statement to figure out + // if it needs to do an insert. + TwoStepUpsert bool } Dialect interface { diff --git a/server/store/adapters/rdbms/rdbms.gen.go b/server/store/adapters/rdbms/rdbms.gen.go index de39a7758..51d9461f2 100644 --- a/server/store/adapters/rdbms/rdbms.gen.go +++ b/server/store/adapters/rdbms/rdbms.gen.go @@ -117,8 +117,29 @@ func (s *Store) UpsertActionlog(ctx context.Context, rr ...*actionlogType.Action return } - if err = s.Exec(ctx, actionlogUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, actionlogUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, actionlogInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, actionlogUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -428,8 +449,29 @@ func (s *Store) UpsertApigwFilter(ctx context.Context, rr ...*systemType.ApigwFi return } - if err = s.Exec(ctx, apigwFilterUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, apigwFilterUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, apigwFilterInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, apigwFilterUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -1005,8 +1047,29 @@ func (s *Store) UpsertApigwRoute(ctx context.Context, rr ...*systemType.ApigwRou return } - if err = s.Exec(ctx, apigwRouteUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, apigwRouteUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, apigwRouteInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, apigwRouteUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -1586,8 +1649,29 @@ func (s *Store) UpsertApplication(ctx context.Context, rr ...*systemType.Applica return } - if err = s.Exec(ctx, applicationUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, applicationUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, applicationInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, applicationUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -2122,8 +2206,29 @@ func (s *Store) UpsertAttachment(ctx context.Context, rr ...*systemType.Attachme return } - if err = s.Exec(ctx, attachmentUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, attachmentUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, attachmentInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, attachmentUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -2653,8 +2758,29 @@ func (s *Store) UpsertAuthClient(ctx context.Context, rr ...*systemType.AuthClie return } - if err = s.Exec(ctx, authClientUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, authClientUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, authClientInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, authClientUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -3268,8 +3394,29 @@ func (s *Store) UpsertAuthConfirmedClient(ctx context.Context, rr ...*systemType return } - if err = s.Exec(ctx, authConfirmedClientUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, authConfirmedClientUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, authConfirmedClientInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, authConfirmedClientUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -3580,8 +3727,29 @@ func (s *Store) UpsertAuthOa2token(ctx context.Context, rr ...*systemType.AuthOa return } - if err = s.Exec(ctx, authOa2tokenUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, authOa2tokenUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, authOa2tokenInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, authOa2tokenUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -4004,8 +4172,29 @@ func (s *Store) UpsertAuthSession(ctx context.Context, rr ...*systemType.AuthSes return } - if err = s.Exec(ctx, authSessionUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, authSessionUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, authSessionInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, authSessionUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -4308,8 +4497,29 @@ func (s *Store) UpsertAutomationSession(ctx context.Context, rr ...*automationTy return } - if err = s.Exec(ctx, automationSessionUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, automationSessionUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, automationSessionInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, automationSessionUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -4854,8 +5064,29 @@ func (s *Store) UpsertAutomationTrigger(ctx context.Context, rr ...*automationTy return } - if err = s.Exec(ctx, automationTriggerUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, automationTriggerUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, automationTriggerInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, automationTriggerUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -5396,8 +5627,29 @@ func (s *Store) UpsertAutomationWorkflow(ctx context.Context, rr ...*automationT return } - if err = s.Exec(ctx, automationWorkflowUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, automationWorkflowUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, automationWorkflowInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, automationWorkflowUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -6000,8 +6252,29 @@ func (s *Store) UpsertComposeAttachment(ctx context.Context, rr ...*composeType. return } - if err = s.Exec(ctx, composeAttachmentUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, composeAttachmentUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, composeAttachmentInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, composeAttachmentUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -6535,8 +6808,29 @@ func (s *Store) UpsertComposeChart(ctx context.Context, rr ...*composeType.Chart return } - if err = s.Exec(ctx, composeChartUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, composeChartUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, composeChartInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, composeChartUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -7111,8 +7405,29 @@ func (s *Store) UpsertComposeModule(ctx context.Context, rr ...*composeType.Modu return } - if err = s.Exec(ctx, composeModuleUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, composeModuleUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, composeModuleInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, composeModuleUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -7761,8 +8076,29 @@ func (s *Store) UpsertComposeModuleField(ctx context.Context, rr ...*composeType return } - if err = s.Exec(ctx, composeModuleFieldUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, composeModuleFieldUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, composeModuleFieldInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, composeModuleFieldUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -8155,8 +8491,29 @@ func (s *Store) UpsertComposeNamespace(ctx context.Context, rr ...*composeType.N return } - if err = s.Exec(ctx, composeNamespaceUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, composeNamespaceUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, composeNamespaceInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, composeNamespaceUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -8756,8 +9113,29 @@ func (s *Store) UpsertComposePage(ctx context.Context, rr ...*composeType.Page) return } - if err = s.Exec(ctx, composePageUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, composePageUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, composePageInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, composePageUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -9381,8 +9759,29 @@ func (s *Store) UpsertCredential(ctx context.Context, rr ...*systemType.Credenti return } - if err = s.Exec(ctx, credentialUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, credentialUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, credentialInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, credentialUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -9699,8 +10098,29 @@ func (s *Store) UpsertDalConnection(ctx context.Context, rr ...*systemType.DalCo return } - if err = s.Exec(ctx, dalConnectionUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, dalConnectionUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, dalConnectionInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, dalConnectionUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -10303,8 +10723,29 @@ func (s *Store) UpsertDalSensitivityLevel(ctx context.Context, rr ...*systemType return } - if err = s.Exec(ctx, dalSensitivityLevelUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, dalSensitivityLevelUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, dalSensitivityLevelInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, dalSensitivityLevelUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -10837,8 +11278,29 @@ func (s *Store) UpsertDataPrivacyRequest(ctx context.Context, rr ...*systemType. return } - if err = s.Exec(ctx, dataPrivacyRequestUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, dataPrivacyRequestUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, dataPrivacyRequestInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, dataPrivacyRequestUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -11378,8 +11840,29 @@ func (s *Store) UpsertDataPrivacyRequestComment(ctx context.Context, rr ...*syst return } - if err = s.Exec(ctx, dataPrivacyRequestCommentUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, dataPrivacyRequestCommentUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, dataPrivacyRequestCommentInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, dataPrivacyRequestCommentUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -11863,8 +12346,29 @@ func (s *Store) UpsertFederationExposedModule(ctx context.Context, rr ...*federa return } - if err = s.Exec(ctx, federationExposedModuleUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, federationExposedModuleUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, federationExposedModuleInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, federationExposedModuleUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -12401,8 +12905,29 @@ func (s *Store) UpsertFederationModuleMapping(ctx context.Context, rr ...*federa return } - if err = s.Exec(ctx, federationModuleMappingUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, federationModuleMappingUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, federationModuleMappingInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, federationModuleMappingUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -12959,8 +13484,29 @@ func (s *Store) UpsertFederationNode(ctx context.Context, rr ...*federationType. return } - if err = s.Exec(ctx, federationNodeUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, federationNodeUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, federationNodeInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, federationNodeUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -13379,8 +13925,29 @@ func (s *Store) UpsertFederationNodeSync(ctx context.Context, rr ...*federationT return } - if err = s.Exec(ctx, federationNodeSyncUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, federationNodeSyncUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, federationNodeSyncInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, federationNodeSyncUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -13956,8 +14523,29 @@ func (s *Store) UpsertFederationSharedModule(ctx context.Context, rr ...*federat return } - if err = s.Exec(ctx, federationSharedModuleUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, federationSharedModuleUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, federationSharedModuleInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, federationSharedModuleUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -14498,8 +15086,29 @@ func (s *Store) UpsertFlag(ctx context.Context, rr ...*flagType.Flag) (err error return } - if err = s.Exec(ctx, flagUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, flagUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, flagInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, flagUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -14826,8 +15435,29 @@ func (s *Store) UpsertLabel(ctx context.Context, rr ...*labelsType.Label) (err e return } - if err = s.Exec(ctx, labelUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, labelUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, labelInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, labelUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -15143,8 +15773,29 @@ func (s *Store) UpsertQueue(ctx context.Context, rr ...*systemType.Queue) (err e return } - if err = s.Exec(ctx, queueUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, queueUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, queueInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, queueUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -15714,8 +16365,29 @@ func (s *Store) UpsertQueueMessage(ctx context.Context, rr ...*systemType.QueueM return } - if err = s.Exec(ctx, queueMessageUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, queueMessageUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, queueMessageInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, queueMessageUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -16184,8 +16856,29 @@ func (s *Store) UpsertRbacRule(ctx context.Context, rr ...*rbacType.Rule) (err e return } - if err = s.Exec(ctx, rbacRuleUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, rbacRuleUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, rbacRuleInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, rbacRuleUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -16459,8 +17152,29 @@ func (s *Store) UpsertReminder(ctx context.Context, rr ...*systemType.Reminder) return } - if err = s.Exec(ctx, reminderUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, reminderUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, reminderInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, reminderUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -16999,8 +17713,29 @@ func (s *Store) UpsertReport(ctx context.Context, rr ...*systemType.Report) (err return } - if err = s.Exec(ctx, reportUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, reportUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, reportInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, reportUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -17600,8 +18335,29 @@ func (s *Store) UpsertResourceActivity(ctx context.Context, rr ...*discoveryType return } - if err = s.Exec(ctx, resourceActivityUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, resourceActivityUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, resourceActivityInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, resourceActivityUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -17859,8 +18615,29 @@ func (s *Store) UpsertResourceTranslation(ctx context.Context, rr ...*systemType return } - if err = s.Exec(ctx, resourceTranslationUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, resourceTranslationUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, resourceTranslationInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, resourceTranslationUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -18373,8 +19150,29 @@ func (s *Store) UpsertRole(ctx context.Context, rr ...*systemType.Role) (err err return } - if err = s.Exec(ctx, roleUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, roleUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, roleInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, roleUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -19051,8 +19849,29 @@ func (s *Store) UpsertRoleMember(ctx context.Context, rr ...*systemType.RoleMemb return } - if err = s.Exec(ctx, roleMemberUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, roleMemberUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, roleMemberInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, roleMemberUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -19318,8 +20137,29 @@ func (s *Store) UpsertSettingValue(ctx context.Context, rr ...*systemType.Settin return } - if err = s.Exec(ctx, settingValueUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, settingValueUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, settingValueInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, settingValueUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -19629,8 +20469,29 @@ func (s *Store) UpsertTemplate(ctx context.Context, rr ...*systemType.Template) return } - if err = s.Exec(ctx, templateUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, templateUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, templateInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, templateUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } @@ -20243,8 +21104,29 @@ func (s *Store) UpsertUser(ctx context.Context, rr ...*systemType.User) (err err return } - if err = s.Exec(ctx, userUpsertQuery(s.Dialect.GOQU(), rr[i])); err != nil { - return + // @todo this solution is ok for now but could be problematic when we start + // batching together DB operations. + if s.Dialect.Nuances().TwoStepUpsert { + var rsp sql.Result + rsp, err = s.ExecR(ctx, userUpdateQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + if c, err := rsp.RowsAffected(); err != nil { + return err + } else if c > 0 { + continue + } + + err = s.Exec(ctx, userInsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } + } else { + err = s.Exec(ctx, userUpsertQuery(s.Dialect.GOQU(), rr[i])) + if err != nil { + return + } } } diff --git a/server/store/adapters/rdbms/rdbms_store.go b/server/store/adapters/rdbms/rdbms_store.go index fe0288b17..dc75b78f5 100644 --- a/server/store/adapters/rdbms/rdbms_store.go +++ b/server/store/adapters/rdbms/rdbms_store.go @@ -114,17 +114,28 @@ func (s Store) Healthcheck(ctx context.Context) error { return s.Ping(ctx) } +// Exec executes the SQL and drops the result func (s Store) Exec(ctx context.Context, q sqlizer) error { + _, err := s.exec(ctx, q) + return err +} + +// ExecR executes the SQL and returns the result +func (s Store) ExecR(ctx context.Context, q sqlizer) (rs sql.Result, _ error) { + return s.exec(ctx, q) +} + +func (s Store) exec(ctx context.Context, q sqlizer) (rs sql.Result, _ error) { var ( query, args, err = q.ToSQL() ) if err != nil { - return fmt.Errorf("could not build query: %w", err) + return rs, fmt.Errorf("could not build query: %w", err) } - _, err = s.DB.ExecContext(ctx, query, args...) - return store.HandleError(err, s.ErrorHandler) + rs, err = s.DB.ExecContext(ctx, query, args...) + return rs, store.HandleError(err, s.ErrorHandler) } func (s Store) Query(ctx context.Context, q sqlizer) (*sql.Rows, error) {