From a643fd99f2f338724121e3750e84ff8bcbb3e2b0 Mon Sep 17 00:00:00 2001 From: Sergey Polygalin Date: Sun, 17 Dec 2023 17:13:33 +0300 Subject: [PATCH] Builder for single query in saving collections --- tpl/codegen_bundle.twig | 16 +++++++++++ tpl/macros_struct.twig | 59 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/tpl/codegen_bundle.twig b/tpl/codegen_bundle.twig index 463145f..f604d43 100644 --- a/tpl/codegen_bundle.twig +++ b/tpl/codegen_bundle.twig @@ -35,10 +35,26 @@ var _ = strings.Clone {{ enum_macros.enum(u.object) }} {% endfor %} +type queryDiffBuilder struct { + query *strings.Builder + values *strings.Builder + update *strings.Builder + rawValues []any +} + +func NewQueryDiffBuilder() queryDiffBuilder { + return queryDiffBuilder{ + query: &strings.Builder{}, + values: &strings.Builder{}, + update: &strings.Builder{}, + } +} + {% for u in structs %} {{ struct_macros.struct(u.object) }} {% endfor %} + func CreateById(classId uint32) (meta.Struct, error) { switch classId { {% for u in structs %} diff --git a/tpl/macros_struct.twig b/tpl/macros_struct.twig index 7d3435b..3c06c41 100644 --- a/tpl/macros_struct.twig +++ b/tpl/macros_struct.twig @@ -215,11 +215,66 @@ func Save{{ ctx.s.name }}Diff(ctx context.Context, dbe metadb.Execer, rec {{ ctx } func Save{{ ctx.s.name }}CollectionDiff(ctx context.Context, dbe metadb.Execer, recs []{{ ctx.s.name }}) error { + byFieldsKey := map[string]queryDiffBuilder{} for _, rec := range recs { - if err := Save{{ ctx.s.name }}Diff(ctx, dbe, rec); err != nil { - return err + if rec.changedFields.Empty() { + continue } + + key := rec.changedFields.GetFieldsKey() + if _, ok := byFieldsKey[key]; !ok { + builder := NewQueryDiffBuilder() + + builder.query.WriteString("INSERT INTO `{{ ctx.table_name }}` ({{ ctx.pkey_column_expr }}") + builder.update.WriteString(" ON DUPLICATE KEY UPDATE {{ ctx.pkey_update_expr }}") + builder.values.WriteString(" VALUES ") + + {% if ctx.raw_nonpk_fields|length > 0 %} + {% for f in ctx.raw_nonpk_fields %} + if rec.{{ f|fname }}Changed() { + builder.query.WriteString(",`{{ f.name }}`") + builder.update.WriteString(",`{{ f.name }}`=VALUES(`{{ f.name }}`)") + } + {% endfor %} + {% endif %} + + byFieldsKey[key] = builder + } + + builder := byFieldsKey[key] + builder.values.WriteString("({{ ctx.pkey_values_expr }}") + + {% for f in ctx.pkey %} + builder.rawValues = append(builder.rawValues, rec.{{ f|fname }}) + {% endfor %} + + {% if ctx.raw_nonpk_fields|length > 0 %} + {% for f in ctx.raw_nonpk_fields %} + if rec.{{ f|fname }}Changed() { + builder.values.WriteString(",?") + builder.rawValues = append(builder.rawValues, rec.{{ f|fname }}) + } + {% endfor %} + {% endif %} + + builder.values.WriteRune(')') + builder.values.WriteRune(',') } + + for _, builder := range byFieldsKey { + var index int = 1 + if len(builder.rawValues) > 1 { + index = 2 + } + queryBuilder := builder.query + builder.query.WriteRune(')') + queryBuilder.WriteString(builder.values.String()[0 : len(builder.values.String())-index]) + queryBuilder.WriteString(builder.update.String()) + + _, saveErr := dbe.ExecContext(ctx, queryBuilder.String(), builder.rawValues...) + return errors.Wrap(saveErr, queryBuilder.String()) + } + return nil } {% endmacro table_save %}