github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/table/table.go (about)

     1  package table
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Formats"
     8  	"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table"
     9  
    10  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
    11  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/closer"
    12  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
    13  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/tx"
    14  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
    15  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
    16  	"github.com/ydb-platform/ydb-go-sdk/v3/retry"
    17  	"github.com/ydb-platform/ydb-go-sdk/v3/retry/budget"
    18  	"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
    19  	"github.com/ydb-platform/ydb-go-sdk/v3/table/result"
    20  	"github.com/ydb-platform/ydb-go-sdk/v3/trace"
    21  )
    22  
    23  // Operation is the interface that holds an operation for retry.
    24  // if Operation returns not nil - operation will retry
    25  // if Operation returns nil - retry loop will break
    26  type Operation func(ctx context.Context, s Session) error
    27  
    28  // TxOperation is the interface that holds an operation for retry.
    29  // if TxOperation returns not nil - operation will retry
    30  // if TxOperation returns nil - retry loop will break
    31  type TxOperation func(ctx context.Context, tx TransactionActor) error
    32  
    33  type ClosableSession interface {
    34  	closer.Closer
    35  
    36  	Session
    37  }
    38  
    39  type Client interface {
    40  	// CreateSession returns session or error for manually control of session lifecycle
    41  	//
    42  	// CreateSession implements internal busy loop until one of the following conditions is met:
    43  	// - context was canceled or deadlined
    44  	// - session was created
    45  	//
    46  	// Deprecated: not for public usage. Because explicit session often leaked on server-side due to bad client-side usage.
    47  	// Will be removed after Oct 2024.
    48  	// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
    49  	CreateSession(ctx context.Context, opts ...Option) (s ClosableSession, err error)
    50  
    51  	// Do provide the best effort for execute operation.
    52  	//
    53  	// Do implements internal busy loop until one of the following conditions is met:
    54  	// - deadline was canceled or deadlined
    55  	// - retry operation returned nil as error
    56  	//
    57  	// Warning: if context without deadline or cancellation func than Do can run indefinitely.
    58  	Do(ctx context.Context, op Operation, opts ...Option) error
    59  
    60  	// DoTx provide the best effort for execute transaction.
    61  	//
    62  	// DoTx implements internal busy loop until one of the following conditions is met:
    63  	// - deadline was canceled or deadlined
    64  	// - retry operation returned nil as error
    65  	//
    66  	// DoTx makes auto begin (with TxSettings, by default - SerializableReadWrite), commit and
    67  	// rollback (on error) of transaction.
    68  	//
    69  	// If op TxOperation returns nil - transaction will be committed
    70  	// If op TxOperation return non nil - transaction will be rollback
    71  	// Warning: if context without deadline or cancellation func than DoTx can run indefinitely
    72  	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
    79  }
    80  
    81  type SessionStatus = string
    82  
    83  const (
    84  	SessionStatusUnknown = SessionStatus("unknown")
    85  	SessionReady         = SessionStatus("ready")
    86  	SessionBusy          = SessionStatus("busy")
    87  	SessionClosing       = SessionStatus("closing")
    88  	SessionClosed        = SessionStatus("closed")
    89  )
    90  
    91  type SessionInfo interface {
    92  	ID() string
    93  	NodeID() uint32
    94  	Status() SessionStatus
    95  	LastUsage() time.Time
    96  }
    97  
    98  type Session interface {
    99  	SessionInfo
   100  
   101  	CreateTable(
   102  		ctx context.Context,
   103  		path string,
   104  		opts ...options.CreateTableOption,
   105  	) (err error)
   106  
   107  	DescribeTable(
   108  		ctx context.Context,
   109  		path string,
   110  		opts ...options.DescribeTableOption,
   111  	) (desc options.Description, err error)
   112  
   113  	DropTable(
   114  		ctx context.Context,
   115  		path string,
   116  		opts ...options.DropTableOption,
   117  	) (err error)
   118  
   119  	AlterTable(
   120  		ctx context.Context,
   121  		path string,
   122  		opts ...options.AlterTableOption,
   123  	) (err error)
   124  
   125  	// Deprecated: use CopyTables method instead
   126  	// Will be removed after Oct 2024.
   127  	// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
   128  	CopyTable(
   129  		ctx context.Context,
   130  		dst, src string,
   131  		opts ...options.CopyTableOption,
   132  	) (err error)
   133  
   134  	CopyTables(
   135  		ctx context.Context,
   136  		opts ...options.CopyTablesOption,
   137  	) (err error)
   138  
   139  	RenameTables(
   140  		ctx context.Context,
   141  		opts ...options.RenameTablesOption,
   142  	) (err error)
   143  
   144  	Explain(
   145  		ctx context.Context,
   146  		query string,
   147  	) (exp DataQueryExplanation, err error)
   148  
   149  	// Prepare prepares query for executing in the future
   150  	Prepare(
   151  		ctx context.Context,
   152  		query string,
   153  	) (stmt Statement, err error)
   154  
   155  	// Execute executes query.
   156  	//
   157  	// By default, Execute have a flag options.WithKeepInCache(true) if params is not empty. For redefine behavior -
   158  	// append option options.WithKeepInCache(false)
   159  	Execute(
   160  		ctx context.Context,
   161  		tx *TransactionControl,
   162  		query string,
   163  		params *params.Parameters,
   164  		opts ...options.ExecuteDataQueryOption,
   165  	) (txr Transaction, r result.Result, err error)
   166  
   167  	ExecuteSchemeQuery(
   168  		ctx context.Context,
   169  		query string,
   170  		opts ...options.ExecuteSchemeQueryOption,
   171  	) (err error)
   172  
   173  	DescribeTableOptions(
   174  		ctx context.Context,
   175  	) (desc options.TableOptionsDescription, err error)
   176  
   177  	StreamReadTable(
   178  		ctx context.Context,
   179  		path string,
   180  		opts ...options.ReadTableOption,
   181  	) (r result.StreamResult, err error)
   182  
   183  	StreamExecuteScanQuery(
   184  		ctx context.Context,
   185  		query string,
   186  		params *params.Parameters,
   187  		opts ...options.ExecuteScanQueryOption,
   188  	) (_ result.StreamResult, err error)
   189  
   190  	// Deprecated: use Client instance instead.
   191  	BulkUpsert(
   192  		ctx context.Context,
   193  		table string,
   194  		rows value.Value,
   195  		opts ...options.BulkUpsertOption,
   196  	) (err error)
   197  
   198  	ReadRows(
   199  		ctx context.Context,
   200  		path string,
   201  		keys value.Value,
   202  		opts ...options.ReadRowsOption,
   203  	) (_ result.Result, err error)
   204  
   205  	BeginTransaction(
   206  		ctx context.Context,
   207  		tx *TransactionSettings,
   208  	) (x Transaction, err error)
   209  
   210  	KeepAlive(
   211  		ctx context.Context,
   212  	) error
   213  }
   214  
   215  type TransactionSettings struct {
   216  	settings Ydb_Table.TransactionSettings
   217  }
   218  
   219  func (t *TransactionSettings) Settings() *Ydb_Table.TransactionSettings {
   220  	if t == nil {
   221  		return nil
   222  	}
   223  
   224  	return &t.settings
   225  }
   226  
   227  // Explanation is a result of Explain calls.
   228  type Explanation struct {
   229  	Plan string
   230  }
   231  
   232  // ScriptingYQLExplanation is a result of Explain calls.
   233  type ScriptingYQLExplanation struct {
   234  	Explanation
   235  
   236  	ParameterTypes map[string]types.Type
   237  }
   238  
   239  // DataQueryExplanation is a result of ExplainDataQuery call.
   240  type DataQueryExplanation struct {
   241  	Explanation
   242  
   243  	AST string
   244  }
   245  
   246  // DataQuery only for tracers
   247  type DataQuery interface {
   248  	String() string
   249  	ID() string
   250  	YQL() string
   251  }
   252  
   253  type TransactionIdentifier = tx.Identifier
   254  
   255  type TransactionActor interface {
   256  	TransactionIdentifier
   257  
   258  	Execute(
   259  		ctx context.Context,
   260  		query string,
   261  		params *params.Parameters,
   262  		opts ...options.ExecuteDataQueryOption,
   263  	) (result.Result, error)
   264  	ExecuteStatement(
   265  		ctx context.Context,
   266  		stmt Statement,
   267  		params *params.Parameters,
   268  		opts ...options.ExecuteDataQueryOption,
   269  	) (result.Result, error)
   270  }
   271  
   272  type Transaction interface {
   273  	TransactionActor
   274  
   275  	CommitTx(
   276  		ctx context.Context,
   277  		opts ...options.CommitTransactionOption,
   278  	) (r result.Result, err error)
   279  	Rollback(
   280  		ctx context.Context,
   281  	) (err error)
   282  }
   283  
   284  type Statement interface {
   285  	Execute(
   286  		ctx context.Context,
   287  		tx *TransactionControl,
   288  		params *params.Parameters,
   289  		opts ...options.ExecuteDataQueryOption,
   290  	) (txr Transaction, r result.Result, err error)
   291  	NumInput() int
   292  	Text() string
   293  }
   294  
   295  var (
   296  	serializableReadWrite = &Ydb_Table.TransactionSettings_SerializableReadWrite{
   297  		SerializableReadWrite: &Ydb_Table.SerializableModeSettings{},
   298  	}
   299  	staleReadOnly = &Ydb_Table.TransactionSettings_StaleReadOnly{
   300  		StaleReadOnly: &Ydb_Table.StaleModeSettings{},
   301  	}
   302  	snapshotReadOnly = &Ydb_Table.TransactionSettings_SnapshotReadOnly{
   303  		SnapshotReadOnly: &Ydb_Table.SnapshotModeSettings{},
   304  	}
   305  )
   306  
   307  // Transaction control options
   308  type (
   309  	txDesc   Ydb_Table.TransactionSettings
   310  	TxOption func(*txDesc)
   311  )
   312  
   313  // TxSettings returns transaction settings
   314  func TxSettings(opts ...TxOption) *TransactionSettings {
   315  	s := new(TransactionSettings)
   316  	for _, opt := range opts {
   317  		if opt != nil {
   318  			opt((*txDesc)(&s.settings))
   319  		}
   320  	}
   321  
   322  	return s
   323  }
   324  
   325  // BeginTx returns begin transaction control option
   326  func BeginTx(opts ...TxOption) TxControlOption {
   327  	return func(d *txControlDesc) {
   328  		s := TxSettings(opts...)
   329  		d.TxSelector = &Ydb_Table.TransactionControl_BeginTx{
   330  			BeginTx: &s.settings,
   331  		}
   332  	}
   333  }
   334  
   335  func WithTx(t TransactionIdentifier) TxControlOption {
   336  	return func(d *txControlDesc) {
   337  		d.TxSelector = &Ydb_Table.TransactionControl_TxId{
   338  			TxId: t.ID(),
   339  		}
   340  	}
   341  }
   342  
   343  func WithTxID(txID string) TxControlOption {
   344  	return func(d *txControlDesc) {
   345  		d.TxSelector = &Ydb_Table.TransactionControl_TxId{
   346  			TxId: txID,
   347  		}
   348  	}
   349  }
   350  
   351  // CommitTx returns commit transaction control option
   352  func CommitTx() TxControlOption {
   353  	return func(d *txControlDesc) {
   354  		d.CommitTx = true
   355  	}
   356  }
   357  
   358  func WithSerializableReadWrite() TxOption {
   359  	return func(d *txDesc) {
   360  		d.TxMode = serializableReadWrite
   361  	}
   362  }
   363  
   364  func WithSnapshotReadOnly() TxOption {
   365  	return func(d *txDesc) {
   366  		d.TxMode = snapshotReadOnly
   367  	}
   368  }
   369  
   370  func WithStaleReadOnly() TxOption {
   371  	return func(d *txDesc) {
   372  		d.TxMode = staleReadOnly
   373  	}
   374  }
   375  
   376  func WithOnlineReadOnly(opts ...TxOnlineReadOnlyOption) TxOption {
   377  	return func(d *txDesc) {
   378  		var ro txOnlineReadOnly
   379  		for _, opt := range opts {
   380  			if opt != nil {
   381  				opt(&ro)
   382  			}
   383  		}
   384  		d.TxMode = &Ydb_Table.TransactionSettings_OnlineReadOnly{
   385  			OnlineReadOnly: (*Ydb_Table.OnlineModeSettings)(&ro),
   386  		}
   387  	}
   388  }
   389  
   390  type (
   391  	txOnlineReadOnly       Ydb_Table.OnlineModeSettings
   392  	TxOnlineReadOnlyOption func(*txOnlineReadOnly)
   393  )
   394  
   395  func WithInconsistentReads() TxOnlineReadOnlyOption {
   396  	return func(d *txOnlineReadOnly) {
   397  		d.AllowInconsistentReads = true
   398  	}
   399  }
   400  
   401  type (
   402  	txControlDesc   Ydb_Table.TransactionControl
   403  	TxControlOption func(*txControlDesc)
   404  )
   405  
   406  type TransactionControl struct {
   407  	desc Ydb_Table.TransactionControl
   408  }
   409  
   410  func (t *TransactionControl) Desc() *Ydb_Table.TransactionControl {
   411  	if t == nil {
   412  		return nil
   413  	}
   414  
   415  	return &t.desc
   416  }
   417  
   418  // TxControl makes transaction control from given options
   419  func TxControl(opts ...TxControlOption) *TransactionControl {
   420  	c := new(TransactionControl)
   421  	for _, opt := range opts {
   422  		if opt != nil {
   423  			opt((*txControlDesc)(&c.desc))
   424  		}
   425  	}
   426  
   427  	return c
   428  }
   429  
   430  // DefaultTxControl returns default transaction control with serializable read-write isolation mode and auto-commit
   431  func DefaultTxControl() *TransactionControl {
   432  	return TxControl(
   433  		BeginTx(WithSerializableReadWrite()),
   434  		CommitTx(),
   435  	)
   436  }
   437  
   438  // SerializableReadWriteTxControl returns transaction control with serializable read-write isolation mode
   439  func SerializableReadWriteTxControl(opts ...TxControlOption) *TransactionControl {
   440  	return TxControl(
   441  		append([]TxControlOption{
   442  			BeginTx(WithSerializableReadWrite()),
   443  		}, opts...)...,
   444  	)
   445  }
   446  
   447  // OnlineReadOnlyTxControl returns online read-only transaction control
   448  func OnlineReadOnlyTxControl(opts ...TxOnlineReadOnlyOption) *TransactionControl {
   449  	return TxControl(
   450  		BeginTx(WithOnlineReadOnly(opts...)),
   451  		CommitTx(), // open transactions not supported for OnlineReadOnly
   452  	)
   453  }
   454  
   455  // StaleReadOnlyTxControl returns stale read-only transaction control
   456  func StaleReadOnlyTxControl() *TransactionControl {
   457  	return TxControl(
   458  		BeginTx(WithStaleReadOnly()),
   459  		CommitTx(), // open transactions not supported for StaleReadOnly
   460  	)
   461  }
   462  
   463  // SnapshotReadOnlyTxControl returns snapshot read-only transaction control
   464  func SnapshotReadOnlyTxControl() *TransactionControl {
   465  	return TxControl(
   466  		BeginTx(WithSnapshotReadOnly()),
   467  		CommitTx(), // open transactions not supported for StaleReadOnly
   468  	)
   469  }
   470  
   471  // QueryParameters
   472  type (
   473  	ParameterOption = params.NamedValue
   474  	QueryParameters = params.Parameters
   475  )
   476  
   477  func NewQueryParameters(opts ...ParameterOption) *QueryParameters {
   478  	qp := QueryParameters(make([]*params.Parameter, len(opts)))
   479  	for i, opt := range opts {
   480  		if opt != nil {
   481  			qp[i] = params.Named(opt.Name(), opt.Value())
   482  		}
   483  	}
   484  
   485  	return &qp
   486  }
   487  
   488  func ValueParam(name string, v value.Value) ParameterOption {
   489  	switch len(name) {
   490  	case 0:
   491  		panic("empty name")
   492  	default:
   493  		if name[0] != '$' {
   494  			name = "$" + name
   495  		}
   496  	}
   497  
   498  	return params.Named(name, v)
   499  }
   500  
   501  type Options struct {
   502  	Label           string
   503  	Idempotent      bool
   504  	TxSettings      *TransactionSettings
   505  	TxCommitOptions []options.CommitTransactionOption
   506  	RetryOptions    []retry.Option
   507  	Trace           *trace.Table
   508  }
   509  
   510  type Option interface {
   511  	ApplyTableOption(opts *Options)
   512  }
   513  
   514  var _ Option = labelOption("")
   515  
   516  type labelOption string
   517  
   518  func (label labelOption) ApplyTableOption(opts *Options) {
   519  	opts.Label = string(label)
   520  	opts.RetryOptions = append(opts.RetryOptions, retry.WithLabel(string(label)))
   521  }
   522  
   523  func WithLabel(label string) labelOption {
   524  	return labelOption(label)
   525  }
   526  
   527  var _ Option = retryOptionsOption{}
   528  
   529  type retryOptionsOption []retry.Option
   530  
   531  func (retryOptions retryOptionsOption) ApplyTableOption(opts *Options) {
   532  	opts.RetryOptions = append(opts.RetryOptions, retryOptions...)
   533  }
   534  
   535  // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
   536  func WithRetryBudget(b budget.Budget) retryOptionsOption {
   537  	return []retry.Option{retry.WithBudget(b)}
   538  }
   539  
   540  // Deprecated: redundant option
   541  // Will be removed after Oct 2024.
   542  // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
   543  func WithRetryOptions(retryOptions []retry.Option) retryOptionsOption {
   544  	return retryOptions
   545  }
   546  
   547  func WithIdempotent() retryOptionsOption {
   548  	return []retry.Option{retry.WithIdempotent(true)}
   549  }
   550  
   551  var _ Option = txSettingsOption{}
   552  
   553  type txSettingsOption struct {
   554  	txSettings *TransactionSettings
   555  }
   556  
   557  func (opt txSettingsOption) ApplyTableOption(opts *Options) {
   558  	opts.TxSettings = opt.txSettings
   559  }
   560  
   561  func WithTxSettings(txSettings *TransactionSettings) txSettingsOption {
   562  	return txSettingsOption{txSettings: txSettings}
   563  }
   564  
   565  var _ Option = txCommitOptionsOption(nil)
   566  
   567  type txCommitOptionsOption []options.CommitTransactionOption
   568  
   569  func (txCommitOpts txCommitOptionsOption) ApplyTableOption(opts *Options) {
   570  	opts.TxCommitOptions = append(opts.TxCommitOptions, txCommitOpts...)
   571  }
   572  
   573  func WithTxCommitOptions(opts ...options.CommitTransactionOption) txCommitOptionsOption {
   574  	return opts
   575  }
   576  
   577  var _ Option = traceOption{}
   578  
   579  type traceOption struct {
   580  	t *trace.Table
   581  }
   582  
   583  func (opt traceOption) ApplyTableOption(opts *Options) {
   584  	opts.Trace = opts.Trace.Compose(opt.t)
   585  }
   586  
   587  func WithTrace(t trace.Table) traceOption { //nolint:gocritic
   588  	return traceOption{t: &t}
   589  }
   590  
   591  type BulkUpsertData interface {
   592  	ToYDB(a *allocator.Allocator, tableName string) (*Ydb_Table.BulkUpsertRequest, error)
   593  }
   594  
   595  type bulkUpsertRows struct {
   596  	rows value.Value
   597  }
   598  
   599  func (data bulkUpsertRows) ToYDB(a *allocator.Allocator, tableName string) (*Ydb_Table.BulkUpsertRequest, error) {
   600  	return &Ydb_Table.BulkUpsertRequest{
   601  		Table: tableName,
   602  		Rows:  value.ToYDB(data.rows, a),
   603  	}, nil
   604  }
   605  
   606  func BulkUpsertDataRows(rows value.Value) bulkUpsertRows {
   607  	return bulkUpsertRows{
   608  		rows: rows,
   609  	}
   610  }
   611  
   612  type bulkUpsertCsv struct {
   613  	data []byte
   614  	opts []csvFormatOption
   615  }
   616  
   617  type csvFormatOption interface {
   618  	applyCsvFormatOption(dataFormat *Ydb_Table.BulkUpsertRequest_CsvSettings) (err error)
   619  }
   620  
   621  func (data bulkUpsertCsv) ToYDB(a *allocator.Allocator, tableName string) (*Ydb_Table.BulkUpsertRequest, error) {
   622  	var (
   623  		request = &Ydb_Table.BulkUpsertRequest{
   624  			Table: tableName,
   625  			Data:  data.data,
   626  		}
   627  		dataFormat = &Ydb_Table.BulkUpsertRequest_CsvSettings{
   628  			CsvSettings: &Ydb_Formats.CsvSettings{},
   629  		}
   630  	)
   631  
   632  	for _, opt := range data.opts {
   633  		if opt != nil {
   634  			if err := opt.applyCsvFormatOption(dataFormat); err != nil {
   635  				return nil, err
   636  			}
   637  		}
   638  	}
   639  
   640  	request.DataFormat = dataFormat
   641  
   642  	return request, nil
   643  }
   644  
   645  func BulkUpsertDataCsv(data []byte, opts ...csvFormatOption) bulkUpsertCsv {
   646  	return bulkUpsertCsv{
   647  		data: data,
   648  		opts: opts,
   649  	}
   650  }
   651  
   652  type csvHeaderOption struct{}
   653  
   654  func (opt *csvHeaderOption) applyCsvFormatOption(dataFormat *Ydb_Table.BulkUpsertRequest_CsvSettings) error {
   655  	dataFormat.CsvSettings.Header = true
   656  
   657  	return nil
   658  }
   659  
   660  // First not skipped line is a CSV header (list of column names).
   661  func WithCsvHeader() csvFormatOption {
   662  	return &csvHeaderOption{}
   663  }
   664  
   665  type csvNullValueOption []byte
   666  
   667  func (nullValue csvNullValueOption) applyCsvFormatOption(dataFormat *Ydb_Table.BulkUpsertRequest_CsvSettings) error {
   668  	dataFormat.CsvSettings.NullValue = nullValue
   669  
   670  	return nil
   671  }
   672  
   673  // String value that would be interpreted as NULL.
   674  func WithCsvNullValue(value []byte) csvFormatOption {
   675  	return csvNullValueOption(value)
   676  }
   677  
   678  type csvDelimiterOption []byte
   679  
   680  func (delimeter csvDelimiterOption) applyCsvFormatOption(dataFormat *Ydb_Table.BulkUpsertRequest_CsvSettings) error {
   681  	dataFormat.CsvSettings.Delimiter = delimeter
   682  
   683  	return nil
   684  }
   685  
   686  // Fields delimiter in CSV file. It's "," if not set.
   687  func WithCsvDelimiter(value []byte) csvFormatOption {
   688  	return csvDelimiterOption(value)
   689  }
   690  
   691  type csvSkipRowsOption uint32
   692  
   693  func (skipRows csvSkipRowsOption) applyCsvFormatOption(dataFormat *Ydb_Table.BulkUpsertRequest_CsvSettings) error {
   694  	dataFormat.CsvSettings.SkipRows = uint32(skipRows)
   695  
   696  	return nil
   697  }
   698  
   699  // Number of rows to skip before CSV data. It should be present only in the first upsert of CSV file.
   700  func WithCsvSkipRows(skipRows uint32) csvFormatOption {
   701  	return csvSkipRowsOption(skipRows)
   702  }
   703  
   704  type bulkUpsertArrow struct {
   705  	data []byte
   706  	opts []arrowFormatOption
   707  }
   708  
   709  type arrowFormatOption interface {
   710  	applyArrowFormatOption(req *Ydb_Table.BulkUpsertRequest_ArrowBatchSettings) (err error)
   711  }
   712  
   713  func (data bulkUpsertArrow) ToYDB(a *allocator.Allocator, tableName string) (*Ydb_Table.BulkUpsertRequest, error) {
   714  	var (
   715  		request = &Ydb_Table.BulkUpsertRequest{
   716  			Table: tableName,
   717  			Data:  data.data,
   718  		}
   719  		dataFormat = &Ydb_Table.BulkUpsertRequest_ArrowBatchSettings{
   720  			ArrowBatchSettings: &Ydb_Formats.ArrowBatchSettings{},
   721  		}
   722  	)
   723  
   724  	for _, opt := range data.opts {
   725  		if opt != nil {
   726  			if err := opt.applyArrowFormatOption(dataFormat); err != nil {
   727  				return nil, err
   728  			}
   729  		}
   730  	}
   731  
   732  	request.DataFormat = dataFormat
   733  
   734  	return request, nil
   735  }
   736  
   737  func BulkUpsertDataArrow(data []byte, opts ...arrowFormatOption) bulkUpsertArrow {
   738  	return bulkUpsertArrow{
   739  		data: data,
   740  		opts: opts,
   741  	}
   742  }
   743  
   744  type arrowSchemaOption []byte
   745  
   746  func (schema arrowSchemaOption) applyArrowFormatOption(
   747  	dataFormat *Ydb_Table.BulkUpsertRequest_ArrowBatchSettings,
   748  ) error {
   749  	dataFormat.ArrowBatchSettings.Schema = schema
   750  
   751  	return nil
   752  }
   753  
   754  func WithArrowSchema(schema []byte) arrowFormatOption {
   755  	return arrowSchemaOption(schema)
   756  }