# 2026-03-19 — добавлен version и hostname в ответ list_rows для тестирования обновления кода # table_rw.py — чтение и запись строк в terraform_demo_table. # Два entrypoint в одном файле: list_rows (JSON API) и add_row (HTML-страница + POST-обработчик). # ENV: PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD, PGSSLMODE import os import json import socket import psycopg2 import psycopg2.extras _CODE_VERSION = "v2-with-hostname" def _connect(): return psycopg2.connect( host=os.environ["PGHOST"], port=os.environ.get("PGPORT", "5432"), dbname=os.environ["PGDATABASE"], user=os.environ["PGUSER"], password=os.environ["PGPASSWORD"], sslmode=os.environ.get("PGSSLMODE", "require"), ) def list_rows(event): # Возвращает все строки terraform_demo_table, отсортированные по убыванию created_at. conn = _connect() try: cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) cur.execute( "SELECT id, title, created_at::text FROM terraform_demo_table ORDER BY created_at DESC" ) rows = [dict(r) for r in cur.fetchall()] return {"rows": rows, "count": len(rows), "version": _CODE_VERSION, "host": socket.gethostname()} finally: conn.close() def _render_page(rows, message=""): # HTML-страница с формой ввода и таблицей строк. # message — статус последней операции (успех / ошибка). rows_html = "".join( f"{r['id']}{r['title']}{r['created_at']}" for r in rows ) msg_html = f'

{message}

' if message else "" return f""" pg-table-writer

pg-table-writer

{msg_html} {rows_html}
#titlecreated_at
""" def add_row(event): # GET → HTML-страница с формой и списком строк. # POST → вставляет строку из form-поля title или JSON-поля title, # затем возвращает обновлённую HTML-страницу. # POST с Content-Type: application/json (curl/API) → возвращает JSON. method = event.get("_method", "GET") if method == "GET": conn = _connect() try: cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) cur.execute("SELECT id, title, created_at::text FROM terraform_demo_table ORDER BY created_at DESC") rows = [dict(r) for r in cur.fetchall()] finally: conn.close() return _render_page(rows) # POST — вставка строки # Поле title приходит либо из JSON-тела, либо из application/x-www-form-urlencoded. # Сервер уже распарсил JSON в event; form-данные приходят как event["body"] = "title=...". title = event.get("title", "").strip() if not title: # Попытка распарсить form-encoded body (браузерная форма) body = event.get("body", "") if body.startswith("title="): from urllib.parse import unquote_plus title = unquote_plus(body[len("title="):].split("&")[0]).strip() if not title: return {"ok": False, "error": "title is required"} conn = _connect() try: cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) cur.execute( "INSERT INTO terraform_demo_table (title) VALUES (%s) RETURNING id, title, created_at::text", (title,), ) row = dict(cur.fetchone()) conn.commit() # Если запрос из браузера (form POST) — возвращаем обновлённую страницу. # Если из curl/API — возвращаем JSON. accept = event.get("_accept", "") if "application/json" in accept: return {"ok": True, "row": row} # Перечитываем все строки для обновлённой страницы cur.execute("SELECT id, title, created_at::text FROM terraform_demo_table ORDER BY created_at DESC") rows = [dict(r) for r in cur.fetchall()] return _render_page(rows, message=f"Добавлено: «{row['title']}»") finally: conn.close()