@@ -4,8 +4,10 @@ import (
44 "context"
55 "time"
66
7+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Formats"
78 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table"
89
10+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
911 "github.com/ydb-platform/ydb-go-sdk/v3/internal/closer"
1012 "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
1113 "github.com/ydb-platform/ydb-go-sdk/v3/internal/tx"
@@ -68,6 +70,12 @@ type Client interface {
6870 // If op TxOperation return non nil - transaction will be rollback
6971 // Warning: if context without deadline or cancellation func than DoTx can run indefinitely
7072 DoTx (ctx context.Context , op TxOperation , opts ... Option ) error
73+
74+ // BulkUpsert upserts a batch of rows non-transactionally.
75+ //
76+ // Returns success only when all rows were successfully upserted. In case of an error some rows might
77+ // be upserted and some might not.
78+ BulkUpsert (ctx context.Context , table string , data BulkUpsertData , opts ... Option ) error
7179}
7280
7381type SessionStatus = string
@@ -179,6 +187,7 @@ type Session interface {
179187 opts ... options.ExecuteScanQueryOption ,
180188 ) (_ result.StreamResult , err error )
181189
190+ // Deprecated: use Client instance instead.
182191 BulkUpsert (
183192 ctx context.Context ,
184193 table string ,
@@ -578,3 +587,205 @@ func (opt traceOption) ApplyTableOption(opts *Options) {
578587func WithTrace (t trace.Table ) traceOption { //nolint:gocritic
579588 return traceOption {t : & t }
580589}
590+
591+ type (
592+ BulkUpsertRequest Ydb_Table.BulkUpsertRequest
593+ )
594+
595+ type BulkUpsertData interface {
596+ ApplyBulkUpsertRequest (a * allocator.Allocator , req * BulkUpsertRequest ) error
597+ }
598+
599+ type bulkUpsertRows struct {
600+ Rows value.Value
601+ }
602+
603+ func (data bulkUpsertRows ) ApplyBulkUpsertRequest (a * allocator.Allocator , req * BulkUpsertRequest ) error {
604+ req .Rows = value .ToYDB (data .Rows , a )
605+
606+ return nil
607+ }
608+
609+ func NewBulkUpsertRows (rows value.Value ) bulkUpsertRows {
610+ return bulkUpsertRows {
611+ Rows : rows ,
612+ }
613+ }
614+
615+ type bulkUpsertCsv struct {
616+ Data []byte
617+ Options []CsvFormatOption
618+ }
619+
620+ type CsvFormatOption interface {
621+ ApplyCsvFormatOption (req * BulkUpsertRequest ) (err error )
622+ }
623+
624+ func (data bulkUpsertCsv ) ApplyBulkUpsertRequest (a * allocator.Allocator , req * BulkUpsertRequest ) error {
625+ req .Data = data .Data
626+
627+ var err error
628+ for _ , opt := range data .Options {
629+ if opt != nil {
630+ err = opt .ApplyCsvFormatOption (req )
631+ if err != nil {
632+ return err
633+ }
634+ }
635+ }
636+
637+ return err
638+ }
639+
640+ func NewBulkUpsertCsv (data []byte , opts ... CsvFormatOption ) bulkUpsertCsv {
641+ return bulkUpsertCsv {
642+ Data : data ,
643+ Options : opts ,
644+ }
645+ }
646+
647+ func ensureCsvDataFormatSettings (req * BulkUpsertRequest ) (format * Ydb_Formats.CsvSettings ) {
648+ if settings , ok := req .DataFormat .(* Ydb_Table.BulkUpsertRequest_CsvSettings ); ok {
649+ if settings .CsvSettings == nil {
650+ settings .CsvSettings = & Ydb_Formats.CsvSettings {}
651+ }
652+
653+ return settings .CsvSettings
654+ }
655+
656+ req .DataFormat = & Ydb_Table.BulkUpsertRequest_CsvSettings {
657+ CsvSettings : & Ydb_Formats.CsvSettings {},
658+ }
659+
660+ settings , ok := req .DataFormat .(* Ydb_Table.BulkUpsertRequest_CsvSettings )
661+ if ! ok {
662+ return nil
663+ }
664+
665+ return settings .CsvSettings
666+ }
667+
668+ type csvHeaderOption struct {}
669+
670+ func (opt * csvHeaderOption ) ApplyCsvFormatOption (req * BulkUpsertRequest ) error {
671+ ensureCsvDataFormatSettings (req ).Header = true
672+
673+ return nil
674+ }
675+
676+ // First not skipped line is a CSV header (list of column names).
677+ func WithCsvHeader () CsvFormatOption {
678+ return & csvHeaderOption {}
679+ }
680+
681+ type csvNullValueOption struct {
682+ Value []byte
683+ }
684+
685+ func (opt * csvNullValueOption ) ApplyCsvFormatOption (req * BulkUpsertRequest ) error {
686+ ensureCsvDataFormatSettings (req ).NullValue = opt .Value
687+
688+ return nil
689+ }
690+
691+ // String value that would be interpreted as NULL.
692+ func WithCsvNullValue (value []byte ) CsvFormatOption {
693+ return & csvNullValueOption {value }
694+ }
695+
696+ type csvDelimiterOption struct {
697+ Value []byte
698+ }
699+
700+ func (opt * csvDelimiterOption ) ApplyCsvFormatOption (req * BulkUpsertRequest ) error {
701+ ensureCsvDataFormatSettings (req ).Delimiter = opt .Value
702+
703+ return nil
704+ }
705+
706+ // Fields delimiter in CSV file. It's "," if not set.
707+ func WithCsvDelimiter (value []byte ) CsvFormatOption {
708+ return & csvDelimiterOption {value }
709+ }
710+
711+ type csvSkipRowsOption struct {
712+ Count uint32
713+ }
714+
715+ func (opt * csvSkipRowsOption ) ApplyCsvFormatOption (req * BulkUpsertRequest ) error {
716+ ensureCsvDataFormatSettings (req ).SkipRows = opt .Count
717+
718+ return nil
719+ }
720+
721+ // Number of rows to skip before CSV data. It should be present only in the first upsert of CSV file.
722+ func WithCsvSkipRows (count uint32 ) CsvFormatOption {
723+ return & csvSkipRowsOption {count }
724+ }
725+
726+ type bulkUpsertArrow struct {
727+ Data []byte
728+ Options []ArrowFormatOption
729+ }
730+
731+ type ArrowFormatOption interface {
732+ ApplyArrowFormatOption (req * BulkUpsertRequest ) (err error )
733+ }
734+
735+ func (data bulkUpsertArrow ) ApplyBulkUpsertRequest (a * allocator.Allocator , req * BulkUpsertRequest ) error {
736+ req .Data = data .Data
737+
738+ var err error
739+ for _ , opt := range data .Options {
740+ if opt != nil {
741+ err = opt .ApplyArrowFormatOption (req )
742+ if err != nil {
743+ return err
744+ }
745+ }
746+ }
747+
748+ return err
749+ }
750+
751+ func NewBulkUpsertArrow (data []byte , opts ... ArrowFormatOption ) bulkUpsertArrow {
752+ return bulkUpsertArrow {
753+ Data : data ,
754+ Options : opts ,
755+ }
756+ }
757+
758+ func ensureArrowDataFormatSettings (req * BulkUpsertRequest ) (format * Ydb_Formats.ArrowBatchSettings ) {
759+ if settings , ok := req .DataFormat .(* Ydb_Table.BulkUpsertRequest_ArrowBatchSettings ); ok {
760+ if settings .ArrowBatchSettings == nil {
761+ settings .ArrowBatchSettings = & Ydb_Formats.ArrowBatchSettings {}
762+ }
763+
764+ return settings .ArrowBatchSettings
765+ }
766+
767+ req .DataFormat = & Ydb_Table.BulkUpsertRequest_ArrowBatchSettings {
768+ ArrowBatchSettings : & Ydb_Formats.ArrowBatchSettings {},
769+ }
770+
771+ settings , ok := req .DataFormat .(* Ydb_Table.BulkUpsertRequest_ArrowBatchSettings )
772+ if ! ok {
773+ return nil
774+ }
775+
776+ return settings .ArrowBatchSettings
777+ }
778+
779+ type arrowSchemaOption struct {
780+ Schema []byte
781+ }
782+
783+ func (opt * arrowSchemaOption ) ApplyArrowFormatOption (req * BulkUpsertRequest ) error {
784+ ensureArrowDataFormatSettings (req ).Schema = opt .Schema
785+
786+ return nil
787+ }
788+
789+ func WithArrowSchema (schema []byte ) ArrowFormatOption {
790+ return & arrowSchemaOption {schema }
791+ }
0 commit comments