Commit e847e6b2 authored by Артём Исаев's avatar Артём Исаев
Browse files

feat: add new tables for related arguments in SQL functions

......@@ -24,8 +24,8 @@ final class RowFormulaSqlTest extends TestCase
protected static $cnx;
private const CURRENT_TABLE_ID = 1;
private const RELATED_OBJECT_ID = 100;
public static function setUpBeforeClass()
{
self::$cnx = DriverManager::getConnection([
......@@ -36,6 +36,15 @@ final class RowFormulaSqlTest extends TestCase
'password' => getenv("TEST_DB_PASSWORD"),
'port' => getenv("TEST_DB_PORT"),
]);
$stmt = self::$cnx->prepare("CREATE TABLE IF NOT EXISTS entities(
id serial,
primary key(id)
)");
$stmt->execute();
$stmt = self::$cnx->prepare("insert into entities(id) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)");
$stmt->execute();
$stmt = self::$cnx->prepare("CREATE TABLE IF NOT EXISTS object_1_(
id serial,
......@@ -52,6 +61,7 @@ final class RowFormulaSqlTest extends TestCase
$stmt = self::$cnx->prepare("CREATE TABLE IF NOT EXISTS object_8_(
id serial,
object_id integer,
attr_9_ varchar,
attr_10_ int,
attr_11_ int,
......@@ -59,17 +69,41 @@ final class RowFormulaSqlTest extends TestCase
)");
$stmt->execute();
$stmt = self::$cnx->prepare("CREATE OR REPLACE VIEW object_8_view
$stmt = self::$cnx->prepare("CREATE TABLE IF NOT EXISTS logic(
id serial,
entity_id int references entities(id) on delete cascade,
primary key(id)
)");
$stmt->execute();
$stmt = self::$cnx->prepare("INSERT INTO logic (id, entity_id) values (1, 1)");
$stmt->execute();
$stmt = self::$cnx->prepare("CREATE TABLE IF NOT EXISTS related_objects(
id serial,
logic_id int references logic(id) on delete cascade,
object_id int references entities(id) on delete cascade,
alias_field_id int references entities(id) on delete cascade,
primary key(id)
)");
$stmt->execute();
$stmt = self::$cnx->prepare("INSERT INTO related_objects (id, logic_id, object_id, alias_field_id)
values (100, 1, 8, 9)");
$stmt->execute();
$stmt = self::$cnx->prepare("CREATE OR REPLACE VIEW related_object_100
AS
SELECT t1.* FROM object_8_ t1
INNER JOIN object_1_ t2 ON t1.attr_11_ = t2.attr_6_
INNER JOIN object_1_ t2 ON t1.attr_11_ = t2.attr_7_
");
$stmt->execute();
$stmt = self::$cnx->prepare("CREATE TABLE IF NOT EXISTS row_formulas(
id serial,
object_id int,
alias_field_id int,
object_id int references entities(id) on delete cascade,
alias_field_id int references entities(id) on delete cascade,
target_alias_value text,
value text,
ast xml,
......@@ -88,18 +122,18 @@ final class RowFormulaSqlTest extends TestCase
id serial,
guid uuid,
row_formula_id int references row_formulas(id) on delete cascade,
alias_field_id int,
alias_field_id int references entities(id) on delete cascade,
alias_field_value text,
object_id int,
related_object_id int,
column_id int,
object_id int references entities(id) on delete cascade,
related_object_id int references related_objects(id) on delete cascade,
column_id int references entities(id) on delete cascade,
primary key(id)
)");
$stmt->execute();
$stmt = self::$cnx->prepare("CREATE TABLE IF NOT EXISTS row_formula_argument_filters(
row_formula_argument_id int references row_formula_arguments(id) on delete cascade,
field_id int
field_id int references entities(id) on delete cascade
)");
$stmt->execute();
......@@ -112,15 +146,8 @@ final class RowFormulaSqlTest extends TestCase
$stmt = self::$cnx->prepare("CREATE TABLE IF NOT EXISTS filter_fields(
filter_id int references filters(id) on delete cascade,
related_object_field_id int,
current_object_field_id int
)");
$stmt->execute();
$stmt = self::$cnx->prepare("CREATE TABLE IF NOT EXISTS row_formula_trees (
row_formula_id int references row_formulas(id) on delete cascade,
parent_id int references row_formulas(id) on delete cascade,
level int
related_object_field_id int references entities(id) on delete cascade,
current_object_field_id int references entities(id) on delete cascade
)");
$stmt->execute();
......@@ -202,8 +229,8 @@ AS $BODY$DECLARE
set_arr varchar[] := \'{}\';
BEGIN
select jsonb_agg(row_to_json(sub.*)) from(
select a.id, a.alias_field_id, a.alias_field_value, a.guid, a.column_id,
array_to_string(array_agg(distinct f.field_id), \',\') as filters
select a.id, a.object_id, a.related_object_id, a.alias_field_id, a.alias_field_value,
a.guid, a.column_id, array_to_string(array_agg(distinct f.field_id), \',\') as filters
from row_formula_arguments a
left join row_formula_argument_filters f ON f.row_formula_argument_id = a.id
where a.row_formula_id = formula.id
......@@ -272,9 +299,12 @@ AS $BODY$DECLARE
BEGIN
/*Бежим по всем формулам-правилам, вокруг текущего объекта*/
FOR formula IN
select *
from row_formulas rf
where rf.object_id = "updateRowFormulasByRow".object_id
select f.id, f.object_id, f.alias_field_id, f.target_alias_value, f.prepared_statement
from row_formulas f
left join logic l on l.entity_id = f.object_id
left join related_objects r on r.logic_id = l.id
where f.object_id = "updateRowFormulasByRow".object_id or r.object_id = "updateRowFormulasByRow".object_id
group by f.id
LOOP
alias_value = init_row->>(\'attr_\' || formula.alias_field_id || \'_\');
......@@ -355,7 +385,13 @@ $BODY$');
public static function tearDownAfterClass()
{
$stmt = self::$cnx->prepare("drop table row_formula_trees");
$stmt = self::$cnx->prepare("drop table entities cascade");
$stmt->execute();
$stmt = self::$cnx->prepare("drop table logic cascade");
$stmt->execute();
$stmt = self::$cnx->prepare("drop table related_objects cascade");
$stmt->execute();
$stmt = self::$cnx->prepare("drop table row_formula_argument_filters");
......@@ -363,7 +399,7 @@ $BODY$');
$stmt = self::$cnx->prepare("drop table row_formula_arguments");
$stmt->execute();
$stmt = self::$cnx->prepare("drop table filter_fields");
$stmt->execute();
......@@ -375,10 +411,10 @@ $BODY$');
$stmt = self::$cnx->prepare("drop table row_formulas");
$stmt->execute();
$stmt = self::$cnx->prepare("drop view object_8_view");
$stmt = self::$cnx->prepare("drop view related_object_100");
$stmt->execute();
$stmt = self::$cnx->prepare("drop table object_1_");
$stmt->execute();
......@@ -432,12 +468,51 @@ $BODY$');
(29, 'Множитель 2', 0, 0, 0, 9, 7),
(30, 'Произведение 2', 0, 0, 0, 10, 8),
(31, 'Множитель 1', 0, 0, 0, 10, 8),
(32, 'Множитель 2', 0, 0, 0, 10, 8)");
(32, 'Множитель 2', 0, 0, 0, 10, 8),
(33, 'СУММА', 0, 0, 0, 11, 9),
(34, 'Слагаемое 1', 0, 0, 0, 11, 9),
(35, 'Слагаемое 2', 0, 0, 0, 11, 9),
(36, 'СУММА', 0, 0, 0, 12, 10),
(37, 'Слагаемое 1', 0, 0, 0, 12, 10),
(38, 'Слагаемое 2', 0, 0, 0, 12, 10)");
$stmt->execute();
$stmt = self::$cnx->prepare("update object_1_
set object_id = 1");
$stmt->execute();
$stmt = self::$cnx->prepare("INSERT INTO object_8_(
id,
attr_9_,
attr_10_,
attr_11_
)
values(
1,
'Показатель',
100,
9
),(
2,
'Показатель',
120,
9
),(
3,
'Показатель',
120,
9
),(
4,
'Показатель',
230,
10
)");
$stmt->execute();
$stmt = self::$cnx->prepare("update object_8_
set object_id = 8");
$stmt->execute();
}
public function tearDown()
......@@ -447,6 +522,9 @@ $BODY$');
$stmt = self::$cnx->prepare("delete from object_1_");
$stmt->execute();
$stmt = self::$cnx->prepare("delete from object_8_");
$stmt->execute();
}
public function testDataPreparation()
......@@ -1140,4 +1218,97 @@ $BODY$');
$this->assertEquals(0, $data["attr_4_"]);
$this->assertEquals(0, $data["attr_5_"]);
}
public function testSimpleRelatedArgumentsNoFilters()
{
/*(33, 'СУММА', 0, 0, 0, 11, 9),
(34, 'Слагаемое 1', 0, 0, 0, 11, 9),
(35, 'Слагаемое 2', 0, 0, 0, 11, 9),
*/
//Пример: [СУММА] = [Показатель]
$repo = new RowFormulaDataRepository(self::$cnx);
$formula = '<span alias_field_id="9" related_object_id="100" object_id="8" alias_value="Показатель" ' .
'field_id="10" filters="null" field_type="integer_field"></span>';
$source = new Source($formula);
$parser = FrontendFactory::createParser('Formula', $source);
$parser->parse();
$code = $parser->getICode();
$tree = new ParseTreeGenerator();
$ast = $tree->ast($code);
$interpreter = BackendFactory::createBackend('RowFormula');
$interpreter->process($code);
$prepared_statement = $interpreter->getStatement();
//1. RowFormulas. Сохранили новую формулу в сыром виде и в виде AST дерева после интерпретации
// Поле-псевдоним: attr_2_
$stmt = self::$cnx->prepare("
insert into row_formulas
(id, object_id, alias_field_id, target_alias_value, value, ast, prepared_statement)
values
(1, 1, 2, 'СУММА', :value, :ast, :prepared_statement)
");
$stmt->bindValue('value', $formula);
$stmt->bindValue('ast', $ast);
$stmt->bindValue('prepared_statement', $prepared_statement);
$stmt->execute();
//2. TargetRowFormulaColumns. Заполняем столбцы целевых строк: attr_3_, attr_4_, attr_5_
$stmt = self::$cnx->prepare("
insert into target_row_formula_columns
(row_formula_id, column_id)
values
(1, 3), (1, 4), (1, 5)
");
$stmt->execute();
//4. RowFormulaArguments. Сохраняем аргументы формулы
$args = array_map(function ($arg) {
return $arg->getAttributes();
}, $code->getNodesByType(FormulaTokenType::ARGUMENT));
$maxKey = 0;
foreach ($args as $key => $arg) {
$stmt = self::$cnx->prepare("
insert into row_formula_arguments
(id, row_formula_id, alias_field_id, alias_field_value, object_id, related_object_id, column_id, guid)
values
(:id, 1, :alias_field_id, :alias_value, :object_id, :related_object_id, :column_id, :guid)
");
$stmt->bindValue('id', $key);
$stmt->bindValue('alias_field_id', $arg['alias_field_id']);
$stmt->bindValue('alias_value', $arg['alias_value']);
$stmt->bindValue('object_id', $arg['object_id']);
$relatedObjectId = isset($arg['related_object_id']) && $arg['related_object_id'] !== "null" ?
$arg['related_object_id'] : null;
$stmt->bindValue('related_object_id', $relatedObjectId);
$fieldId = isset($arg['field_id']) && $arg['field_id'] !== "null" ? $arg['field_id'] : null;
$stmt->bindValue('column_id', $fieldId);
$stmt->bindValue('guid', $arg['guid']);
$stmt->execute();
//5. RowFormulaArgumentFilters.
// Если аргумент текущей таблицы, то заполняем таблицу фильтров аргументов текущей таблицы
$filters = $arg['filters'] == "null" ? [] : explode(",", $arg['filters']);
if (!empty($filters)) {
foreach ($filters as $field_id) {
$stmt = self::$cnx->prepare("insert into row_formula_argument_filters(
row_formula_argument_id, field_id
) values (:row_formula_argument_id, :field_id)");
$stmt->bindValue('row_formula_argument_id', $key);
$stmt->bindValue('field_id', $field_id);
$stmt->execute();
}
}
$maxKey = $key;
}
//Обновили запись - через грид или карточку
$stmt = self::$cnx->prepare("update object_8_ set attr_10_ = 100 where id = 1");
$stmt->execute();
$this->assertTrue(true, true);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment