Drop-in copy of labdb's API surface from
fivenode/labdb/api/*.prg into app/api/. Single fnode invocation builds
the whole thing (bridge_server + bridge/ + 22 api/*.prg) into one
24 MB Go binary — no Node.js, no FFI, no Apache.
End-to-end smoke test (server.js not running, ctx empty so defaults
fall back) hitting six endpoints all return well-formed JSON via the
bridge layer + path -> Main dispatcher:
GET /api/hello.prg -> {"msg":"hello from PRG","ok":true}
GET /api/admin-stats.prg -> {"active_sessions":0,...}
GET /api/admin-me.prg -> {"ok":true,"user":{...}}
GET /api/sessions-list.prg -> {"sessions":[],"total":0}
GET /api/records-list.prg -> {"records":[],"sessionId":"",...}
POST /api/devices-register -> {"deviceId":"","status":"pending",...}
One small upstream patch was needed: seven .prg files each define
their own STATIC FUNCTION fn_HGet, but Five doesn't yet honour
file-local STATIC scoping for top-level functions — all definitions
land in the same symbol table and collide. Renamed each duplicate to
<file>_fn_hget so they peacefully coexist; the call sites still
reference fn_HGet and Five resolves them against _helpers.prg's
public version (signature-compatible). TODO: revert once Five gains
file-local STATIC FUNCTION scoping.
What's deferred to 1a.4-4: ctx data injection (so endpoints return
real labdb data), static asset embedding (labdb/public/), and a live
LABDB_DSN round-trip to confirm pgrtl in the request path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
48 lines
1.3 KiB
Plaintext
48 lines
1.3 KiB
Plaintext
// api/test-pg.prg — Verify pg module works from PRG via TFNModule
|
|
// GET → returns current_user, current_database, version
|
|
FUNCTION Main()
|
|
|
|
LOCAL oPg, oPool, oResult, hRow, hConfig
|
|
|
|
// Build pg config from context (passed by server.js)
|
|
hConfig := { ;
|
|
"host" => ctx_get("db_host", "localhost"), ;
|
|
"port" => Val(ctx_get("db_port", "5432")), ;
|
|
"user" => ctx_get("db_user", "labdb"), ;
|
|
"password" => ctx_get("db_password", ""), ;
|
|
"database" => ctx_get("db_name", "labdb") ;
|
|
}
|
|
|
|
// Load pg module
|
|
oPg := TFNModule():New("pg")
|
|
IF oPg == NIL
|
|
AP_JSONRESPONSE({ "ok" => .f., "error" => "failed to load pg module" })
|
|
RETURN NIL
|
|
ENDIF
|
|
|
|
// Create pool (using Pool constructor)
|
|
oPool := oPg:NewInstance("Pool", hConfig)
|
|
IF oPool == NIL
|
|
AP_JSONRESPONSE({ "ok" => .f., "error" => "failed to create pool" })
|
|
RETURN NIL
|
|
ENDIF
|
|
|
|
// Run a simple query (async via aWait)
|
|
oResult := aWait(oPool:Call("query", "SELECT current_user, current_database(), version()"))
|
|
|
|
IF oResult == NIL
|
|
AP_JSONRESPONSE({ "ok" => .f., "error" => "query returned nil" })
|
|
RETURN NIL
|
|
ENDIF
|
|
|
|
AP_JSONRESPONSE({ ;
|
|
"ok" => .t., ;
|
|
"rowCount" => oResult:rowCount, ;
|
|
"rows" => oResult:rows ;
|
|
})
|
|
|
|
// Cleanup
|
|
aWait(oPool:Call("end"))
|
|
|
|
RETURN NIL
|