Skip to content

Commit bd2244f

Browse files
committed
Fixed error of calculation of possible values for generation of string template, updated usage.md, updated CHANGELOG, and improve and columns are sorted at the point of use.
1 parent 2d0effd commit bd2244f

File tree

10 files changed

+405
-76
lines changed

10 files changed

+405
-76
lines changed

CHANGELOG.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [latest](https://github.com/tarantool/sdvg/compare/0.0.1..master)
99

10+
### Changed
11+
12+
- String templates replaced with jinja like
13+
14+
### Breaking changes
15+
16+
- The old version of string template in `type_params` of `string` type is no longer supported,
17+
instead you should use `{{ pattern('pattern_expression') }}`
18+
1019
## [0.0.1](https://github.com/tarantool/sdvg/compare/36d0930..0.0.1) - 2025-07-21
1120

1221
### Added
@@ -38,7 +47,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3847
- Data partitioning
3948
- Ability to continue generation
4049
- Availability to ignore some models for generation
41-
42-
### Changed
43-
44-
- String templates replaced with jinja like

config/models.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ models:
6262
- name: passport
6363
type: string
6464
type_params:
65-
template: AA 00 000 000
65+
template: "{{ pattern('AA 00 000 000') }}"
6666
distinct_percentage: 1
6767
ordered: true
6868
- name: created

doc/ru/usage.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ open_ai:
161161
- `max_length`: Максимальная длина строки. По умолчанию 32.
162162
- `logical_type`: Логический тип строки. Поддерживаемые значения: `first_name`, `last_name`, `phone`, `text`.
163163
- `template`: Jinja-подобный шаблон для генерации строки. Позволяет использовать любые поля генерируемой модели и
164-
задавать паттерн строки с помощью функции `pattern`, где символ `A` - любая большая буква, символ `a` - любая маленькая буква,
165-
символ `0` - любая цифра, символ `#` - любой символ, а остальные символы остаются как есть.
164+
задавать паттерн строки с помощью функции `pattern`. Информация о фильтрах и функциях, доступных в шаблонных
165+
строках описана [здесь](#фильтры-и-функции-используемые-в-шаблонных-строках).
166166
Также поддерживается использование фильтров, таких как `upper` и `lower`.
167167
- `locale`: Локаль для генерации строк. Поддерживаемые значения: `ru`, `en`. По умолчанию `en`.
168168
- `without_large_letters`: Флаг, указывающий, исключать ли большие буквы из строки.
@@ -244,6 +244,18 @@ open_ai:
244244
Подобна структуре для формата `http`, за исключением того,
245245
что поле `format_template` неизменяемое и всегда равняется значению по умолчанию.
246246

247+
#### Фильтры и функции, используемые в шаблонных строках
248+
249+
Шаблонные строки реализованы с использованием библиотеки `pongo2`, ознакомиться
250+
со всеми доступными фильтрами и функциями можно в репозитории [pongo2](https://github.com/flosch/pongo2).
251+
252+
Вдобавок к ним была добавлена 1 функция:
253+
254+
- pattern: позволяет создать паттерн строки при помощи специальных символов.
255+
Символ `A` - любая большая буква, символ `a` - любая маленькая буква,
256+
символ `0` - любая цифра, символ `#` - любой символ, а остальные символы остаются как есть.
257+
Функция доступна только в поле `template` типа данных `string`.
258+
247259
#### Примеры конфигурации генерации данных
248260

249261
Пример конфигурации модели данных:

internal/generator/models/common.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package models
22

33
import (
44
"encoding/json"
5-
"github.com/tarantool/sdvg/internal/generator/common"
65
"io"
76
"os"
87
"path/filepath"
@@ -12,6 +11,7 @@ import (
1211
"github.com/ilyakaznacheev/cleanenv"
1312
"github.com/otaviokr/topological-sort/toposort"
1413
"github.com/pkg/errors"
14+
"github.com/tarantool/sdvg/internal/generator/common"
1515
"gopkg.in/yaml.v3"
1616
)
1717

@@ -122,8 +122,8 @@ func parseErrsToString(errs []error) string {
122122
return sb.String()
123123
}
124124

125-
func topologicalSort(columns []*Column) ([]string, error) {
126-
graph := make(map[string][]string)
125+
func TopologicalSort(columns []*Column) ([]string, error) {
126+
graph := make(map[string][]string, len(columns))
127127
for _, c := range columns {
128128
graph[c.Name] = make([]string, 0)
129129

internal/generator/models/common_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func TestTopologicalSort(t *testing.T) {
106106
testFunc := func(t *testing.T, tc testCase) {
107107
t.Helper()
108108

109-
actual, err := topologicalSort(tc.columns)
109+
actual, err := TopologicalSort(tc.columns)
110110
require.Equal(t, tc.wantErr, err != nil)
111111
require.Equal(t, tc.expected, actual)
112112
}

internal/generator/models/generator_model.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,8 @@ type Model struct {
3030
RowsPerFile uint64 `backup:"true" json:"rows_per_file" yaml:"rows_per_file"`
3131
ModelDir string `backup:"true" json:"model_dir" yaml:"model_dir"`
3232
// The columns from the partitioning key with PartitionColumn.WriteToOutput == false, must be at the end of slice.
33-
Columns []*Column `backup:"true" json:"columns" yaml:"columns"`
34-
ColumnsTopologicalOrder []string
35-
PartitionColumns []*PartitionColumn `backup:"true" json:"partition_columns" yaml:"partition_columns"`
33+
Columns []*Column `backup:"true" json:"columns" yaml:"columns"`
34+
PartitionColumns []*PartitionColumn `backup:"true" json:"partition_columns" yaml:"partition_columns"`
3635
}
3736

3837
// PartitionColumn type is used to describe partition parameters for column.
@@ -81,13 +80,6 @@ func (m *Model) Parse() error {
8180

8281
m.shiftColumnsToEnd(nonWriteableColumns)
8382

84-
sortedColumns, err := topologicalSort(m.Columns)
85-
if err != nil {
86-
return errors.WithMessage(err, "failed to sorting columns by dependencies")
87-
}
88-
89-
m.ColumnsTopologicalOrder = sortedColumns
90-
9183
return nil
9284
}
9385

internal/generator/models/models_test.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,9 +1197,6 @@ parquet params:
11971197
expectedModel := tc.expected.Models[modelName]
11981198
gotModel := cfg.Models[modelName]
11991199

1200-
// skip ColumnsTopologicalOrder check
1201-
expectedModel.ColumnsTopologicalOrder = gotModel.ColumnsTopologicalOrder
1202-
12031200
for columnName := range expectedModel.Columns {
12041201
expectedColumn := expectedModel.Columns[columnName]
12051202
gotColumn := gotModel.Columns[columnName]

internal/generator/usecase/general/generator/generator.go

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@ import (
1111
)
1212

1313
type rangeGenerator struct {
14-
numFrom uint64
15-
numTo uint64
16-
distinctValuesCount uint64
17-
sequencer sequencer
18-
dataRandomFactor float64
19-
generator value.Generator
20-
nullPercentage float64
14+
numFrom uint64
15+
numTo uint64
16+
sequencer sequencer
17+
dataRandomFactor float64
18+
generator value.Generator
19+
nullPercentage float64
2120
}
2221

2322
type ColumnGenerator struct {
@@ -175,13 +174,12 @@ func newRangeGenerator(
175174
dataRandomFactor := 1 - float64(distinctValuesCount)/generatorValuesCount
176175

177176
return &rangeGenerator{
178-
numFrom: rangeRowsOffset,
179-
numTo: rangeRowsOffset + rangeRowsCount,
180-
distinctValuesCount: distinctValuesCount,
181-
dataRandomFactor: dataRandomFactor,
182-
generator: valueGenerator,
183-
sequencer: rangeSequencer,
184-
nullPercentage: dataRange.NullPercentage,
177+
numFrom: rangeRowsOffset,
178+
numTo: rangeRowsOffset + rangeRowsCount,
179+
dataRandomFactor: dataRandomFactor,
180+
generator: valueGenerator,
181+
sequencer: rangeSequencer,
182+
nullPercentage: dataRange.NullPercentage,
185183
}, nil
186184
}
187185

internal/generator/usecase/general/task.go

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,21 @@ func newGenerators(cfg *models.GenerationConfig) (map[string]*generator.ColumnGe
8484
generators := make(map[string]*generator.ColumnGenerator)
8585

8686
for modelName, model := range cfg.Models {
87-
distinctValuesCountByColumn := make(map[string]uint64)
87+
distinctValuesCountByColumn := make(map[string]uint64, len(model.Columns))
88+
89+
sortedColumns, err := models.TopologicalSort(model.Columns)
90+
if err != nil {
91+
return nil, errors.WithMessagef(err, "failed to sorting columns by dependencies for model %q", modelName)
92+
}
93+
94+
originIndexes := make(map[string]int, len(model.Columns))
95+
for index, column := range model.Columns {
96+
originIndexes[column.Name] = index
97+
}
98+
99+
for _, columnName := range sortedColumns {
100+
column := model.Columns[originIndexes[columnName]]
88101

89-
for _, column := range model.Columns {
90102
dataModelName := modelName
91103
dataModel := model
92104
dataColumn := column
@@ -173,6 +185,8 @@ func (t *Task) WaitError() error {
173185
}
174186

175187
// generateAndSaveValues function generates values for all model.
188+
//
189+
//nolint:cyclop
176190
func (t *Task) generateAndSaveValues(ctx context.Context) error {
177191
var err error
178192

@@ -203,6 +217,16 @@ func (t *Task) generateAndSaveValues(ctx context.Context) error {
203217
continue
204218
}
205219

220+
columnsTopologicalOrder, err := models.TopologicalSort(model.Columns)
221+
if err != nil {
222+
return errors.WithMessagef(err, "failed to sorting columns by dependencies for model %q", modelName)
223+
}
224+
225+
originColumnsIndexes := make(map[string]int, len(model.Columns))
226+
for index, column := range model.Columns {
227+
originColumnsIndexes[column.Name] = index
228+
}
229+
206230
pool.Add(1)
207231

208232
go func() {
@@ -223,7 +247,11 @@ func (t *Task) generateAndSaveValues(ctx context.Context) error {
223247
generators = append(generators, t.generators[columnKey].NewBatchGenerator(rowsCount))
224248
}
225249

226-
pool.Submit(ctx, outputSyncer.WorkerSyncer(), model, generators, rowsCount)
250+
pool.Submit(
251+
ctx, outputSyncer.WorkerSyncer(),
252+
modelName, columnsTopologicalOrder, originColumnsIndexes,
253+
generators, rowsCount,
254+
)
227255
}
228256
}()
229257
}
@@ -257,7 +285,8 @@ func (t *Task) skipRows() {
257285
// generateAndSaveBatch function generate batch of values for selected column and send it to output.
258286
func (t *Task) generateAndSaveBatch(
259287
ctx context.Context, outputSync *common.WorkerSyncer,
260-
model *models.Model, generators []*generator.BatchGenerator, count uint64,
288+
modelName string, columnsTopologicalOrder []string, originColumnsIndexes map[string]int,
289+
generators []*generator.BatchGenerator, count uint64,
261290
) error {
262291
defer outputSync.Done(ctx)
263292

@@ -268,20 +297,15 @@ func (t *Task) generateAndSaveBatch(
268297
}
269298
}
270299

271-
originIndexes := make(map[string]int, len(model.Columns))
272-
for index, column := range model.Columns {
273-
originIndexes[column.Name] = index
274-
}
275-
276300
for i := range count {
277-
generatedValues := make(map[string]any)
301+
generatedValues := make(map[string]any, len(originColumnsIndexes))
278302

279-
for _, columnName := range model.ColumnsTopologicalOrder {
303+
for _, columnName := range columnsTopologicalOrder {
280304
if common.CtxClosed(ctx) {
281305
return &common.ContextCancelError{}
282306
}
283307

284-
idx := originIndexes[columnName]
308+
idx := originColumnsIndexes[columnName]
285309

286310
value, err := generators[idx].Value(generatedValues)
287311
if err != nil {
@@ -295,12 +319,12 @@ func (t *Task) generateAndSaveBatch(
295319

296320
outputSync.WaitPrevious(ctx)
297321

298-
err := t.output.HandleRowsBatch(ctx, model.Name, batch)
322+
err := t.output.HandleRowsBatch(ctx, modelName, batch)
299323
if err != nil {
300324
return errors.WithMessage(err, "failed to save batch to output")
301325
}
302326

303-
t.progress.Add(model.Name, count)
327+
t.progress.Add(modelName, count)
304328

305329
return nil
306330
}

0 commit comments

Comments
 (0)