PgGraph๋Š” PostgreSQL์—์„œ ํ…Œ์ด๋ธ” ์ข…์†์„ฑ์„ ๋ณด๊ด€ํ•˜๊ณ  ์ฐพ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ์ž…๋‹ˆ๋‹ค.

PgGraph๋Š” PostgreSQL์—์„œ ํ…Œ์ด๋ธ” ์ข…์†์„ฑ์„ ๋ณด๊ด€ํ•˜๊ณ  ์ฐพ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ์ž…๋‹ˆ๋‹ค.
์˜ค๋Š˜ ์ €๋Š” Habr ๋…์ž๋“ค์—๊ฒŒ PostgreSQL DBMS์—์„œ ํ…Œ์ด๋ธ” ์ข…์†์„ฑ ์ž‘์—…์„ ์œ„ํ•ด Python์œผ๋กœ ์ž‘์„ฑ๋œ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์ œ์‹œํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์œ ํ‹ธ๋ฆฌํ‹ฐ์˜ API๋Š” ๊ฐ„๋‹จํ•˜๋ฉฐ ๋‹ค์Œ ์„ธ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

  • archive_table - ์ง€์ •๋œ ๊ธฐ๋ณธ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ–‰์„ ์žฌ๊ท€์ ์œผ๋กœ ๋ณด๊ด€/์‚ญ์ œ
  • get_table_references โ€” ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์ข…์†์„ฑ์„ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค(์ง€์ •๋œ ํ…Œ์ด๋ธ”๊ณผ ์ด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ…Œ์ด๋ธ”์ด ํ‘œ์‹œ๋จ).
  • get_rows_references - ์›ํ•˜๋Š” ํ…Œ์ด๋ธ”์˜ ์ง€์ •๋œ ํ–‰์„ ์ฐธ์กฐํ•˜๋Š” ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์˜ ํ–‰์„ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.

์„ ์‚ฌ ์‹œ๋Œ€

์ œ ์ด๋ฆ„์€ Oleg Borzov์ด๊ณ  Domklik์˜ ๋ชจ๊ธฐ์ง€ ๋Œ€์ถœ ๊ด€๋ฆฌ์ž๋ฅผ ์œ„ํ•œ CRM ํŒ€์˜ ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ CRM ์‹œ์Šคํ…œ์˜ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ํšŒ์‚ฌ์—์„œ ๊ฐ€์žฅ ํฐ ๊ทœ๋ชจ์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋˜ํ•œ ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๊ฒƒ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ๊ฐ€ ์‹œ์ž‘๋  ๋•Œ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค. ๋‚˜๋ฌด๊ฐ€ ์ปธ์„ ๋•Œ Domklik์€ ์Šคํƒ€ํŠธ์—…์ด์—ˆ๊ณ  ์„ธ๋ จ๋œ Python ๋น„๋™๊ธฐ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ๋Œ€์‹  PHP์— ๊ฑฐ๋Œ€ํ•œ ๋‹จ์ผ์ฒด๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

PHP์—์„œ Python์œผ๋กœ์˜ ์ „ํ™˜์€ ๋งค์šฐ ๊ธธ์—ˆ๊ณ  ๋‘ ์‹œ์Šคํ…œ์˜ ๋™์‹œ ์ง€์›์ด ํ•„์š”ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„์— ์˜ํ–ฅ์„ ๋ฏธ์ณค์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ ์šฐ๋ฆฌ๋Š” ๋‹ค์–‘ํ•œ ์œ ํ˜•์˜ ์ฟผ๋ฆฌ์— ๋Œ€ํ•œ ๋งŽ์€ ์ธ๋ฑ์Šค๋ฅผ ํฌํ•จํ•˜๋Š” ๊ณ ๋„๋กœ ์—ฐ๊ฒฐ๋˜๊ณ  ๊ฑฐ๋Œ€ํ•œ ํ…Œ์ด๋ธ”์ด ๋งŽ์ด ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋ณด์œ ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ชจ๋“  ๊ฒƒ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ฑ๋Šฅ์— ๋ถ€์ •์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค. ํฐ ํ…Œ์ด๋ธ”๊ณผ ํ…Œ์ด๋ธ” ์‚ฌ์ด์˜ ์ˆ˜๋งŽ์€ ๊ด€๊ณ„๋กœ ์ธํ•ด ์ฟผ๋ฆฌ์˜ ๋ณต์žก์„ฑ์ด ์ง€์†์ ์œผ๋กœ ์ฆ๊ฐ€ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์ด๋Š” ๊ฐ€์žฅ ๋งŽ์ด ๋กœ๋“œ๋œ ํ…Œ์ด๋ธ”์— ํŠนํžˆ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋กœ๋“œ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” ๊ฐ€์žฅ ๋ฐฉ๋Œ€ํ•˜๊ณ  ๋กœ๋“œ๋œ ํ…Œ์ด๋ธ”์˜ ์˜ค๋ž˜๋œ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ณด๊ด€๋œ ํ…Œ์ด๋ธ”(์˜ˆ: task ะฒ task_archive).

์ด ์ž‘์—…์€ ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๊ด€๊ณ„๊ฐ€ ๋„ˆ๋ฌด ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. task ะฒ task_archive ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ ์ „์— ์ฐธ์กฐํ•˜๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ๋™์ผํ•œ ์ž‘์—…์„ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. task ํ…Œ์ด๋ธ”.

์˜ˆ์‹œ๋ฅผ ๋“ค์–ด ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค postgrespro.ru ์‚ฌ์ดํŠธ์˜ ๋ฐ๋ชจ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค:

PgGraph๋Š” PostgreSQL์—์„œ ํ…Œ์ด๋ธ” ์ข…์†์„ฑ์„ ๋ณด๊ด€ํ•˜๊ณ  ์ฐพ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ์ž…๋‹ˆ๋‹ค.
ํ…Œ์ด๋ธ”์—์„œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์‚ญ์ œํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. Flights. Postgres๋Š” ๊ทธ๋Ÿฐ ์‹์œผ๋กœ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋จผ์ € ๋ชจ๋“  ์ฐธ์กฐ ํ…Œ์ด๋ธ”์—์„œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์‚ญ์ œํ•ด์•ผ ํ•˜๋ฉฐ, ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ˆ„๊ตฌ๋„ ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š” ํ…Œ์ด๋ธ”๊นŒ์ง€ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ญ์ œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์˜ ์˜ˆ์—์„œ๋Š” Flights ~์„ ์ง€์นญํ•˜๋‹ค Ticket_flights, ๊ทธ๋ฆฌ๊ณ  ๊ทธ๋…€์—๊ฒŒ- Boarding_passes.

๋”ฐ๋ผ์„œ ๋‹ค์Œ ์ˆœ์„œ๋กœ ์‚ญ์ œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. ์šฐ๋ฆฌ๋Š” ํ–‰์˜ ๊ธฐ๋ณธ ํ‚ค(PK) ๊ฐ’์„ ์–ป์Šต๋‹ˆ๋‹ค. Ticket_flights, ์‚ญ์ œ๋  ํ–‰์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. Flights.
  2. PK ํ–‰์„ ์–ป์Šต๋‹ˆ๋‹ค. Boarding_passes, ์ด๋Š” ๋‹ค์Œ์„ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. Ticket_flights.
  3. ํ…Œ์ด๋ธ”์˜ 2๋‹จ๊ณ„์—์„œ PK๋ณ„๋กœ ํ–‰์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. Boarding_passes.
  4. 1๋‹จ๊ณ„์—์„œ PK๋ณ„๋กœ ๋ผ์ธ์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. Ticket_flights.
  5. ๋‹ค์Œ์—์„œ ์ค„ ์ œ๊ฑฐ Flights.

๊ทธ ๊ฒฐ๊ณผ PgGraph๋ผ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ๊ฐ€ ํƒ„์ƒํ–ˆ๊ณ , ์šฐ๋ฆฌ๋Š” ์ด๋ฅผ ์˜คํ”ˆ ์†Œ์Šค๋กœ ๋งŒ๋“ค๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ ๋ฐฉ๋ฒ•

์ด ์œ ํ‹ธ๋ฆฌํ‹ฐ๋Š” ๋‘ ๊ฐ€์ง€ ์‚ฌ์šฉ ๋ชจ๋“œ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ช…๋ น์ค„์—์„œ ํ˜ธ์ถœ(pggraph โ€ฆ).
  • Python ์ฝ”๋“œ์—์„œ์˜ ์‚ฌ์šฉ๋ฒ•(ํด๋ž˜์Šค PgGraphApi).

์„ค์น˜ ๋ฐ ๊ตฌ์„ฑ

๋จผ์ € Pypi ์ €์žฅ์†Œ์—์„œ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

pip3 install pggraph

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ตฌ์„ฑ๊ณผ ๋ณด๊ด€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ์ปฌ ์ปดํ“จํ„ฐ์— config.ini ํŒŒ์ผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

[db]
host = localhost
port = 5432
user = postgres
password = postgres
dbname = postgres
schema = public ; ะะตะพะฑัะทะฐั‚ะตะปัŒะฝั‹ะน ะฟะฐั€ะฐะผะตั‚ั€, ัƒะบะฐะทะฐะฝะพ ะทะฝะฐั‡ะตะฝะธะต ะฟะพ ัƒะผะพะปั‡ะฐะฝะธัŽ

[archive]  ; ะ”ะฐะฝะฝั‹ะน ั€ะฐะทะดะตะป ะทะฐะฟะพะปะฝัั‚ัŒ ะฝะตะพะฑัะทะฐั‚ะตะปัŒะฝะพ, ะฝะธะถะต ัƒะบะฐะทะฐะฝั‹ ะทะฝะฐั‡ะตะฝะธั ะฟะพ ัƒะผะพะปั‡ะฐะฝะธัŽ
is_debug = false
chunk_size = 1000
max_depth = 20
to_archive = true
archive_suffix = 'archive'

์ฝ˜์†”์—์„œ ์‹คํ–‰

๋งค๊ฐœ ๋ณ€์ˆ˜

$ pggraph -h
usage: pggraph action [-h] --table TABLE [--ids IDS] [--config_path CONFIG_PATH]
positional arguments:
  action        required action: archive_table, get_table_references, get_rows_references

optional arguments:
  -h, --help                    show this help message and exit
  --table TABLE                 table name
  --ids IDS                     primary key ids, separated by comma, e.g. 1,2,3
  --config_path CONFIG_PATH     path to config.ini
  --log_path LOG_PATH           path to log dir
  --log_level LOG_LEVEL         log level (debug, info, error)

์œ„์น˜ ์ธ์ˆ˜:

  • action - ํ•„์ˆ˜ ์กฐ์น˜: archive_table, get_table_references ๋˜๋Š” get_rows_references.

๋ช…๋ช…๋œ ์ธ์ˆ˜:

  • --config_path โ€” ๊ตฌ์„ฑ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ;
  • --table โ€” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ํ…Œ์ด๋ธ”
  • --ids โ€” ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ID ๋ชฉ๋ก(์˜ˆ: 1,2,3 (์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜);
  • --log_path โ€” ๋กœ๊ทธ ํด๋” ๊ฒฝ๋กœ(์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜, ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™ˆ ํด๋”)
  • --log_level โ€” ๋กœ๊น… ์ˆ˜์ค€(์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜, ๊ธฐ๋ณธ๊ฐ’์€ INFO).

๋ช…๋ น ์˜ˆ

ํ…Œ์ด๋ธ” ๋ณด๊ด€

์œ ํ‹ธ๋ฆฌํ‹ฐ์˜ ์ฃผ์š” ๊ธฐ๋Šฅ์€ ๋ฐ์ดํ„ฐ ๋ณด๊ด€์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ํ…Œ์ด๋ธ”์—์„œ ๋ณด๊ด€ ํ…Œ์ด๋ธ”๋กœ ํ–‰ ์ „์†ก(์˜ˆ: ํ…Œ์ด๋ธ”์—์„œ) ์„œ์  ะฒ ์ฑ…_์•„์นด์ด๋ธŒ).

๋ณด๊ด€ํ•˜์ง€ ์•Š๊ณ  ์‚ญ์ œํ•˜๋Š” ๊ฒƒ๋„ ์ง€์›๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” config.ini์—์„œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. to_archive = ๊ฑฐ์ง“).

ํ•„์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜ - config_path, ํ…Œ์ด๋ธ” ๋ฐ ID.

์ถœ์‹œ ํ›„ ๊ธฐ๋ก์€ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค. ids ํ…Œ์ด๋ธ”์— table ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์„ ์ฐธ์กฐํ•˜๋Š” ๋ชจ๋“  ํ…Œ์ด๋ธ”์—์„œ.

$ pggraph archive_table --config_path config.hw.local.ini --table flights --ids 1,2,3
2020-06-20 19:27:44 INFO: flights - START
2020-06-20 19:27:44 INFO: flights - start archive_recursive 3 rows (depth=0)
2020-06-20 19:27:44 INFO:       START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:       ticket_flights - start archive_recursive 3 rows (depth=1)
2020-06-20 19:27:44 INFO:               START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:               boarding_passes - start archive_recursive 3 rows (depth=2)
2020-06-20 19:27:44 INFO:                       START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:                       END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:               boarding_passes - archive_by_ids 3 rows by ticket_no, flight_id
2020-06-20 19:27:44 INFO:               boarding_passes - start archive_recursive 3 rows (depth=2)
2020-06-20 19:27:44 INFO:                       START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:                       END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:               boarding_passes - archive_by_ids 3 rows by ticket_no, flight_id
2020-06-20 19:27:44 INFO:               boarding_passes - start archive_recursive 3 rows (depth=2)
2020-06-20 19:27:44 INFO:                       START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:                       END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:               boarding_passes - archive_by_ids 3 rows by ticket_no, flight_id
2020-06-20 19:27:44 INFO:               boarding_passes - start archive_recursive 3 rows (depth=2)
2020-06-20 19:27:44 INFO:                       START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:                       END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:               boarding_passes - archive_by_ids 3 rows by ticket_no, flight_id
2020-06-20 19:27:44 INFO:               END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:       ticket_flights - archive_by_ids 3 rows by ticket_no, flight_id
2020-06-20 19:27:44 INFO:       END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO: flights - archive_by_ids 3 rows by id
2020-06-20 19:27:44 INFO: flights - END

์ง€์ •๋œ ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์ข…์†์„ฑ ์ฐพ๊ธฐ

์ง€์ •๋œ ํ…Œ์ด๋ธ”์˜ ์ข…์†์„ฑ์„ ์ฐพ๋Š” ๊ธฐ๋Šฅ table. ํ•„์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜ - config_path ะธ table.

์‹คํ–‰ ํ›„ ํ™”๋ฉด์— ์‚ฌ์ „์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

  • in_refs โ€” ์ฃผ์–ด์ง„ ํ…Œ์ด๋ธ”์„ ์ฐธ์กฐํ•˜๋Š” ํ…Œ์ด๋ธ” ์‚ฌ์ „. ์—ฌ๊ธฐ์„œ ํ‚ค๋Š” ํ…Œ์ด๋ธ” ์ด๋ฆ„์ด๊ณ  ๊ฐ’์€ ์™ธ๋ž˜ ํ‚ค ๊ฐ์ฒด ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค(pk_main - ๋ฉ”์ธ ํ…Œ์ด๋ธ”์˜ ๊ธฐ๋ณธ ํ‚ค, pk_ref - ์ฐธ์กฐ ํ…Œ์ด๋ธ”์˜ ๊ธฐ๋ณธ ํ‚ค fk_ref โ€” ์†Œ์Šค ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์™ธ๋ž˜ ํ‚ค์ธ ์—ด์˜ ์ด๋ฆ„)
  • out_refs โ€” ์ด๊ฒƒ์ด ์ฐธ์กฐํ•˜๋Š” ํ…Œ์ด๋ธ” ์‚ฌ์ „์ž…๋‹ˆ๋‹ค.

$ pggraph get_table_references --config_path config.hw.local.ini --table flights
{'in_refs': {'ticket_flights': [ForeignKey(pk_main='flight_id', pk_ref='ticket_no, flight_id', fk_ref='flight_id')]},
 'out_refs': {'aircrafts': [ForeignKey(pk_main='aircraft_code', pk_ref='flight_id', fk_ref='aircraft_code')],
              'airports': [ForeignKey(pk_main='airport_code', pk_ref='flight_id', fk_ref='arrival_airport'),
                           ForeignKey(pk_main='airport_code', pk_ref='flight_id', fk_ref='departure_airport')]}}

์ง€์ •๋œ ๊ธฐ๋ณธ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ์ฐธ์กฐ ์ฐพ๊ธฐ

์™ธ๋ž˜ํ‚ค๋ฅผ ํ†ตํ•ด ํ–‰์„ ์ฐธ์กฐํ•˜๋Š” ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์˜ ํ–‰์„ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ธฐ๋Šฅ ids ํ…Œ์ด๋ธ” table. ํ•„์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜ - config_path, table ะธ ids.

์‹คํ–‰ ํ›„ ๋‹ค์Œ ๊ตฌ์กฐ์˜ ์‚ฌ์ „์ด ํ™”๋ฉด์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

{
	pk_id_1: {
		reffering_table_name_1: {
			foreign_key_1: [
				{row_pk_1: value, row_pk_2: value},
				...
			], 
			...
		},
		...
	},
	pk_id_2: {...},
	...
}

ํ˜ธ์ถœ ์˜ˆ์‹œ:

$ pggraph get_rows_references --config_path config.hw.local.ini --table flights --ids 1,2,3
{1: {'ticket_flights': {'flight_id': [{'flight_id': 1,
                                       'ticket_no': '0005432816945'},
                                      {'flight_id': 1,
                                       'ticket_no': '0005432816941'}]}},
 2: {'ticket_flights': {'flight_id': [{'flight_id': 2,
                                       'ticket_no': '0005433101832'},
                                      {'flight_id': 2,
                                       'ticket_no': '0005433101864'},
                                      {'flight_id': 2,
                                       'ticket_no': '0005432919715'}]}},
 3: {'ticket_flights': {'flight_id': [{'flight_id': 3,
                                       'ticket_no': '0005432817560'},
                                      {'flight_id': 3,
                                       'ticket_no': '0005432817568'},
                                      {'flight_id': 3,
                                       'ticket_no': '0005432817559'}]}}}

์ฝ”๋“œ์—์„œ์˜ ์‚ฌ์šฉ๋ฒ•

์ฝ˜์†”์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ Python ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. iPython ๋Œ€ํ™”ํ˜• ํ™˜๊ฒฝ์—์„œ์˜ ํ˜ธ์ถœ ์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํ…Œ์ด๋ธ” ๋ณด๊ด€

>>> from pg_graph.main import setup_logging
>>> setup_logging(log_level='DEBUG')
>>> from pg_graph.api import PgGraphApi
>>> api = PgGraphApi('config.hw.local.ini')
>>> api.archive_table('flights', [4,5])
2020-06-20 23:12:08 INFO: flights - START
2020-06-20 23:12:08 INFO: flights - start archive_recursive 2 rows (depth=0)
2020-06-20 23:12:08 INFO: 	START ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 DEBUG: 	ticket_flights - ForeignKey(pk_main='flight_id', pk_ref='flight_id, ticket_no', fk_ref='flight_id')
2020-06-20 23:12:08 DEBUG: 	SQL('SELECT flight_id, ticket_no FROM bookings.ticket_flights WHERE (flight_id) IN (%s, %s)')
2020-06-20 23:12:08 INFO: 	ticket_flights - start archive_recursive 30 rows (depth=1)
2020-06-20 23:12:08 INFO: 		START ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 DEBUG: 		boarding_passes - ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 INFO: 		boarding_passes - archive_by_fk 30 rows by ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 DEBUG: 		SQL('CREATE TABLE IF NOT EXISTS bookings.boarding_passes_archive (LIKE bookings.boarding_passes)')
2020-06-20 23:12:08 DEBUG: 		DELETE FROM boarding_passes by FK flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 INFO: 		END ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 INFO: 	ticket_flights - archive_by_ids 30 rows by flight_id, ticket_no
2020-06-20 23:12:08 DEBUG: 	SQL('CREATE TABLE IF NOT EXISTS bookings.ticket_flights_archive (LIKE bookings.ticket_flights)')
2020-06-20 23:12:08 DEBUG: 	DELETE FROM ticket_flights by flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 DEBUG: 	INSERT INTO ticket_flights_archive - 30 rows
2020-06-20 23:12:08 INFO: 	ticket_flights - start archive_recursive 30 rows (depth=1)
2020-06-20 23:12:08 INFO: 		START ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 DEBUG: 		boarding_passes - ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 INFO: 		boarding_passes - archive_by_fk 30 rows by ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 DEBUG: 		SQL('CREATE TABLE IF NOT EXISTS bookings.boarding_passes_archive (LIKE bookings.boarding_passes)')
2020-06-20 23:12:08 DEBUG: 		DELETE FROM boarding_passes by FK flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 INFO: 		END ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 INFO: 	ticket_flights - archive_by_ids 30 rows by flight_id, ticket_no
2020-06-20 23:12:08 DEBUG: 	SQL('CREATE TABLE IF NOT EXISTS bookings.ticket_flights_archive (LIKE bookings.ticket_flights)')
2020-06-20 23:12:08 DEBUG: 	DELETE FROM ticket_flights by flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 DEBUG: 	INSERT INTO ticket_flights_archive - 30 rows
2020-06-20 23:12:08 INFO: 	ticket_flights - start archive_recursive 30 rows (depth=1)
2020-06-20 23:12:08 INFO: 		START ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 DEBUG: 		boarding_passes - ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 INFO: 		boarding_passes - archive_by_fk 30 rows by ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 DEBUG: 		SQL('CREATE TABLE IF NOT EXISTS bookings.boarding_passes_archive (LIKE bookings.boarding_passes)')
2020-06-20 23:12:08 DEBUG: 		DELETE FROM boarding_passes by FK flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 INFO: 		END ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 INFO: 	ticket_flights - archive_by_ids 30 rows by flight_id, ticket_no
2020-06-20 23:12:08 DEBUG: 	SQL('CREATE TABLE IF NOT EXISTS bookings.ticket_flights_archive (LIKE bookings.ticket_flights)')
2020-06-20 23:12:08 DEBUG: 	DELETE FROM ticket_flights by flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 DEBUG: 	INSERT INTO ticket_flights_archive - 30 rows
2020-06-20 23:12:08 INFO: 	ticket_flights - start archive_recursive 3 rows (depth=1)
2020-06-20 23:12:08 INFO: 		START ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 DEBUG: 		boarding_passes - ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 INFO: 		boarding_passes - archive_by_fk 3 rows by ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 DEBUG: 		SQL('CREATE TABLE IF NOT EXISTS bookings.boarding_passes_archive (LIKE bookings.boarding_passes)')
2020-06-20 23:12:08 DEBUG: 		DELETE FROM boarding_passes by FK flight_id, ticket_no - 3 rows
2020-06-20 23:12:08 INFO: 		END ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 INFO: 	ticket_flights - archive_by_ids 3 rows by flight_id, ticket_no
2020-06-20 23:12:08 DEBUG: 	SQL('CREATE TABLE IF NOT EXISTS bookings.ticket_flights_archive (LIKE bookings.ticket_flights)')
2020-06-20 23:12:08 DEBUG: 	DELETE FROM ticket_flights by flight_id, ticket_no - 3 rows
2020-06-20 23:12:08 DEBUG: 	INSERT INTO ticket_flights_archive - 3 rows
2020-06-20 23:12:08 INFO: 	END ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 INFO: flights - archive_by_ids 2 rows by flight_id
2020-06-20 23:12:09 DEBUG: SQL('CREATE TABLE IF NOT EXISTS bookings.flights_archive (LIKE bookings.flights)')
2020-06-20 23:12:09 DEBUG: DELETE FROM flights by flight_id - 2 rows
2020-06-20 23:12:09 DEBUG: INSERT INTO flights_archive - 2 rows
2020-06-20 23:12:09 INFO: flights - END

์ง€์ •๋œ ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์ข…์†์„ฑ ์ฐพ๊ธฐ

>>> from pg_graph.api import PgGraphApi
>>> from pprint import pprint
>>> api = PgGraphApi('config.hw.local.ini')
>>> res = api.get_table_references('flights')
>>> pprint(res)
{'in_refs': {'ticket_flights': [ForeignKey(pk_main='flight_id', pk_ref='flight_id, ticket_no', fk_ref='flight_id')]},
 'out_refs': {'aircrafts': [ForeignKey(pk_main='aircraft_code', pk_ref='flight_id', fk_ref='aircraft_code')],
              'airports': [ForeignKey(pk_main='airport_code', pk_ref='flight_id', fk_ref='arrival_airport'),
                           ForeignKey(pk_main='airport_code', pk_ref='flight_id', fk_ref='departure_airport')]}}

์ง€์ •๋œ ๊ธฐ๋ณธ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ์ฐธ์กฐ ์ฐพ๊ธฐ

>>> from pg_graph.api import PgGraphApi
>>> from pprint import pprint
>>> api = PgGraphApi('config.hw.local.ini')
>>> rows = api.get_rows_references('flights', [1,2,3])
>>> pprint(rows)
{1: {'ticket_flights': {'flight_id': [{'flight_id': 1,
                                       'ticket_no': '0005432816945'},
                                      {'flight_id': 1,
                                       'ticket_no': '0005432816941'}]}},
 2: {'ticket_flights': {'flight_id': [{'flight_id': 2,
                                       'ticket_no': '0005433101832'},
                                      {'flight_id': 2,
                                       'ticket_no': '0005433101864'},
                                      {'flight_id': 2,
                                       'ticket_no': '0005432919715'}]}},
 3: {'ticket_flights': {'flight_id': [{'flight_id': 3,
                                       'ticket_no': '0005432817560'},
                                      {'flight_id': 3,
                                       'ticket_no': '0005432817568'},
                                      {'flight_id': 3,
                                       'ticket_no': '0005432817559'}]}}}

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์†Œ์Šค ์ฝ”๋“œ๋Š” ๋‹ค์Œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. GitHub์˜ MIT ๋ผ์ด์„ ์Šค์™€ ์ €์žฅ์†Œ์— ๋”ฐ๋ผ PyPI.

๋‚˜๋Š” ์˜๊ฒฌ, ์ปค๋ฐ‹ ๋ฐ ์ œ์•ˆ์„ ๊ธฐ๊บผ์ด ๋ฐ›์•„๋“ค์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ €๋Š” ์—ฌ๊ธฐ์™€ ์ €์žฅ์†Œ์—์„œ ์ตœ์„ ์„ ๋‹คํ•ด ์งˆ๋ฌธ์— ๋‹ต๋ณ€ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€