clickhouse-go icon indicating copy to clipboard operation
clickhouse-go copied to clipboard

Batch: impl `Columns() []column.Interface` method

Open egsam98 opened this issue 1 year ago • 4 comments

Hello, my proposal is to provide additional method Columns() []column.Interface for Batch interface. This might be useful when additional information about the table metadata is needed.

Example:

batch, err := chConn.PrepareBatch(ctx, fmt.Sprintf(`INSERT INTO %q`, table))
if err != nil {
        return errors.Wrap(err, "ClickHouse: Prepare batch")
}

structType, err := tableSchema(batch.Columns())
if err != nil {
        return err
}

func tableSchema(columns []column.Interface) (reflect.Type, error) {
	fields := make([]reflect.StructField, len(columns ))
	for i, col := range columns  {
		fieldType := col.ScanType()
		name := col.Name()
		fields[i] = reflect.StructField{
			Name: cases.Title(language.Und).String(name),
			Type: fieldType,
			Tag:  reflect.StructTag(fmt.Sprintf("json:%q ch:%q", name, name)),
		}
	}
	return reflect.StructOf(fields), nil
}

egsam98 avatar Apr 18 '24 12:04 egsam98

CLA assistant check
All committers have signed the CLA.

CLAassistant avatar Apr 18 '24 12:04 CLAassistant

Hi @egsam98

This might be useful when additional information about the table metadata is needed.

What additional data is needed? Perhaps we can try to expose more safe interface.

jkaflik avatar Apr 25 '24 10:04 jkaflik

I suppose the whole information provided by column.Interface might be useful for metaprogramming. As I pointed in example code, by means of Block() I can receive column info like name and Go type from proto.Block. I intentionally made this method returning shallow copy instead of pointer to somehow exclude possible modification. Unfortunately, there's no immutable pointers in Go.

As alternative solution I can replace Block() proto.Block with Columns() []column.Interface. If we speak about safer interface

Personally I use this approach to build dynamic struct via reflect.StructOf and then parse input JSON bytes. Also it would be useful to deal with impossibility to insert Go maps instead of structs:

  1. Obtain column names from proto.Block in the correct order
  2. Unwrap the map into slice by iteration for column names
  3. Use slice for Batch.Append() method.

egsam98 avatar Apr 26 '24 17:04 egsam98

Replaced with Columns []column.Interface method

egsam98 avatar Apr 30 '24 11:04 egsam98

@egsam98 Columns method works for me. Please add a test case that does a simple assertion.

jkaflik avatar Jun 03 '24 07:06 jkaflik

@jkaflik Hi, let me know if I've added test case in a wrong place of codebase. Thank you

egsam98 avatar Jun 04 '24 10:06 egsam98