PgGraph PostgreSQL рдореЗрдВ рддрд╛рд▓рд┐рдХрд╛ рдирд┐рд░реНрднрд░рддрд╛рдУрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдФрд░ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╣реИ

PgGraph PostgreSQL рдореЗрдВ рддрд╛рд▓рд┐рдХрд╛ рдирд┐рд░реНрднрд░рддрд╛рдУрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдФрд░ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╣реИ
рдЖрдЬ рдореИрдВ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдПрд╕рдХреНрдпреВрдПрд▓ рдбреАрдмреАрдПрдордПрд╕ рдореЗрдВ рдЯреЗрдмрд▓ рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИрдмрд░ рдкрд╛рдардХреЛрдВ рдХреЛ рдкрд╛рдпрдерди рдореЗрдВ рд▓рд┐рдЦреА рдЧрдИ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХреЗ рд╕рд╛рде рдкреНрд░рд╕реНрддреБрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХреА рдПрдкреАрдЖрдИ рд╕рд░рд▓ рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рддреАрди рд╡рд┐рдзрд┐рдпрд╛рдБ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ:

  • рдкреБрд░рд╛рд▓реЗрдЦ_рддрд╛рд▓рд┐рдХрд╛ - рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдВрдЬреА рдХреЗ рд╕рд╛рде рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдкреБрдирд░рд╛рд╡рд░реНрддреА рд╕рдВрдЧреНрд░рд╣рд┐рдд/рд╣рдЯрд╛рдирд╛
  • get_table_references - рдХрд┐рд╕реА рддрд╛рд▓рд┐рдХрд╛ рдХреЗ рд▓рд┐рдП рдирд┐рд░реНрднрд░рддрд╛рдПрдБ рдЦреЛрдЬреЗрдВ (рдирд┐рд░реНрджрд┐рд╖реНрдЯ рддрд╛рд▓рд┐рдХрд╛ рджреНрд╡рд╛рд░рд╛ рд╕рдВрджрд░реНрднрд┐рдд рддрд╛рд▓рд┐рдХрд╛рдПрдБ рдФрд░ рдЙрд╕реЗ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реА рддрд╛рд▓рд┐рдХрд╛рдПрдБ рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреА)
  • рдкрдВрдХреНрддрд┐рдпрд╛рдБ_рд╕рдВрджрд░реНрдн рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ - рдЕрдиреНрдп рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдореЗрдВ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреА рдЦреЛрдЬ рдХрд░реЗрдВ рдЬреЛ рд╡рд╛рдВрдЫрд┐рдд рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддреА рд╣реИрдВ

рдкреГрд╖реНрдарднреВрдорд┐

рдореЗрд░рд╛ рдирд╛рдо рдУрд▓реЗрдЧ рдмреЛрд░рдЬрд╝реЛрд╡ рд╣реИ, рдореИрдВ рдбреЛрдордХреНрд▓рд┐рдХ рдореЗрдВ рдмрдВрдзрдХ рдЛрдг рджреЗрдиреЗ рд╡рд╛рд▓реЗ рдкреНрд░рдмрдВрдзрдХреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реАрдЖрд░рдПрдо рдЯреАрдо рдореЗрдВ рдПрдХ рдбреЗрд╡рд▓рдкрд░ рд╣реВрдВред

рд╣рдорд╛рд░реЗ рд╕реАрдЖрд░рдПрдо рд╕рд┐рд╕реНрдЯрдо рдХрд╛ рдореБрдЦреНрдп рдбреЗрдЯрд╛рдмреЗрд╕ рдХрдВрдкрдиреА рдореЗрдВ рд╡реЙрд▓реНрдпреВрдо рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рд╕рдмрд╕реЗ рдмрдбрд╝реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИред рдпрд╣ рднреА рд╕рдмрд╕реЗ рдкреБрд░рд╛рдиреЗ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИ: рдпрд╣ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓реЙрдиреНрдЪ рдХреЗ рд╕рдордп рд╣реА рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛ рдерд╛, рдЬрдм рдкреЗрдбрд╝ рдмрдбрд╝реЗ рдереЗ, рдбреЛрдордХреНрд▓рд┐рдХ рдПрдХ рд╕реНрдЯрд╛рд░реНрдЯрдЕрдк рдерд╛, рдФрд░ рдлреИрд╢рдиреЗрдмрд▓ рдкрд╛рдпрдерди рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдлреНрд░реЗрдорд╡рд░реНрдХ рдкрд░ рдПрдХ рдорд╛рдЗрдХреНрд░реЛрд╕рд░реНрд╡рд┐рд╕ рдХреЗ рдмрдЬрд╛рдп PHP рдореЗрдВ рдПрдХ рд╡рд┐рд╢рд╛рд▓ рдореЛрдиреЛрд▓рд┐рде рдерд╛ред

PHP рд╕реЗ рдкрд╛рдпрдерди рдореЗрдВ рд╕рдВрдХреНрд░рдордг рдмрд╣реБрдд рд▓рдВрдмрд╛ рдерд╛ рдФрд░ рджреЛрдиреЛрдВ рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХреЗ рдПрдХ рд╕рд╛рде рд╕рдорд░реНрдерди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереА, рдЬрд┐рд╕рдиреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рдбрд┐рдЬрд╝рд╛рдЗрди рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд┐рдпрд╛ред

рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рдХреЗ рдПрдХ рд╕рдореВрд╣ рдХреЗ рд╕рд╛рде рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдЕрддреНрдпрдзрд┐рдХ рдЬреБрдбрд╝реЗ рд╣реБрдП рдФрд░ рд╡рд┐рд╢рд╛рд▓ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рд╡рд╛рд▓рд╛ рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рд╣реИред рдпрд╣ рд╕рдм рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдирдХрд╛рд░рд╛рддреНрдордХ рд░реВрдк рд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддрд╛ рд╣реИ: рдмрдбрд╝реА рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдФрд░ рдЙрдирдХреЗ рдмреАрдЪ рд╕рдВрдмрдВрдзреЛрдВ рдХреЗ рдПрдХ рд╕рдореВрд╣ рдХреЗ рдХрд╛рд░рдг, рдкреНрд░рд╢реНрдиреЛрдВ рдХреА рдЬрдЯрд┐рд▓рддрд╛ рд▓рдЧрд╛рддрд╛рд░ рдмрдврд╝ рд░рд╣реА рд╣реИ, рдЬреЛ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╕рдмрд╕реЗ рднрд░реА рд╣реБрдИ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред

рдбреЗрдЯрд╛рдмреЗрд╕ рдкрд░ рд▓реЛрдб рдХреЛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдордиреЗ рдПрдХ рдРрд╕реА рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ рдЬреЛ рдкреБрд░рд╛рдиреЗ рд░рд┐рдХреЙрд░реНрдб рдХреЛ рд╕рдмрд╕реЗ рдмрдбрд╝реА рдФрд░ рднрд░реА рд╣реБрдИ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рд╕реЗ рд╕рдВрдЧреНрд░рд╣реАрдд рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рджреЗрдЧреА (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╕реЗ) task ╨▓ task_archive).

рдпрд╣ рдХрд╛рд░реНрдп рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЗ рдмреАрдЪ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд╕рдВрдмрдВрдзреЛрдВ рдХреЗ рдХрд╛рд░рдг рдЬрдЯрд┐рд▓ рд╣реИ: рдмрд╕ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдЗрдзрд░-рдЙрдзрд░ рдХрд░ рджреЗрдВ task ╨▓ task_archive рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдЙрди рд╕рднреА рд╕рдВрджрд░реНрднреЛрдВ рдХреЗ рд╕рд╛рде рдкреБрдирд░рд╛рд╡рд░реНрддреА рд░реВрдк рд╕реЗ рдРрд╕рд╛ рд╣реА рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ task рдЯреЗрдмрд▓.

рдореИрдВ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реВрдВрдЧрд╛ рд╕рд╛рдЗрдЯ postgrespro.ru рд╕реЗ рдбреЗрдореЛ рдбреЗрдЯрд╛рдмреЗрд╕:

PgGraph PostgreSQL рдореЗрдВ рддрд╛рд▓рд┐рдХрд╛ рдирд┐рд░реНрднрд░рддрд╛рдУрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдФрд░ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╣реИ
рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рд╣рдореЗрдВ рдХрд┐рд╕реА рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рд░рд┐рдХреЙрд░реНрдб рд╣рдЯрд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ Flights. рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдЬрд╝ рд╣рдореЗрдВ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрдЧрд╛: рд╣рдореЗрдВ рдкрд╣рд▓реЗ рд╕рднреА рд╕рдВрджрд░реНрднрд┐рдд рддрд╛рд▓рд┐рдХрд╛рдУрдВ рд╕реЗ рд░рд┐рдХреЙрд░реНрдб рдХреЛ рд╣рдЯрд╛рдирд╛ рд╣реЛрдЧрд╛, рдФрд░ рдЗрд╕реА рддрд░рд╣ рдЙрди рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЛ рдкреБрдирд░рд╛рд╡рд░реНрддреА рд░реВрдк рд╕реЗ рд╣рдЯрд╛рдирд╛ рд╣реЛрдЧрд╛ рдЬрд┐рдиреНрд╣реЗрдВ рдХрд┐рд╕реА рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╕рдВрджрд░реНрднрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ Flights рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИ Ticket_flights, рдФрд░ рдЙрд╕ рдкрд░ - Boarding_passes.

рдЗрд╕рд▓рд┐рдП, рдЖрдкрдХреЛ рдЗрд╕реЗ рдЗрд╕ рдХреНрд░рдо рдореЗрдВ рд╣рдЯрд╛рдирд╛ рд╣реЛрдЧрд╛:

  1. рд╣рдореЗрдВ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреА рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдВрдЬреА (рдкреАрдХреЗ) рдорд╛рди рдорд┐рд▓рддреЗ рд╣реИрдВ Ticket_flights, рдЬреЛ рд╣рдЯрд╛рдИ рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИ Flights.
  2. рд╣рдореЗрдВ рдкреАрдХреЗ рдкрдВрдХреНрддрд┐рдпрд╛рдБ рдорд┐рд▓рддреА рд╣реИрдВ Boarding_passes, рдЬреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИ Ticket_flights.
  3. рд╣рдо рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдЪрд░рдг 2 рд╕реЗ PK рджреНрд╡рд╛рд░рд╛ рдкрдВрдХреНрддрд┐рдпрд╛рдБ рд╣рдЯрд╛рддреЗ рд╣реИрдВ Boarding_passes.
  4. рдЪрд░рдг 1 рд╕реЗ PK рджреНрд╡рд╛рд░рд╛ рдкрдВрдХреНрддрд┐рдпрд╛рдБ рд╣рдЯрд╛рдПрдБ Ticket_flights.
  5. рд╕реЗ рдкрдВрдХреНрддрд┐рдпрд╛рдБ рд╣рдЯрд╛ рд░рд╣рд╛ рд╣реВрдБ Flights.

рдкрд░рд┐рдгрд╛рдо PgGraph рдирд╛рдордХ рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдереА, рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдЦреБрд▓рд╛ рд╕реНрд░реЛрдд рдмрдирд╛рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ред

рдХреИрд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ

рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдЙрдкрдпреЛрдЧ рдХреЗ рджреЛ рддрд░реАрдХреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддреА рд╣реИ:

  • рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рд╕реЗ рдХреЙрд▓ рдХрд░реЗрдВ (pggraph тАж).
  • рдкрд╛рдпрдерди рдХреЛрдб рдореЗрдВ рдЙрдкрдпреЛрдЧ (рдХреНрд▓рд╛рд╕ 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 - рдЕрд▓реНрдкрд╡рд┐рд░рд╛рдо рджреНрд╡рд╛рд░рд╛ рдЕрд▓рдЧ рдХреА рдЧрдИ рдЖрдИрдбреА рдХреА рд╕реВрдЪреА, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, 1,2,3 (рд╡реИрдХрд▓реНрдкрд┐рдХ рдкреИрд░рд╛рдореАрдЯрд░);
  • --log_path - рд▓реЙрдЧ рдХреЗ рд▓рд┐рдП рдлрд╝реЛрд▓реНрдбрд░ рдХрд╛ рдкрде (рд╡реИрдХрд▓реНрдкрд┐рдХ рдкреИрд░рд╛рдореАрдЯрд░, рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ - рд╣реЛрдо рдлрд╝реЛрд▓реНрдбрд░);
  • --log_level - рд▓реЙрдЧрд┐рдВрдЧ рд╕реНрддрд░ (рд╡реИрдХрд▓реНрдкрд┐рдХ рдкреИрд░рд╛рдореАрдЯрд░, рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдЬрд╛рдирдХрд╛рд░реА рд╣реИ)ред

рдХрдорд╛рди рдХреЗ рдЙрджрд╛рд╣рд░рдг

рдПрдХ рддрд╛рд▓рд┐рдХрд╛ рд╕рдВрдЧреНрд░рд╣рд┐рдд рдХрд░рдирд╛

рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХрд╛ рдореБрдЦреНрдп рдХрд╛рд░реНрдп рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣ рдХрд░рдирд╛ рд╣реИ, рдЕрд░реНрдерд╛рддред рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдореБрдЦреНрдп рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рд╕рдВрдЧреНрд░рд╣ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдХрд┐рддрд╛рдмреЗрдВ ╨▓ рдкреБрд╕реНрддрдХреЗрдВ_рд╕рдВрдЧреНрд░рд╣).

рд╕рдВрдЧреНрд░рд╣ рдХрд┐рдП рдмрд┐рдирд╛ рд╣рдЯрд╛рдирд╛ рднреА рд╕рдорд░реНрдерд┐рдд рд╣реИ: рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ config.ini рдореЗрдВ рдкреИрд░рд╛рдореАрдЯрд░ рд╕реЗрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ to_archive = рдЧрд▓рдд).

рдЖрд╡рд╢реНрдпрдХ рдкреИрд░рд╛рдореАрдЯрд░ - config_path, рддрд╛рд▓рд┐рдХрд╛ рдФрд░ рдЖрдИрдбреА.

рд▓реЙрдиреНрдЪ рдХреЗ рдмрд╛рдж, рд░рд┐рдХреЙрд░реНрдб рдкреБрдирд░рд╛рд╡рд░реНрддреА рд░реВрдк рд╕реЗ рд╣рдЯрд╛ рджрд┐рдП рдЬрд╛рдПрдВрдЧреЗ 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'}]}}}

рдХреЛрдб рдореЗрдВ рдЙрдкрдпреЛрдЧ

рдЗрд╕реЗ рдХрдВрд╕реЛрд▓ рдореЗрдВ рдЪрд▓рд╛рдиреЗ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдкрд╛рдпрдерди рдХреЛрдб рдореЗрдВ рднреА рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред 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 рдПрдордЖрдИрдЯреА рд▓рд╛рдЗрд╕реЗрдВрд╕ рдХреЗ рддрд╣рдд, рд╕рд╛рде рд╣реА рднрдВрдбрд╛рд░ рдореЗрдВ рднреА PyPI.

рдореБрдЭреЗ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ, рдкреНрд░рддрд┐рдмрджреНрдзрддрд╛рдУрдВ рдФрд░ рд╕реБрдЭрд╛рд╡реЛрдВ рдкрд░ рдЦреБрд╢реА рд╣реЛрдЧреАред

рдореИрдВ рдпрд╣рд╛рдВ рдФрд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдЕрдкрдиреА рд╕рд░реНрд╡реЛрддреНрддрдо рдХреНрд╖рдорддрд╛ рд╕реЗ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рдЙрддреНрддрд░ рджреЗрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реВрдВрдЧрд╛ред

рд╕реНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╝реЗрдВ