@@ -816,32 +816,60 @@ func (u *CreateSpec) SetField(column string, t field.Type, value driver.Value) {
816816// CreateNode applies the CreateSpec on the graph. The operation creates a new
817817// record in the database, and connects it to other nodes specified in spec.Edges.
818818func CreateNode (ctx context.Context , drv dialect.Driver , spec * CreateSpec ) error {
819- op := func (ctx context.Context , d dialect.Driver ) error {
820- gr := graph {tx : d , builder : sql .Dialect (drv .Dialect ())}
821- cr := & creator {CreateSpec : spec , graph : gr }
822- return cr .node (ctx , d )
823- }
824- return execWithRetryTx (ctx , drv , op , spec .RetryConfig .Options )
819+ return execWithRetryTx (
820+ ctx ,
821+ drv ,
822+ spec .RetryConfig .Options ,
823+ func (ctx context.Context , d dialect.Driver ) error {
824+ gr := graph {tx : d , builder : sql .Dialect (drv .Dialect ())}
825+ cr := & creator {CreateSpec : spec , graph : gr }
826+ return cr .node (ctx , d )
827+ },
828+ )
825829}
826830
827831// BatchCreate applies the BatchCreateSpec on the graph.
828832func BatchCreate (ctx context.Context , drv dialect.Driver , spec * BatchCreateSpec ) error {
829- op := func (ctx context.Context , d dialect.Driver ) error {
830- gr := graph {tx : d , builder : sql .Dialect (drv .Dialect ())}
831- cr := & batchCreator {BatchCreateSpec : spec , graph : gr }
832- return cr .nodes (ctx , d )
833- }
834- return execWithRetryTx (ctx , drv , op , spec .RetryConfig .Options )
833+ return execWithRetryTx (
834+ ctx ,
835+ drv ,
836+ spec .RetryConfig .Options ,
837+ func (ctx context.Context , d dialect.Driver ) error {
838+ gr := graph {tx : d , builder : sql .Dialect (drv .Dialect ())}
839+ cr := & batchCreator {BatchCreateSpec : spec , graph : gr }
840+ return cr .nodes (ctx , d )
841+ },
842+ )
835843}
836844
837- // execWithRetryTx executes the operation with retry if available, otherwise executes directly.
838- func execWithRetryTx (ctx context.Context , drv dialect.Driver , op func (context.Context , dialect.Driver ) error , opts []any ) error {
845+ // execWithRetryTx executes the operation with retry
846+ // in a transaction if available, otherwise executes directly.
847+ func execWithRetryTx (
848+ ctx context.Context ,
849+ drv dialect.Driver ,
850+ opts []any ,
851+ op func (context.Context , dialect.Driver ) error ,
852+ ) error {
839853 if retry := sql .GetRetryExecutor (drv ); retry != nil {
840854 return retry .DoTx (ctx , op , opts ... )
841855 }
842856 return op (ctx , drv )
843857}
844858
859+ // execWithRetry executes the operation with retry if available, otherwise executes directly.
860+ // Use this for read-only operations that don't require a transaction.
861+ func execWithRetry (
862+ ctx context.Context ,
863+ drv dialect.Driver ,
864+ opts []any ,
865+ op func (context.Context , dialect.Driver ) error ,
866+ ) error {
867+ if retry := sql .GetRetryExecutor (drv ); retry != nil {
868+ return retry .Do (ctx , op , opts ... )
869+ }
870+ return op (ctx , drv )
871+ }
872+
845873type (
846874 // EdgeMut defines edge mutations.
847875 EdgeMut struct {
@@ -924,22 +952,23 @@ func (u *UpdateSpec) ClearField(column string, t field.Type) {
924952
925953// UpdateNode applies the UpdateSpec on one node in the graph.
926954func UpdateNode (ctx context.Context , drv dialect.Driver , spec * UpdateSpec ) error {
927- op := func (ctx context.Context , d dialect.Driver ) error {
928- tx , err := d .Tx (ctx )
929- if err != nil {
930- return err
931- }
932- gr := graph {tx : tx , builder : sql .Dialect (drv .Dialect ())}
933- cr := & updater {UpdateSpec : spec , graph : gr }
934- if err := cr .node (ctx , tx ); err != nil {
935- return rollback (tx , err )
936- }
937- return tx .Commit ()
938- }
939- if retry := sql .GetRetryExecutor (drv ); retry != nil {
940- return retry .DoTx (ctx , op , spec .RetryConfig .Options ... )
941- }
942- return op (ctx , drv )
955+ return execWithRetryTx (
956+ ctx ,
957+ drv ,
958+ spec .RetryConfig .Options ,
959+ func (ctx context.Context , d dialect.Driver ) error {
960+ tx , err := d .Tx (ctx )
961+ if err != nil {
962+ return err
963+ }
964+ gr := graph {tx : tx , builder : sql .Dialect (drv .Dialect ())}
965+ cr := & updater {UpdateSpec : spec , graph : gr }
966+ if err := cr .node (ctx , tx ); err != nil {
967+ return rollback (tx , err )
968+ }
969+ return tx .Commit ()
970+ },
971+ )
943972}
944973
945974// UpdateNodes applies the UpdateSpec on a set of nodes in the graph.
@@ -955,13 +984,7 @@ func UpdateNodes(ctx context.Context, drv dialect.Driver, spec *UpdateSpec) (int
955984 affected = n
956985 return nil
957986 }
958- if retry := sql .GetRetryExecutor (drv ); retry != nil {
959- if err := retry .DoTx (ctx , op , spec .RetryConfig .Options ... ); err != nil {
960- return 0 , err
961- }
962- return affected , nil
963- }
964- if err := op (ctx , drv ); err != nil {
987+ if err := execWithRetryTx (ctx , drv , spec .RetryConfig .Options , op ); err != nil {
965988 return 0 , err
966989 }
967990 return affected , nil
@@ -978,6 +1001,12 @@ func (e *NotFoundError) Error() string {
9781001 return fmt .Sprintf ("record with id %v not found in table %s" , e .id , e .table )
9791002}
9801003
1004+ // IsNotFound returns true if the error is a NotFoundError or wraps one.
1005+ func IsNotFound (err error ) bool {
1006+ var e * NotFoundError
1007+ return errors .As (err , & e )
1008+ }
1009+
9811010// DeleteSpec holds the information for delete one
9821011// or more nodes in the graph.
9831012type DeleteSpec struct {
@@ -1031,13 +1060,7 @@ func DeleteNodes(ctx context.Context, drv dialect.Driver, spec *DeleteSpec) (int
10311060 affected = int (n )
10321061 return nil
10331062 }
1034- if retry := sql .GetRetryExecutor (drv ); retry != nil {
1035- if err := retry .DoTx (ctx , op , spec .RetryConfig .Options ... ); err != nil {
1036- return 0 , err
1037- }
1038- return affected , nil
1039- }
1040- if err := op (ctx , drv ); err != nil {
1063+ if err := execWithRetryTx (ctx , drv , spec .RetryConfig .Options , op ); err != nil {
10411064 return 0 , err
10421065 }
10431066 return affected , nil
@@ -1075,15 +1098,16 @@ func NewQuerySpec(table string, columns []string, id *FieldSpec) *QuerySpec {
10751098
10761099// QueryNodes queries the nodes in the graph query and scans them to the given values.
10771100func QueryNodes (ctx context.Context , drv dialect.Driver , spec * QuerySpec ) error {
1078- op := func (ctx context.Context , d dialect.Driver ) error {
1079- builder := sql .Dialect (drv .Dialect ())
1080- qr := & query {graph : graph {builder : builder }, QuerySpec : spec }
1081- return qr .nodes (ctx , d )
1082- }
1083- if retry := sql .GetRetryExecutor (drv ); retry != nil {
1084- return retry .Do (ctx , op , spec .RetryConfig .Options ... )
1085- }
1086- return op (ctx , drv )
1101+ return execWithRetry (
1102+ ctx ,
1103+ drv ,
1104+ spec .RetryConfig .Options ,
1105+ func (ctx context.Context , d dialect.Driver ) error {
1106+ builder := sql .Dialect (drv .Dialect ())
1107+ qr := & query {graph : graph {builder : builder }, QuerySpec : spec }
1108+ return qr .nodes (ctx , d )
1109+ },
1110+ )
10871111}
10881112
10891113// CountNodes counts the nodes in the given graph query.
@@ -1099,13 +1123,7 @@ func CountNodes(ctx context.Context, drv dialect.Driver, spec *QuerySpec) (int,
10991123 count = n
11001124 return nil
11011125 }
1102- if retry := sql .GetRetryExecutor (drv ); retry != nil {
1103- if err := retry .Do (ctx , op , spec .RetryConfig .Options ... ); err != nil {
1104- return 0 , err
1105- }
1106- return count , nil
1107- }
1108- if err := op (ctx , drv ); err != nil {
1126+ if err := execWithRetry (ctx , drv , spec .RetryConfig .Options , op ); err != nil {
11091127 return 0 , err
11101128 }
11111129 return count , nil
@@ -1114,43 +1132,51 @@ func CountNodes(ctx context.Context, drv dialect.Driver, spec *QuerySpec) (int,
11141132// EdgeQuerySpec holds the information for querying
11151133// edges in the graph.
11161134type EdgeQuerySpec struct {
1117- Edge * EdgeSpec
1118- Predicate func (* sql.Selector )
1119- ScanValues func () [2 ]any
1120- Assign func (out , in any ) error
1135+ Edge * EdgeSpec
1136+ Predicate func (* sql.Selector )
1137+ ScanValues func () [2 ]any
1138+ Assign func (out , in any ) error
1139+ RetryConfig sql.RetryConfig
11211140}
11221141
11231142// QueryEdges queries the edges in the graph and scans the result with the given dest function.
11241143func QueryEdges (ctx context.Context , drv dialect.Driver , spec * EdgeQuerySpec ) error {
11251144 if len (spec .Edge .Columns ) != 2 {
11261145 return fmt .Errorf ("sqlgraph: edge query requires 2 columns (out, in)" )
11271146 }
1128- out , in := spec .Edge .Columns [0 ], spec .Edge .Columns [1 ]
1129- if spec .Edge .Inverse {
1130- out , in = in , out
1131- }
1132- selector := sql .Dialect (drv .Dialect ()).
1133- Select (out , in ).
1134- From (sql .Table (spec .Edge .Table ).Schema (spec .Edge .Schema ))
1135- if p := spec .Predicate ; p != nil {
1136- p (selector )
1137- }
1138- rows := & sql.Rows {}
1139- query , args := selector .Query ()
1140- if err := drv .Query (ctx , query , args , rows ); err != nil {
1141- return err
1142- }
1143- defer rows .Close ()
1144- for rows .Next () {
1145- values := spec .ScanValues ()
1146- if err := rows .Scan (values [0 ], values [1 ]); err != nil {
1147- return err
1148- }
1149- if err := spec .Assign (values [0 ], values [1 ]); err != nil {
1150- return err
1151- }
1152- }
1153- return rows .Err ()
1147+ return execWithRetry (
1148+ ctx ,
1149+ drv ,
1150+ spec .RetryConfig .Options ,
1151+ func (ctx context.Context , d dialect.Driver ) error {
1152+ out , in := spec .Edge .Columns [0 ], spec .Edge .Columns [1 ]
1153+ if spec .Edge .Inverse {
1154+ out , in = in , out
1155+ }
1156+ selector := sql .Dialect (drv .Dialect ()).
1157+ Select (out , in ).
1158+ From (sql .Table (spec .Edge .Table ).Schema (spec .Edge .Schema ))
1159+ if p := spec .Predicate ; p != nil {
1160+ p (selector )
1161+ }
1162+ rows := & sql.Rows {}
1163+ query , args := selector .Query ()
1164+ if err := d .Query (ctx , query , args , rows ); err != nil {
1165+ return err
1166+ }
1167+ defer rows .Close ()
1168+ for rows .Next () {
1169+ values := spec .ScanValues ()
1170+ if err := rows .Scan (values [0 ], values [1 ]); err != nil {
1171+ return err
1172+ }
1173+ if err := spec .Assign (values [0 ], values [1 ]); err != nil {
1174+ return err
1175+ }
1176+ }
1177+ return rows .Err ()
1178+ },
1179+ )
11541180}
11551181
11561182type query struct {
@@ -1439,14 +1465,14 @@ func (u *updater) updateTable(ctx context.Context, stmt *sql.UpdateBuilder) (int
14391465 if stmt .Empty () {
14401466 return 0 , nil
14411467 }
1442- var (
1443- res sql. Result
1444- query , args = stmt . Query ()
1445- )
1446- if err := u . tx . Exec ( ctx , query , args , & res ); err != nil {
1447- return 0 , err
1468+ // Determine the ID column for RETURNING (needed for YDB).
1469+ var idColumn string
1470+ if u . Node . ID != nil {
1471+ idColumn = u . Node . ID . Column
1472+ } else if len ( u . Node . CompositeID ) > 0 {
1473+ idColumn = u . Node . CompositeID [ 0 ]. Column
14481474 }
1449- affected , err := res . RowsAffected ( )
1475+ affected , err := execUpdate ( ctx , u . tx , stmt , idColumn )
14501476 if err != nil {
14511477 return 0 , err
14521478 }
0 commit comments