powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / Подскажите паттерн
3 сообщений из 3, страница 1 из 1
Подскажите паттерн
    #38641827
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть скрипт на Perl, который осуществляет перенос данных из одной информационной системы в другую.
Структура баз данных в этих информационных системах разная, но общие моменты есть.
Поэтому я хочу написать универсальную процедуру, которая будет осуществлять перенос данных.
На входе структура будет принимать три параметра: источник данных (массив хешей или ссылка на DBI::sth), схема переноса (хеш), приемник данных.
Схема переноса — это хеш, ключи которого будут полями приемника, а значения могут быть:
1. Скаляром (константой), которая переносится один в один.
2. Ссылкой на поле источника данных, значение которого переносится один в один.
3. Анонимной процедурой, в которую передается текущая запись источника и которая используется для произвольной трансформации.
Вызов этой функции и сама функция будут выглядеть примерно так:
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
my $ret = &datasync(
  $rs,
  {
    'field_user' => 'script',
    'field_title' => {'ref'=>'src_name'},
    'field_type' => sub {my $row = shift; return $dict->{$row->{'type_id'}};}
  },
  [$dbh, $table]
);
...
sub datasync($$$)
{
  my $rs = shift;
  my $ds = shift;
  my ($dbh,$tbl) = [shift];
  my $fld = $dbh->column_info(undef,undef,$tbl,undef)->fetchall_hashref('COLUMN_NAME');
  foreach my $row ((values(%$rs)))
  {
    foreach my $fld (sort {$a->{'ORDINAL_POSITION'}<=>$b->{'ORDINAL_POSITION'}} values(%$fld))
    {
      if (!ref($ds->{$fld->{'NAME'}})) {$data->{$fld->{'NAME'}} = $ds->{$fld->{'NAME'}}}
      elsif (ref($ds->{$fld->{'NAME'}}) eq 'CODE') {$data->{$fld->{'NAME'}} = &{$ds->{$fld->{'NAME'}}}($row)}
      elsif (ref($ds->{$fld->{'NAME'}}) eq 'HASH')
      {
        if (exists($ds->{$fld->{'NAME'}}->{'ref'})) {$data->{$fld->{'NAME'}} = $row->{$ds->{$fld->{'NAME'}}->{'field'}}}
      }
...
    }
...
  }



Но тут есть одна сложность.
Описанный код осуществляет получение данных для текущей строки приемника, на месте многоточий будет код, осуществляющий перенос этих данных в БД.
Мне нужно переносить несколько десятков сущностей, у разных сущностей используются разные PK и констрейны.
Я бы не хотел делать мега-процедуру, которая бы изучала приемник, определяла в нем PK и уникальные индексы, дополнительные констрейны и самостоятельно осуществляла перенос данных в приемник в зависимости от десятка критериев (добавить/обновить/удалить/пропустить запись, проверить корректность данных в полях и заполнение обязательных полей и т.п.). Всю эту проверку я бы хотел оставить в вызываемой процедуре. Тогда для каждой сущности я буду использовать свою процедуру, которая будет подготавливать данные с помощью datasync, а различные проверки будут в коде этой процедуры.

В принципе, я бы использовать callback-функцию (передавать в datasync еще один аргумент с анонимной функцией, которая будет вызываться вместо многоточий), но у такой архитектуры есть несколько неудобств.
Я также мог бы в datasync сохранять подготовленные данные в хеш, возвращать его в вызываемую процедуру, которая уже и будет делать проверки и переносить данные в приемник. Но данных может быть много, они и так занимают память в $rs, а тут будет еще один примерно такой же по размеру хеш.

Видимо нужно использовать другую архитектуру, но на ум ничего не приходит.
Не посоветуете, как еще можно обособить код универсальной обработки данных, который выполняется внутри цикла?

________________________
Мы смотрим с оптимизмом...
...в оптический прицел.
...
Рейтинг: 0 / 0
Подскажите паттерн
    #38642046
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пока дошел до такого:
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
	my $sync = &sync_prepare(<dbi::sth>,<table>,{'CODE' => sub {my $row = shift; return $dict->{$row->{'TYPE_ID'}};}});
	while (my $res = &sync_process($sync))
	{
		print Dumper($res);
	}
...
sub sync_prepare($$$)
{
	my $src = shift;
	my $dst = shift;
	my $map = shift;
	my $sync = {};
	return unless ($src && $dst);
	$sync->{'src'} = $src;
	$sync->{'fld'} = $dbh->column_info(undef,undef,$dst,undef)->fetchall_hashref('COLUMN_NAME');
	$sync->{'map'} = $map;
	return $sync;
}

sub sync_process($)
{
	my $sync = shift;
	my $row = $sync->{'src'}->fetchrow_hashref();
	return unless ($row);
	my $data = {};
	foreach my $fld (sort {$a->{'ORDINAL_POSITION'}<=>$b->{'ORDINAL_POSITION'}} values %{$sync->{'fld'}})
	{
		if (exists $sync->{'map'}->{$fld->{'COLUMN_NAME'}})
		{
			my $f = $sync->{'map'}->{$fld->{'COLUMN_NAME'}};
			$data->{$fld->{'COLUMN_NAME'}} = undef;
			if (!ref($f)) # константа
			{
				$data->{$fld->{'COLUMN_NAME'}} = $f;
			}
			elsif (ref($f) eq 'CODE') # функция
			{
				$data->{$fld->{'COLUMN_NAME'}} = &$f($row);
			}
			elsif (ref($f) eq 'HASH')
			{
				if (exists $f->{'type'})
				{
					if ($f->{'type'} eq 'value') # значение константы
					{
						$data->{$fld->{'COLUMN_NAME'}} = $f->{'value'};
					}
					elsif ($f->{'type'} eq 'field') # значение поля-источника
					{
						$data->{$fld->{'COLUMN_NAME'}} = $row->{$f->{'field'}};
					}
				}
				else
				{
					$data->{$fld->{'COLUMN_NAME'}} = $row->{$f->{'field'}} if ($f->{'field'});
					$data->{$fld->{'COLUMN_NAME'}} = $f->{'value'} if ($f->{'value'});
				}
			}
		}
	}
	return $data;
}


Все контекстные проверки в вызывающей процедуре.

Может кому пригодится.
А может кто посоветует, как улучшить.
...
Рейтинг: 0 / 0
Подскажите паттерн
    #38642390
Фотография volodin661
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.,

никому не пригодится.

несмотря на имеющиеся общие моменты в нескольких системах,
быстрее и качественнее написать отдельный 'переносчик' для каждой,
пользуясь универсальным инструментом под названием Perl
и не изнывая от фрустрации от 'рутинности' повторяющихся процедур.
...
Рейтинг: 0 / 0
3 сообщений из 3, страница 1 из 1
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / Подскажите паттерн
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]