package stardb import ( "context" "database/sql" "errors" ) // StarTx represents a database transaction type StarTx struct { tx *sql.Tx db *StarDB } // Query executes a query within the transaction func (t *StarTx) Query(query string, args ...interface{}) (*StarRows, error) { return t.query(nil, query, args...) } // QueryContext executes a query with context within the transaction func (t *StarTx) QueryContext(ctx context.Context, query string, args ...interface{}) (*StarRows, error) { return t.query(ctx, query, args...) } // query is the internal query implementation func (t *StarTx) query(ctx context.Context, query string, args ...interface{}) (*StarRows, error) { if err := t.db.Ping(); err != nil { return nil, err } var rows *sql.Rows var err error if ctx == nil { rows, err = t.tx.Query(query, args...) } else { rows, err = t.tx.QueryContext(ctx, query, args...) } if err != nil { return nil, err } starRows := &StarRows{ rows: rows, db: t.db, } if !t.db.ManualScan { err = starRows.parse() } return starRows, err } // Exec executes a query within the transaction func (t *StarTx) Exec(query string, args ...interface{}) (sql.Result, error) { return t.exec(nil, query, args...) } // ExecContext executes a query with context within the transaction func (t *StarTx) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { return t.exec(ctx, query, args...) } // exec is the internal exec implementation func (t *StarTx) exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { if err := t.db.Ping(); err != nil { return nil, err } if ctx == nil { return t.tx.Exec(query, args...) } return t.tx.ExecContext(ctx, query, args...) } // Prepare creates a prepared statement within the transaction func (t *StarTx) Prepare(query string) (*StarStmt, error) { stmt, err := t.tx.Prepare(query) if err != nil { return nil, err } return &StarStmt{stmt: stmt, db: t.db}, nil } // PrepareContext creates a prepared statement with context func (t *StarTx) PrepareContext(ctx context.Context, query string) (*StarStmt, error) { stmt, err := t.tx.PrepareContext(ctx, query) if err != nil { return nil, err } return &StarStmt{stmt: stmt, db: t.db}, nil } // QueryStmt executes a prepared statement query within the transaction func (t *StarTx) QueryStmt(query string, args ...interface{}) (*StarRows, error) { if query == "" { return nil, errors.New("query string cannot be empty") } stmt, err := t.Prepare(query) if err != nil { return nil, err } defer stmt.Close() return stmt.Query(args...) } // QueryStmtContext executes a prepared statement query with context func (t *StarTx) QueryStmtContext(ctx context.Context, query string, args ...interface{}) (*StarRows, error) { if query == "" { return nil, errors.New("query string cannot be empty") } stmt, err := t.PrepareContext(ctx, query) if err != nil { return nil, err } defer stmt.Close() return stmt.QueryContext(ctx, args...) } // ExecStmt executes a prepared statement within the transaction func (t *StarTx) ExecStmt(query string, args ...interface{}) (sql.Result, error) { if query == "" { return nil, errors.New("query string cannot be empty") } stmt, err := t.Prepare(query) if err != nil { return nil, err } defer stmt.Close() return stmt.Exec(args...) } // ExecStmtContext executes a prepared statement with context func (t *StarTx) ExecStmtContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { if query == "" { return nil, errors.New("query string cannot be empty") } stmt, err := t.PrepareContext(ctx, query) if err != nil { return nil, err } defer stmt.Close() return stmt.ExecContext(ctx, args...) } // Commit commits the transaction func (t *StarTx) Commit() error { return t.tx.Commit() } // Rollback rolls back the transaction func (t *StarTx) Rollback() error { return t.tx.Rollback() }