package plg_backend_psql import ( "context" "database/sql" "encoding/json" "fmt" "io" "slices" "strings" . "github.com/mickael-kerjean/filestash/server/common" ) func (this PSQL) Save(path string, file io.Reader) error { defer this.Close() l, err := getPath(path) if err != nil { return err } columns, key, err := processTable(this.ctx, this.db, l.table) if err != nil { return err } f := map[string]FormElement{} if err := json.NewDecoder(file).Decode(&f); err != nil { return err } tx, err := this.db.BeginTx(this.ctx, nil) if err != nil { return err } defer tx.Rollback() rows, err := tx.QueryContext(this.ctx, `SELECT * FROM "`+l.table+`" WHERE "`+key+`" = $1`, l.row) if err != nil { return err } i := 0 dbvals := make([]any, len(columns)) for rows.Next() { currentPtrs := make([]any, len(columns)) for i := range dbvals { currentPtrs[i] = &dbvals[i] } if serr := rows.Scan(currentPtrs...); serr != nil { rows.Close() err = serr break } else if i >= 1 { err = ErrNotValid break } i += 1 } rows.Close() if i == 0 { err = _createRow(tx, this.ctx, l.table, columns, f) } if err == nil && i == 1 { err = _updateRow(tx, this.ctx, l.table, columns, f, key, l.row, dbvals) } if err != nil { return err } return tx.Commit() } func _createRow(tx *sql.Tx, ctx context.Context, table string, columns []Column, f map[string]FormElement) error { colNames := []string{} placeholders := []string{} values := []interface{}{} paramIndex := 1 for _, col := range columns { if formEl, exists := f[col.Name]; exists { if slices.Contains(col.Constraint, "PRIMARY KEY") && col.Default { continue } colNames = append(colNames, `"`+col.Name+`"`) placeholders = append(placeholders, fmt.Sprintf("$%d", paramIndex)) values = append(values, formEl.Value) paramIndex++ } } if len(colNames) == 0 { return ErrNotValid } _, err := tx.ExecContext( ctx, `INSERT INTO "`+table+`" (`+strings.Join(colNames, ", ")+`) VALUES (`+strings.Join(placeholders, ", ")+`)`, values..., ) return err } func _updateRow(tx *sql.Tx, ctx context.Context, table string, columns []Column, f map[string]FormElement, keyName string, keyValue any, dbvals []any) error { for i, col := range columns { dbval := convertFromDB(dbvals[i]) formval, ok := f[col.Name] if !ok || formval.Value == dbval { continue } if _, err := tx.ExecContext( ctx, `UPDATE "`+table+`" SET "`+col.Name+`" = $1 WHERE "`+keyName+`" = $2`, formval.Value, keyValue, ); err != nil { return err } } return nil }