Loading IVOA.js +4 −4 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ import { v4 as uuidv4 } from "uuid"; * Functional signature: Request -> IO -> IO String * * @param {Request} req - Incoming HTTP request * @returns {function(Symbol): Promise<string>} - HTML content * @returns {function(Symbol): Promise<string>} - HTML content (or throws on error) */ const IVOA_tapEndpoint = (req) => async (IO) => { return await readFile("Stat/tap.html")(IO); Loading Loading @@ -167,7 +167,7 @@ const IVOA_syncEndpoint = (req) => async (IO) => { * * Functional signature: String -> IO -> IO String * * @param {string} message - Error message to embed in VOTable * @param {string} message - Error message to embed in the VOTable * @returns {(IO) => Promise<string>} - A CPS IO action returning an XML error document */ function makeSyncError(message) { Loading @@ -191,7 +191,7 @@ function makeSyncError(message) { * Functional signature: IO -> IO () * * @param {Symbol} IO - IO token * @returns {Promise<void>} - Starts the server and binds all routes * @returns {Promise<void>} - A CPS IO action that starts the server and binds all routes */ const IVOA_main = () => async (IO) => { const port = await readRESTPort(IO); Loading IVOA.py +10 −13 Original line number Diff line number Diff line Loading @@ -13,8 +13,8 @@ from typing import Awaitable, Callable from xml.dom import minidom import asyncio import uuid import xml.etree.ElementTree as ET import uuid def ivoa_tap_endpoint(req) -> Callable[[object], Awaitable[str]]: Loading @@ -27,7 +27,7 @@ def ivoa_tap_endpoint(req) -> Callable[[object], Awaitable[str]]: req: Incoming HTTP request. Returns: A function that takes an IO token and returns an awaitable HTML string. Callable[[object], Awaitable[str]]: A CPS IO action that returns HTML content (or raises on error). """ def inner(io): Loading @@ -46,7 +46,7 @@ def ivoa_availability_endpoint(req) -> Callable[[object], Awaitable[str]]: req: Incoming HTTP request. Returns: A function that takes an IO token and returns an awaitable XML string. Callable[[object], Awaitable[str]]: A CPS IO action that returns XML content (or raises on error). """ def inner(io): Loading @@ -65,7 +65,7 @@ def ivoa_capabilities_endpoint(req) -> Callable[[object], Awaitable[str]]: req: Incoming HTTP request. Returns: A function that takes an IO token and returns an awaitable XML string. Callable[[object], Awaitable[str]]: A CPS IO action that returns XML content (or raises on error). """ def inner(io): Loading @@ -84,7 +84,7 @@ def ivoa_tables_endpoint(req) -> Callable[[object], Awaitable[str]]: req: Incoming HTTP request. Returns: A function that takes an IO token and returns an awaitable XML VOTable string. Callable[[object], Awaitable[str]]: A CPS IO action that returns VOTable XML content or an error message. """ async def inner(io): Loading Loading @@ -115,7 +115,7 @@ def make_sync_error(message: str) -> Callable[[object], Awaitable[str]]: message: Error message to embed in the VOTable. Returns: A CPS IO action that returns the XML error document. Callable[[object], Awaitable[str]]: A CPS IO action returning an XML error document. """ async def inner(io): Loading @@ -132,7 +132,6 @@ def make_sync_error(message: str) -> Callable[[object], Awaitable[str]]: ET.SubElement( resource, "INFO", {"name": "QUERY_STATUS", "value": "ERROR"} ).text = message xml_str = ET.tostring(votable, encoding="utf-8") return minidom.parseString(xml_str).toprettyxml(indent=" ") Loading @@ -149,7 +148,7 @@ def ivoa_sync_endpoint(req) -> Callable[[object], Awaitable[str]]: req: Incoming HTTP request. Returns: A function that takes an IO token and returns an awaitable VOTable XML string. Callable[[object], Awaitable[str]]: A CPS IO action that returns VOTable XML content or an error message. """ async def inner(io): Loading Loading @@ -179,7 +178,7 @@ def ivoa_sync_endpoint(req) -> Callable[[object], Awaitable[str]]: await quit_postgresql(conn)(io) if result["tag"] == "nothing": return await make_sync_error("No results")(io) return await make_sync_error("No results.")(io) fields = result["value"]["fields"] rows = result["value"]["rows"] Loading @@ -203,7 +202,6 @@ def ivoa_sync_endpoint(req) -> Callable[[object], Awaitable[str]]: ET.SubElement( table, "FIELD", {"name": "access_url", "datatype": "char", "arraysize": "*"} ) data = ET.SubElement(ET.SubElement(table, "DATA"), "TABLEDATA") for row in rows: Loading @@ -224,7 +222,6 @@ def ivoa_sync_endpoint(req) -> Callable[[object], Awaitable[str]]: ET.SubElement(tr, "TD").text = access_url await quit_redis(redis)(io) xml_str = ET.tostring(votable, encoding="utf-8") return minidom.parseString(xml_str).toprettyxml(indent=" ") Loading @@ -238,7 +235,7 @@ def ivoa_main() -> Callable[[object], Awaitable[None]]: Functional signature: IO -> IO () Returns: A CPS IO action that takes the IO token and starts the IVOA server. Callable[[object], Awaitable[None]]: A CPS IO action that starts the server and binds all routes. """ async def inner(io): Loading Loading @@ -266,7 +263,7 @@ def main_expression() -> Callable[[object], Awaitable[None]]: Functional signature: () -> IO () Returns: A CPS IO action that launches the main TAP and DataLink server logic. Callable[[object], Awaitable[None]]: A CPS IO action that launches the main TAP and DataLink server logic. """ return ivoa_main() Loading Lib/IO.js +9 −9 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ export const IO = Symbol("IO"); /** * Applies an implicit CPS IO continuation to the IO token. * * Functional signature: ((Symbol) -> a) -> a) * Functional signature: ((Symbol) -> a) -> a * * @param {function(Symbol): any} f - A CPS function expecting an IO token * @returns {*} - The result of applying the function to the "IO world" Loading @@ -37,7 +37,7 @@ export function createIO(f) { /** * Alias for createIO which semantically marks a point where an effect is executed. * * Functional signature: ((Symbol) -> a) -> a) * Functional signature: ((Symbol) -> IO a) -> IO a * * @param {function(Symbol): any} f - A CPS function * @returns {*} - The result of the function performing IO operations Loading @@ -49,10 +49,10 @@ export function performIO(f) { /** * Prints a string to the console. * * Functional signature: String -> IO -> IO) * Functional signature: String -> IO -> IO () * * @param {string} x - Text to print * @returns {function(Symbol): Promise<Symbol>} - A CPS IO action that prints a string to the console * @returns {function(Symbol): Promise<Symbol>} - A CPS IO action that prints a string and returns the IO token */ export const putStr = (x) => async (IO) => { console.log(x); Loading @@ -62,10 +62,10 @@ export const putStr = (x) => async (IO) => { /** * Reads the contents of a file as UTF-8. * * Functional signature: String -> IO -> IO String) * Functional signature: String -> IO -> IO String * * @param {string} path - Path to the file * @returns {function(Symbol): Promise<string>} - A CPS IO action that reads the contents of a file as a UTF-8 string * @returns {function(Symbol): Promise<string>} - A CPS IO action that reads the file content and returns it as a string */ export const readFile = (path) => async (IO) => { return await fs.readFile(path, "utf-8"); Loading @@ -74,7 +74,7 @@ export const readFile = (path) => async (IO) => { /** * Represents the absence of a value. * * Functional signature: Maybe a) * Functional signature: Maybe a * * @const * @type {{tag: "nothing"}} Loading @@ -82,9 +82,9 @@ export const readFile = (path) => async (IO) => { export const nothing = { tag: "nothing" }; /** * Wraps a value into a 'just' tagged union * Wraps a value into a 'just' tagged union. * * Functional signature: a -> Maybe a) * Functional signature: a -> Maybe a * * @param {*} value - The value to wrap * @returns {{tag: "just", value: *}} - A tagged value Loading Lib/IO.py +6 −7 Original line number Diff line number Diff line Loading @@ -5,8 +5,7 @@ # - pip install aiofiles import aiofiles from typing import Callable, Awaitable, Any from typing import Any, Awaitable, Callable class InternalError(Exception): Loading Loading @@ -38,7 +37,7 @@ def create_io(f: Callable[[object], Any]) -> Any: f: A CPS function expecting the IO token. Returns: The result of applying the function to the IO world. Any: The result of applying the function to the IO world. """ return f(IO) Loading @@ -53,7 +52,7 @@ def perform_io(f: Callable[[object], Awaitable[Any]]) -> Awaitable[Any]: f: A CPS function. Returns: The result of the function performing IO operations. Awaitable[Any]: The result of the function performing IO operations. """ return create_io(lambda w: f(w)) Loading @@ -68,7 +67,7 @@ def put_str(x: str) -> Callable[[object], Awaitable[object]]: x: Text to print. Returns: A CPS IO action that prints the string. Callable[[object], Awaitable[object]]: A CPS IO action that prints the string and returns the IO token. """ async def inner(io: object) -> object: Loading @@ -88,7 +87,7 @@ def read_file(path: str) -> Callable[[object], Awaitable[str]]: path: Path to the file. Returns: A CPS IO action that reads the contents. Callable[[object], Awaitable[str]]: A CPS IO action that reads the file contents and returns them as a string. """ async def inner(io: object) -> str: Loading @@ -111,6 +110,6 @@ def just(value: Any) -> dict: value: The value to wrap. Returns: A tagged value {'tag': 'just', 'value': *}. dict: A tagged value {'tag': 'just', 'value': *}. """ return {"tag": "just", "value": value} Lib/PostgreSQL.js +5 −7 Original line number Diff line number Diff line Loading @@ -9,7 +9,6 @@ import { putStr } from "./IO.js"; import { just, nothing } from "./IO.js"; import pkg from "pg"; import config from "../Conf/PostgreSQL.json" with { type: "json" }; const { Client } = pkg; Loading @@ -21,12 +20,11 @@ const { Client } = pkg; /** * Connects to the PostgreSQL server using parameters from the config file. * * Functional signature: () -> IO PGConn) * Functional signature: () -> IO -> IO PGConn * * @returns {function(Symbol): Promise<PGConn>} - A CPS IO action that returns a connected PostgreSQL connection * @throws {InternalError} - If the connection fails */ export function connPostgreSQL() { return async (IO) => { const conn = new Client(config); Loading @@ -43,7 +41,7 @@ export function connPostgreSQL() { /** * Executes an SQL query with parameters, returning no result. * * Functional signature: PGConn -> String -> List String -> IO ()) * Functional signature: PGConn -> String -> [String] -> IO -> IO () * * @param {PGConn} conn - A connected PostgreSQL client * @param {string} sql - The SQL statement Loading @@ -66,12 +64,12 @@ export function execQuery(conn, sql, params) { /** * Executes an SQL query and returns both field metadata and row data. * * Functional signature: PGConn -> String -> List String -> IO (Maybe { fields, rows})) * Functional signature: PGConn -> String -> [String] -> IO -> IO (Maybe { fields, rows }) * * @param {PGConn} conn - A connected PostgreSQL client * @param {string} sql - The SQL query * @param {Array<string>} params - A list of parameters to bind * @returns {function(Symbol): Promise<{ tag: "just", value: { fields, rows } } | { tag: "nothing" }>} - A CPS IO action that returns query result wrapped in a Maybe * @returns {function(Symbol): Promise<{ tag: "just", value: { fields: Array, rows: Array } } | { tag: "nothing" }>} - A CPS IO action that returns query result wrapped in a Maybe * @throws {InternalError} - If the query fails */ export function fetchQueryResult(conn, sql, params) { Loading Loading @@ -99,7 +97,7 @@ export function fetchQueryResult(conn, sql, params) { /** * Closes the PostgreSQL connection. * * Functional signature: PGConn -> IO ()) * Functional signature: PGConn -> IO -> IO () * * @param {PGConn} conn - A connected PostgreSQL client * @returns {function(Symbol): Promise<Symbol>} - A CPS IO action that closes the PostgreSQL connection Loading Loading
IVOA.js +4 −4 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ import { v4 as uuidv4 } from "uuid"; * Functional signature: Request -> IO -> IO String * * @param {Request} req - Incoming HTTP request * @returns {function(Symbol): Promise<string>} - HTML content * @returns {function(Symbol): Promise<string>} - HTML content (or throws on error) */ const IVOA_tapEndpoint = (req) => async (IO) => { return await readFile("Stat/tap.html")(IO); Loading Loading @@ -167,7 +167,7 @@ const IVOA_syncEndpoint = (req) => async (IO) => { * * Functional signature: String -> IO -> IO String * * @param {string} message - Error message to embed in VOTable * @param {string} message - Error message to embed in the VOTable * @returns {(IO) => Promise<string>} - A CPS IO action returning an XML error document */ function makeSyncError(message) { Loading @@ -191,7 +191,7 @@ function makeSyncError(message) { * Functional signature: IO -> IO () * * @param {Symbol} IO - IO token * @returns {Promise<void>} - Starts the server and binds all routes * @returns {Promise<void>} - A CPS IO action that starts the server and binds all routes */ const IVOA_main = () => async (IO) => { const port = await readRESTPort(IO); Loading
IVOA.py +10 −13 Original line number Diff line number Diff line Loading @@ -13,8 +13,8 @@ from typing import Awaitable, Callable from xml.dom import minidom import asyncio import uuid import xml.etree.ElementTree as ET import uuid def ivoa_tap_endpoint(req) -> Callable[[object], Awaitable[str]]: Loading @@ -27,7 +27,7 @@ def ivoa_tap_endpoint(req) -> Callable[[object], Awaitable[str]]: req: Incoming HTTP request. Returns: A function that takes an IO token and returns an awaitable HTML string. Callable[[object], Awaitable[str]]: A CPS IO action that returns HTML content (or raises on error). """ def inner(io): Loading @@ -46,7 +46,7 @@ def ivoa_availability_endpoint(req) -> Callable[[object], Awaitable[str]]: req: Incoming HTTP request. Returns: A function that takes an IO token and returns an awaitable XML string. Callable[[object], Awaitable[str]]: A CPS IO action that returns XML content (or raises on error). """ def inner(io): Loading @@ -65,7 +65,7 @@ def ivoa_capabilities_endpoint(req) -> Callable[[object], Awaitable[str]]: req: Incoming HTTP request. Returns: A function that takes an IO token and returns an awaitable XML string. Callable[[object], Awaitable[str]]: A CPS IO action that returns XML content (or raises on error). """ def inner(io): Loading @@ -84,7 +84,7 @@ def ivoa_tables_endpoint(req) -> Callable[[object], Awaitable[str]]: req: Incoming HTTP request. Returns: A function that takes an IO token and returns an awaitable XML VOTable string. Callable[[object], Awaitable[str]]: A CPS IO action that returns VOTable XML content or an error message. """ async def inner(io): Loading Loading @@ -115,7 +115,7 @@ def make_sync_error(message: str) -> Callable[[object], Awaitable[str]]: message: Error message to embed in the VOTable. Returns: A CPS IO action that returns the XML error document. Callable[[object], Awaitable[str]]: A CPS IO action returning an XML error document. """ async def inner(io): Loading @@ -132,7 +132,6 @@ def make_sync_error(message: str) -> Callable[[object], Awaitable[str]]: ET.SubElement( resource, "INFO", {"name": "QUERY_STATUS", "value": "ERROR"} ).text = message xml_str = ET.tostring(votable, encoding="utf-8") return minidom.parseString(xml_str).toprettyxml(indent=" ") Loading @@ -149,7 +148,7 @@ def ivoa_sync_endpoint(req) -> Callable[[object], Awaitable[str]]: req: Incoming HTTP request. Returns: A function that takes an IO token and returns an awaitable VOTable XML string. Callable[[object], Awaitable[str]]: A CPS IO action that returns VOTable XML content or an error message. """ async def inner(io): Loading Loading @@ -179,7 +178,7 @@ def ivoa_sync_endpoint(req) -> Callable[[object], Awaitable[str]]: await quit_postgresql(conn)(io) if result["tag"] == "nothing": return await make_sync_error("No results")(io) return await make_sync_error("No results.")(io) fields = result["value"]["fields"] rows = result["value"]["rows"] Loading @@ -203,7 +202,6 @@ def ivoa_sync_endpoint(req) -> Callable[[object], Awaitable[str]]: ET.SubElement( table, "FIELD", {"name": "access_url", "datatype": "char", "arraysize": "*"} ) data = ET.SubElement(ET.SubElement(table, "DATA"), "TABLEDATA") for row in rows: Loading @@ -224,7 +222,6 @@ def ivoa_sync_endpoint(req) -> Callable[[object], Awaitable[str]]: ET.SubElement(tr, "TD").text = access_url await quit_redis(redis)(io) xml_str = ET.tostring(votable, encoding="utf-8") return minidom.parseString(xml_str).toprettyxml(indent=" ") Loading @@ -238,7 +235,7 @@ def ivoa_main() -> Callable[[object], Awaitable[None]]: Functional signature: IO -> IO () Returns: A CPS IO action that takes the IO token and starts the IVOA server. Callable[[object], Awaitable[None]]: A CPS IO action that starts the server and binds all routes. """ async def inner(io): Loading Loading @@ -266,7 +263,7 @@ def main_expression() -> Callable[[object], Awaitable[None]]: Functional signature: () -> IO () Returns: A CPS IO action that launches the main TAP and DataLink server logic. Callable[[object], Awaitable[None]]: A CPS IO action that launches the main TAP and DataLink server logic. """ return ivoa_main() Loading
Lib/IO.js +9 −9 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ export const IO = Symbol("IO"); /** * Applies an implicit CPS IO continuation to the IO token. * * Functional signature: ((Symbol) -> a) -> a) * Functional signature: ((Symbol) -> a) -> a * * @param {function(Symbol): any} f - A CPS function expecting an IO token * @returns {*} - The result of applying the function to the "IO world" Loading @@ -37,7 +37,7 @@ export function createIO(f) { /** * Alias for createIO which semantically marks a point where an effect is executed. * * Functional signature: ((Symbol) -> a) -> a) * Functional signature: ((Symbol) -> IO a) -> IO a * * @param {function(Symbol): any} f - A CPS function * @returns {*} - The result of the function performing IO operations Loading @@ -49,10 +49,10 @@ export function performIO(f) { /** * Prints a string to the console. * * Functional signature: String -> IO -> IO) * Functional signature: String -> IO -> IO () * * @param {string} x - Text to print * @returns {function(Symbol): Promise<Symbol>} - A CPS IO action that prints a string to the console * @returns {function(Symbol): Promise<Symbol>} - A CPS IO action that prints a string and returns the IO token */ export const putStr = (x) => async (IO) => { console.log(x); Loading @@ -62,10 +62,10 @@ export const putStr = (x) => async (IO) => { /** * Reads the contents of a file as UTF-8. * * Functional signature: String -> IO -> IO String) * Functional signature: String -> IO -> IO String * * @param {string} path - Path to the file * @returns {function(Symbol): Promise<string>} - A CPS IO action that reads the contents of a file as a UTF-8 string * @returns {function(Symbol): Promise<string>} - A CPS IO action that reads the file content and returns it as a string */ export const readFile = (path) => async (IO) => { return await fs.readFile(path, "utf-8"); Loading @@ -74,7 +74,7 @@ export const readFile = (path) => async (IO) => { /** * Represents the absence of a value. * * Functional signature: Maybe a) * Functional signature: Maybe a * * @const * @type {{tag: "nothing"}} Loading @@ -82,9 +82,9 @@ export const readFile = (path) => async (IO) => { export const nothing = { tag: "nothing" }; /** * Wraps a value into a 'just' tagged union * Wraps a value into a 'just' tagged union. * * Functional signature: a -> Maybe a) * Functional signature: a -> Maybe a * * @param {*} value - The value to wrap * @returns {{tag: "just", value: *}} - A tagged value Loading
Lib/IO.py +6 −7 Original line number Diff line number Diff line Loading @@ -5,8 +5,7 @@ # - pip install aiofiles import aiofiles from typing import Callable, Awaitable, Any from typing import Any, Awaitable, Callable class InternalError(Exception): Loading Loading @@ -38,7 +37,7 @@ def create_io(f: Callable[[object], Any]) -> Any: f: A CPS function expecting the IO token. Returns: The result of applying the function to the IO world. Any: The result of applying the function to the IO world. """ return f(IO) Loading @@ -53,7 +52,7 @@ def perform_io(f: Callable[[object], Awaitable[Any]]) -> Awaitable[Any]: f: A CPS function. Returns: The result of the function performing IO operations. Awaitable[Any]: The result of the function performing IO operations. """ return create_io(lambda w: f(w)) Loading @@ -68,7 +67,7 @@ def put_str(x: str) -> Callable[[object], Awaitable[object]]: x: Text to print. Returns: A CPS IO action that prints the string. Callable[[object], Awaitable[object]]: A CPS IO action that prints the string and returns the IO token. """ async def inner(io: object) -> object: Loading @@ -88,7 +87,7 @@ def read_file(path: str) -> Callable[[object], Awaitable[str]]: path: Path to the file. Returns: A CPS IO action that reads the contents. Callable[[object], Awaitable[str]]: A CPS IO action that reads the file contents and returns them as a string. """ async def inner(io: object) -> str: Loading @@ -111,6 +110,6 @@ def just(value: Any) -> dict: value: The value to wrap. Returns: A tagged value {'tag': 'just', 'value': *}. dict: A tagged value {'tag': 'just', 'value': *}. """ return {"tag": "just", "value": value}
Lib/PostgreSQL.js +5 −7 Original line number Diff line number Diff line Loading @@ -9,7 +9,6 @@ import { putStr } from "./IO.js"; import { just, nothing } from "./IO.js"; import pkg from "pg"; import config from "../Conf/PostgreSQL.json" with { type: "json" }; const { Client } = pkg; Loading @@ -21,12 +20,11 @@ const { Client } = pkg; /** * Connects to the PostgreSQL server using parameters from the config file. * * Functional signature: () -> IO PGConn) * Functional signature: () -> IO -> IO PGConn * * @returns {function(Symbol): Promise<PGConn>} - A CPS IO action that returns a connected PostgreSQL connection * @throws {InternalError} - If the connection fails */ export function connPostgreSQL() { return async (IO) => { const conn = new Client(config); Loading @@ -43,7 +41,7 @@ export function connPostgreSQL() { /** * Executes an SQL query with parameters, returning no result. * * Functional signature: PGConn -> String -> List String -> IO ()) * Functional signature: PGConn -> String -> [String] -> IO -> IO () * * @param {PGConn} conn - A connected PostgreSQL client * @param {string} sql - The SQL statement Loading @@ -66,12 +64,12 @@ export function execQuery(conn, sql, params) { /** * Executes an SQL query and returns both field metadata and row data. * * Functional signature: PGConn -> String -> List String -> IO (Maybe { fields, rows})) * Functional signature: PGConn -> String -> [String] -> IO -> IO (Maybe { fields, rows }) * * @param {PGConn} conn - A connected PostgreSQL client * @param {string} sql - The SQL query * @param {Array<string>} params - A list of parameters to bind * @returns {function(Symbol): Promise<{ tag: "just", value: { fields, rows } } | { tag: "nothing" }>} - A CPS IO action that returns query result wrapped in a Maybe * @returns {function(Symbol): Promise<{ tag: "just", value: { fields: Array, rows: Array } } | { tag: "nothing" }>} - A CPS IO action that returns query result wrapped in a Maybe * @throws {InternalError} - If the query fails */ export function fetchQueryResult(conn, sql, params) { Loading Loading @@ -99,7 +97,7 @@ export function fetchQueryResult(conn, sql, params) { /** * Closes the PostgreSQL connection. * * Functional signature: PGConn -> IO ()) * Functional signature: PGConn -> IO -> IO () * * @param {PGConn} conn - A connected PostgreSQL client * @returns {function(Symbol): Promise<Symbol>} - A CPS IO action that closes the PostgreSQL connection Loading