package norm import ( "context" "database/sql" "fmt" "strings" ) type insert struct { into string or InsertOr values []struct { col string val any } } type InsertOr int const ( None InsertOr = iota Abort Fail Ignore Replace Rollback ) func (i InsertOr) String() string { switch i { case Abort: return "ABORT" case Fail: return "FAIL" case Ignore: return "IGNORE" case Replace: return "REPLACE" case Rollback: return "ROLLBACK" default: return "" } } func Insert() insert { return insert{} } type InsertOpt func(s *insert) func (s insert) Into(table string) insert { s.into = table return s } func (s insert) Or(option InsertOr) insert { s.or = option return s } func (s insert) Value(column string, arg any) insert { s.values = append(s.values, struct { col string val any }{ column, arg, }) return s } func (s insert) Values(values map[string]any) insert { for column, arg := range values { s = s.Value(column, arg) } return s } func (s insert) Compile() (string, []any, error) { var sql strings.Builder var args []any sql.WriteString("INSERT ") orKw := s.or.String() if orKw != "" { sql.WriteString("OR ") sql.WriteString(s.or.String()) sql.WriteString(" ") } if s.into == "" { return "", nil, fmt.Errorf("INTO clause is required") } sql.WriteString("INTO ") sql.WriteString(s.into) if len(s.values) == 0 { return "", nil, fmt.Errorf("no values supplied") } sql.WriteString(" (") for i, v := range s.values { if i != 0 { sql.WriteString(", ") } sql.WriteString(v.col) args = append(args, v.val) } sql.WriteString(") VALUES (") sql.WriteString(strings.TrimSuffix(strings.Repeat("?, ", len(s.values)), ", ")) sql.WriteString(")") return sql.String(), args, nil } func (s insert) MustCompile() (string, []any) { sql, args, err := s.Compile() if err != nil { panic(err) } return sql, args } func (s insert) Build(p Database) (*sql.Stmt, []any, error) { return Build(s, p) } func (s insert) MustBuild(p Database) (*sql.Stmt, []any) { return MustBuild(s, p) } func (s insert) Exec(p Database) (sql.Result, error) { return Exec(s, p) } func (s insert) ExecContext(ctx context.Context, p Database) (sql.Result, error) { return ExecContext(ctx, s, p) } func (s insert) MustExec(p Database) sql.Result { return MustExec(s, p) } func (s insert) MustExecContext(ctx context.Context, p Database) sql.Result { return MustExecContext(ctx, s, p) }