sless-primer/notes-python/code/notes/handler.py
“Naeel” daf750e89d feat: notes-python CRUD example + runtime path/query forwarding
- invoke.go: forward sub-path and query string to function pods
- server.js v0.1.2: add _path, _query, _method to event
- server.py v0.1.1: add _path, _query, _method to event
- upload.go: bump runtime versions (nodejs20:v0.1.2, python3.11:v0.1.1)
- examples/notes-python: CRUD notes via sub-path routing
  - sql-runner: generic SQL executor for DDL jobs
  - notes: CRUD router (/add, /update, /delete)
  - notes-list: SELECT all notes
  - init.tf: create TABLE + INDEX on apply
2026-03-09 09:51:56 +04:00

75 lines
2.6 KiB
Python

# 2026-03-09
# handler.py — CRUD роутер для таблицы notes.
# Роутинг по event._path (sub-path URL):
# POST /fn/default/notes/add?title=...&body=... → INSERT
# POST /fn/default/notes/update?id=1&title=... → UPDATE
# POST /fn/default/notes/delete?id=1 → DELETE
# _path и _query добавляет runtime из HTTP запроса (server.py).
import os
import psycopg2
import psycopg2.extras
def handle(event):
dsn = os.environ['PG_DSN']
# sub-path без ведущего слэша: "add", "update", "delete"
action = event.get('_path', '/').strip('/')
q = event.get('_query', {})
conn = psycopg2.connect(dsn)
try:
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
if action == 'add':
title = q.get('title') or event.get('title', '')
body = q.get('body') or event.get('body', '')
if not title:
return {'error': 'title is required'}
cur.execute(
"INSERT INTO notes (title, body) VALUES (%s, %s)"
" RETURNING id, title, body, created_at::text",
(title, body)
)
row = cur.fetchone()
conn.commit()
return dict(row)
elif action == 'update':
id_ = q.get('id') or event.get('id')
if not id_:
return {'error': 'id is required'}
title = q.get('title') or event.get('title', '')
body = q.get('body') or event.get('body', '')
cur.execute(
"UPDATE notes SET title=%s, body=%s WHERE id=%s"
" RETURNING id, title, body, created_at::text",
(title, body, int(id_))
)
row = cur.fetchone()
conn.commit()
return dict(row) if row else {'error': 'not found'}
elif action == 'delete':
id_ = q.get('id') or event.get('id')
if not id_:
return {'error': 'id is required'}
cur.execute(
"DELETE FROM notes WHERE id=%s RETURNING id",
(int(id_),)
)
row = cur.fetchone()
conn.commit()
return {'deleted': row['id']} if row else {'error': 'not found'}
else:
return {
'error': f'unknown action: /{action}',
'hint': 'use /add?title=...&body=..., /update?id=X&title=...&body=..., /delete?id=X'
}
except Exception as e:
conn.rollback()
return {'error': str(e)}
finally:
conn.close()