1
1
package sqlx
2
2
3
3
import (
4
+ "context"
4
5
"database/sql"
5
6
"database/sql/driver"
6
7
"errors"
@@ -86,6 +87,18 @@ type Execer interface {
86
87
Exec (query string , args ... interface {}) (sql.Result , error )
87
88
}
88
89
90
+ // QueryIn is an interface used by InGet and InSelect
91
+ type QueryIn interface {
92
+ Queryer
93
+ In (query string , args ... interface {}) (string , []interface {}, error )
94
+ }
95
+
96
+ // ExecIn is an interface used by MustInExec and InExec
97
+ type ExecIn interface {
98
+ Execer
99
+ In (query string , args ... interface {}) (string , []interface {}, error )
100
+ }
101
+
89
102
// Binder is an interface for something which can bind queries (Tx, DB)
90
103
type binder interface {
91
104
DriverName () string
@@ -343,6 +356,110 @@ func (db *DB) Beginx() (*Tx, error) {
343
356
return & Tx {Tx : tx , driverName : db .driverName , unsafe : db .unsafe , Mapper : db .Mapper }, err
344
357
}
345
358
359
+ // Begin starts a transaction and do the given handle. The default isolation level
360
+ // is dependent on the driver.
361
+ //
362
+ // With uses context.Background internally; to specify the context, use
363
+ // With Tx.
364
+ func (db * DB ) With (handle func (tx * sql.Tx ) error ) error {
365
+ tx , err := db .Begin ()
366
+ if err != nil {
367
+ return err
368
+ }
369
+ defer tx .Rollback ()
370
+ if err = handle (tx ); err != nil {
371
+ return err
372
+ }
373
+ return tx .Commit ()
374
+ }
375
+
376
+ // BeginTx starts a transaction and do the given handle.
377
+ //
378
+ // The provided context is used until the transaction is committed or rolled back.
379
+ // If the context is canceled, the sql package will roll back
380
+ // the transaction. Tx.Commit will return an error if the context provided to
381
+ // BeginTx is canceled.
382
+ //
383
+ // The provided TxOptions is optional and may be nil if defaults should be used.
384
+ // If a non-default isolation level is used that the driver doesn't support,
385
+ // an error will be returned.
386
+ func (db * DB ) WithTx (ctx context.Context , opts * sql.TxOptions , handle func (tx * sql.Tx ) error ) error {
387
+ tx , err := db .BeginTx (ctx , opts )
388
+ if err != nil {
389
+ return err
390
+ }
391
+ defer tx .Rollback ()
392
+ if err = handle (tx ); err != nil {
393
+ return err
394
+ }
395
+ return tx .Commit ()
396
+ }
397
+
398
+ // Withx begins a transaction and returns an *sqlx.Tx instead of an *sql.Tx and do the given handle.
399
+ func (db * DB ) Withx (handle func (tx * Tx ) error ) error {
400
+ tx , err := db .Beginx ()
401
+ if err != nil {
402
+ return err
403
+ }
404
+ defer tx .Rollback ()
405
+ if err = handle (tx ); err != nil {
406
+ return err
407
+ }
408
+ return tx .Commit ()
409
+ }
410
+
411
+ // WithTxx begins a transaction and returns an *sqlx.Tx instead of an
412
+ // *sql.Tx and do the give handle.
413
+ //
414
+ // The provided context is used until the transaction is committed or rolled
415
+ // back. If the context is canceled, the sql package will roll back the
416
+ // transaction. Tx.Commit will return an error if the context provided to
417
+ // BeginxContext is canceled.
418
+ func (db * DB ) WithTxx (ctx context.Context , opts * sql.TxOptions , handle func (tx * Tx ) error ) error {
419
+ tx , err := db .BeginTxx (ctx , opts )
420
+ if err != nil {
421
+ return err
422
+ }
423
+ defer tx .Rollback ()
424
+ if err = handle (tx ); err != nil {
425
+ return err
426
+ }
427
+ return tx .Commit ()
428
+ }
429
+
430
+ // In expands slice values in args, returning the modified query string
431
+ // and a new arg list that can be executed by a database. The `query` should
432
+ // use the `?` bindVar. The return value uses had rebinded bindvar type.
433
+ func (db * DB ) In (query string , args ... any ) (string , []any , error ) {
434
+ q , params , err := In (query , args ... )
435
+ if err != nil {
436
+ return "" , nil , err
437
+ }
438
+ return db .Rebind (q ), params , nil
439
+ }
440
+
441
+ // InExec executes a query without returning any rows for in.
442
+ // The args are for any placeholder parameters in the query.
443
+ //
444
+ // InExec uses context.Background internally; to specify the context, use
445
+ // ExecContext.
446
+ func (db * DB ) InExec (query string , args ... any ) (sql.Result , error ) {
447
+ return InExec (db , query , args ... )
448
+ }
449
+
450
+ // InSelect using this DB but for in.
451
+ // Any placeholder parameters are replaced with supplied args.
452
+ func (db * DB ) InSelect (dest any , query string , args ... any ) error {
453
+ return InSelect (db , dest , query , args ... )
454
+ }
455
+
456
+ // InGet using this DB but for in.
457
+ // Any placeholder parameters are replaced with supplied args.
458
+ // An error is returned if the result set is empty.
459
+ func (db * DB ) InGet (dest any , query string , args ... any ) error {
460
+ return InGet (db , dest , query , args ... )
461
+ }
462
+
346
463
// Queryx queries the database and returns an *sqlx.Rows.
347
464
// Any placeholder parameters are replaced with supplied args.
348
465
func (db * DB ) Queryx (query string , args ... interface {}) (* Rows , error ) {
@@ -366,6 +483,12 @@ func (db *DB) MustExec(query string, args ...interface{}) sql.Result {
366
483
return MustExec (db , query , args ... )
367
484
}
368
485
486
+ // MustExec (panic) runs MustExec using this database for in.
487
+ // Any placeholder parameters are replaced with supplied args.
488
+ func (db * DB ) MustInExec (query string , args ... interface {}) sql.Result {
489
+ return MustInExec (db , query , args ... )
490
+ }
491
+
369
492
// Preparex returns an sqlx.Stmt instead of a sql.Stmt
370
493
func (db * DB ) Preparex (query string ) (* Stmt , error ) {
371
494
return Preparex (db , query )
@@ -425,6 +548,39 @@ func (tx *Tx) NamedExec(query string, arg interface{}) (sql.Result, error) {
425
548
return NamedExec (tx , query , arg )
426
549
}
427
550
551
+ // In expands slice values in args, returning the modified query string
552
+ // and a new arg list that can be executed by a database. The `query` should
553
+ // use the `?` bindVar. The return value uses had rebinded bindvar type.
554
+ func (tx * Tx ) In (query string , args ... any ) (string , []any , error ) {
555
+ q , params , err := In (query , args ... )
556
+ if err != nil {
557
+ return "" , nil , err
558
+ }
559
+ return tx .Rebind (q ), params , nil
560
+ }
561
+
562
+ // InExec executes a query that doesn't return rows for in.
563
+ // For example: an INSERT and UPDATE.
564
+ //
565
+ // Exec uses context.Background internally; to specify the context, use
566
+ // ExecContext.
567
+ func (tx * Tx ) InExec (query string , args ... any ) (sql.Result , error ) {
568
+ return InExec (tx , query , args ... )
569
+ }
570
+
571
+ // InSelect within a transaction for in.
572
+ // Any placeholder parameters are replaced with supplied args.
573
+ func (tx * Tx ) InSelect (dest any , query string , args ... any ) error {
574
+ return InSelect (tx , dest , query , args ... )
575
+ }
576
+
577
+ // Get within a transaction for in.
578
+ // Any placeholder parameters are replaced with supplied args.
579
+ // An error is returned if the result set is empty.
580
+ func (tx * Tx ) InGet (dest any , query string , args ... any ) error {
581
+ return InGet (tx , dest , query , args ... )
582
+ }
583
+
428
584
// Select within a transaction.
429
585
// Any placeholder parameters are replaced with supplied args.
430
586
func (tx * Tx ) Select (dest interface {}, query string , args ... interface {}) error {
@@ -461,6 +617,12 @@ func (tx *Tx) MustExec(query string, args ...interface{}) sql.Result {
461
617
return MustExec (tx , query , args ... )
462
618
}
463
619
620
+ // MustInExec runs MustExec within a transaction for in.
621
+ // Any placeholder parameters are replaced with supplied args.
622
+ func (tx * Tx ) MustInExec (query string , args ... interface {}) sql.Result {
623
+ return MustInExec (tx , query , args ... )
624
+ }
625
+
464
626
// Preparex a statement within a transaction.
465
627
func (tx * Tx ) Preparex (query string ) (* Stmt , error ) {
466
628
return Preparex (tx , query )
@@ -690,6 +852,39 @@ func Get(q Queryer, dest interface{}, query string, args ...interface{}) error {
690
852
return r .scanAny (dest , false )
691
853
}
692
854
855
+ // InSelect for in scene executes a query using the provided Queryer, and StructScans each row
856
+ // into dest, which must be a slice. If the slice elements are scannable, then
857
+ // the result set must have only one column. Otherwise, StructScan is used.
858
+ // The *sql.Rows are closed automatically.
859
+ // Any placeholder parameters are replaced with supplied args.
860
+ func InSelect (q QueryIn , dest interface {}, query string , args ... interface {}) error {
861
+ newQuery , params , err := q .In (query , args ... )
862
+ if err != nil {
863
+ return err
864
+ }
865
+ rows , err := q .Queryx (newQuery , params ... )
866
+ if err != nil {
867
+ return err
868
+ }
869
+ // if something happens here, we want to make sure the rows are Closed
870
+ defer rows .Close ()
871
+ return scanAll (rows , dest , false )
872
+ }
873
+
874
+ // InGet for in scene does a QueryRow using the provided Queryer, and scans the resulting row
875
+ // to dest. If dest is scannable, the result must only have one column. Otherwise,
876
+ // StructScan is used. Get will return sql.ErrNoRows like row.Scan would.
877
+ // Any placeholder parameters are replaced with supplied args.
878
+ // An error is returned if the result set is empty.
879
+ func InGet (q QueryIn , dest interface {}, query string , args ... interface {}) error {
880
+ newQuery , params , err := q .In (query , args ... )
881
+ if err != nil {
882
+ return err
883
+ }
884
+ r := q .QueryRowx (newQuery , params ... )
885
+ return r .scanAny (dest , false )
886
+ }
887
+
693
888
// LoadFile exec's every statement in a file (as a single call to Exec).
694
889
// LoadFile may return a nil *sql.Result if errors are encountered locating or
695
890
// reading the file at path. LoadFile reads the entire file into memory, so it
@@ -724,6 +919,33 @@ func MustExec(e Execer, query string, args ...interface{}) sql.Result {
724
919
return res
725
920
}
726
921
922
+ // MustInExec for in scene execs the query using e and panics if there was an error.
923
+ // Any placeholder parameters are replaced with supplied args.
924
+ func MustInExec (e ExecIn , query string , args ... interface {}) sql.Result {
925
+ newQuery , params , err := e .In (query , args ... )
926
+ if err != nil {
927
+ panic (err )
928
+ }
929
+ res , err := e .Exec (newQuery , params ... )
930
+ if err != nil {
931
+ panic (err )
932
+ }
933
+ return res
934
+ }
935
+
936
+ // Exec for in scene executes a query that doesn't return rows.
937
+ // For example: an INSERT and UPDATE.
938
+ //
939
+ // Exec uses context.Background internally; to specify the context, use
940
+ // ExecContext.
941
+ func InExec (e ExecIn , query string , args ... interface {}) (sql.Result , error ) {
942
+ newQuery , params , err := e .In (query , args ... )
943
+ if err != nil {
944
+ return nil , err
945
+ }
946
+ return e .Exec (newQuery , params ... )
947
+ }
948
+
727
949
// SliceScan using this Rows.
728
950
func (r * Row ) SliceScan () ([]interface {}, error ) {
729
951
return SliceScan (r )
0 commit comments