diff --git a/docs/schema/schema.json b/docs/schema/schema.json index 1e46115..954c2c6 100644 --- a/docs/schema/schema.json +++ b/docs/schema/schema.json @@ -1135,86 +1135,33 @@ } ], "comment": "" - } - ], - "enums": [ - { - "name": "user_role", - "vals": [ - "student", - "alumni", - "faculty", - "external", - "dev" - ], - "comment": "" - } - ], - "composite_types": [] - }, - { - "comment": "", - "name": "pg_temp", - "tables": [], - "enums": [], - "composite_types": [] - }, - { - "comment": "", - "name": "pg_catalog", - "tables": [ + }, { "rel": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" + "catalog": "", + "schema": "", + "name": "links" }, "columns": [ { - "name": "tableoid", + "name": "lid", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" - }, - "table_alias": "", - "type": { "catalog": "", "schema": "", - "name": "oid" - }, - "is_sqlc_slice": false, - "embed_table": null, - "original_name": "", - "unsigned": false, - "array_dims": 0 - }, - { - "name": "cmax", - "not_null": true, - "is_array": false, - "comment": "", - "length": 4, - "is_named_param": false, - "is_func_call": false, - "scope": "", - "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" + "name": "links" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "uuid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1223,24 +1170,24 @@ "array_dims": 0 }, { - "name": "xmax", + "name": "endpoint_url", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" + "catalog": "", + "schema": "", + "name": "links" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -1249,24 +1196,24 @@ "array_dims": 0 }, { - "name": "cmin", + "name": "dest_url", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" + "catalog": "", + "schema": "", + "name": "links" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -1275,24 +1222,24 @@ "array_dims": 0 }, { - "name": "xmin", + "name": "oid", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" + "catalog": "", + "schema": "", + "name": "links" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "uuid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1301,50 +1248,60 @@ "array_dims": 0 }, { - "name": "ctid", - "not_null": true, + "name": "created_at", + "not_null": false, "is_array": false, "comment": "", - "length": 6, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" + "catalog": "", + "schema": "", + "name": "links" }, "table_alias": "", "type": { "catalog": "", - "schema": "", - "name": "tid" + "schema": "pg_catalog", + "name": "timestamp" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - }, + } + ], + "comment": "" + }, + { + "rel": { + "catalog": "", + "schema": "", + "name": "link_visits" + }, + "columns": [ { - "name": "aggfnoid", + "name": "lvid", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" + "catalog": "", + "schema": "", + "name": "link_visits" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "regproc" + "name": "uuid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1353,24 +1310,24 @@ "array_dims": 0 }, { - "name": "aggkind", + "name": "lid", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" + "catalog": "", + "schema": "", + "name": "link_visits" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "char" + "name": "uuid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1379,24 +1336,24 @@ "array_dims": 0 }, { - "name": "aggnumdirectargs", - "not_null": true, + "name": "uid", + "not_null": false, "is_array": false, "comment": "", - "length": 2, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" + "catalog": "", + "schema": "", + "name": "link_visits" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "int2" + "name": "uuid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1405,33 +1362,70 @@ "array_dims": 0 }, { - "name": "aggtransfn", - "not_null": true, + "name": "created_at", + "not_null": false, "is_array": false, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_aggregate" + "catalog": "", + "schema": "", + "name": "link_visits" }, "table_alias": "", "type": { "catalog": "", - "schema": "", - "name": "regproc" + "schema": "pg_catalog", + "name": "timestamp" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - }, + } + ], + "comment": "" + } + ], + "enums": [ + { + "name": "user_role", + "vals": [ + "student", + "alumni", + "faculty", + "external", + "dev" + ], + "comment": "" + } + ], + "composite_types": [] + }, + { + "comment": "", + "name": "pg_temp", + "tables": [], + "enums": [], + "composite_types": [] + }, + { + "comment": "", + "name": "pg_catalog", + "tables": [ + { + "rel": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_aggregate" + }, + "columns": [ { - "name": "aggfinalfn", + "name": "tableoid", "not_null": true, "is_array": false, "comment": "", @@ -1448,7 +1442,7 @@ "type": { "catalog": "", "schema": "", - "name": "regproc" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1457,7 +1451,7 @@ "array_dims": 0 }, { - "name": "aggcombinefn", + "name": "cmax", "not_null": true, "is_array": false, "comment": "", @@ -1474,7 +1468,7 @@ "type": { "catalog": "", "schema": "", - "name": "regproc" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1483,7 +1477,7 @@ "array_dims": 0 }, { - "name": "aggserialfn", + "name": "xmax", "not_null": true, "is_array": false, "comment": "", @@ -1500,7 +1494,7 @@ "type": { "catalog": "", "schema": "", - "name": "regproc" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1509,7 +1503,7 @@ "array_dims": 0 }, { - "name": "aggdeserialfn", + "name": "cmin", "not_null": true, "is_array": false, "comment": "", @@ -1526,7 +1520,7 @@ "type": { "catalog": "", "schema": "", - "name": "regproc" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1535,7 +1529,7 @@ "array_dims": 0 }, { - "name": "aggmtransfn", + "name": "xmin", "not_null": true, "is_array": false, "comment": "", @@ -1552,7 +1546,7 @@ "type": { "catalog": "", "schema": "", - "name": "regproc" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1561,11 +1555,11 @@ "array_dims": 0 }, { - "name": "aggminvtransfn", + "name": "ctid", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 6, "is_named_param": false, "is_func_call": false, "scope": "", @@ -1578,7 +1572,7 @@ "type": { "catalog": "", "schema": "", - "name": "regproc" + "name": "tid" }, "is_sqlc_slice": false, "embed_table": null, @@ -1587,7 +1581,7 @@ "array_dims": 0 }, { - "name": "aggmfinalfn", + "name": "aggfnoid", "not_null": true, "is_array": false, "comment": "", @@ -1613,7 +1607,7 @@ "array_dims": 0 }, { - "name": "aggfinalextra", + "name": "aggkind", "not_null": true, "is_array": false, "comment": "", @@ -1630,7 +1624,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, @@ -1639,11 +1633,11 @@ "array_dims": 0 }, { - "name": "aggmfinalextra", + "name": "aggnumdirectargs", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", @@ -1656,7 +1650,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, @@ -1665,11 +1659,11 @@ "array_dims": 0 }, { - "name": "aggfinalmodify", + "name": "aggtransfn", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -1682,7 +1676,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "regproc" }, "is_sqlc_slice": false, "embed_table": null, @@ -1691,11 +1685,11 @@ "array_dims": 0 }, { - "name": "aggmfinalmodify", + "name": "aggfinalfn", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -1708,7 +1702,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "regproc" }, "is_sqlc_slice": false, "embed_table": null, @@ -1717,7 +1711,7 @@ "array_dims": 0 }, { - "name": "aggsortop", + "name": "aggcombinefn", "not_null": true, "is_array": false, "comment": "", @@ -1734,7 +1728,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "regproc" }, "is_sqlc_slice": false, "embed_table": null, @@ -1743,7 +1737,7 @@ "array_dims": 0 }, { - "name": "aggtranstype", + "name": "aggserialfn", "not_null": true, "is_array": false, "comment": "", @@ -1760,7 +1754,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "regproc" }, "is_sqlc_slice": false, "embed_table": null, @@ -1769,7 +1763,7 @@ "array_dims": 0 }, { - "name": "aggtransspace", + "name": "aggdeserialfn", "not_null": true, "is_array": false, "comment": "", @@ -1786,7 +1780,7 @@ "type": { "catalog": "", "schema": "", - "name": "int4" + "name": "regproc" }, "is_sqlc_slice": false, "embed_table": null, @@ -1795,7 +1789,7 @@ "array_dims": 0 }, { - "name": "aggmtranstype", + "name": "aggmtransfn", "not_null": true, "is_array": false, "comment": "", @@ -1812,7 +1806,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "regproc" }, "is_sqlc_slice": false, "embed_table": null, @@ -1821,7 +1815,7 @@ "array_dims": 0 }, { - "name": "aggmtransspace", + "name": "aggminvtransfn", "not_null": true, "is_array": false, "comment": "", @@ -1838,7 +1832,7 @@ "type": { "catalog": "", "schema": "", - "name": "int4" + "name": "regproc" }, "is_sqlc_slice": false, "embed_table": null, @@ -1847,11 +1841,11 @@ "array_dims": 0 }, { - "name": "agginitval", - "not_null": false, + "name": "aggmfinalfn", + "not_null": true, "is_array": false, "comment": "", - "length": -1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -1864,7 +1858,7 @@ "type": { "catalog": "", "schema": "", - "name": "text" + "name": "regproc" }, "is_sqlc_slice": false, "embed_table": null, @@ -1873,11 +1867,11 @@ "array_dims": 0 }, { - "name": "aggminitval", - "not_null": false, + "name": "aggfinalextra", + "not_null": true, "is_array": false, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -1890,43 +1884,33 @@ "type": { "catalog": "", "schema": "", - "name": "text" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - } - ], - "comment": "" - }, - { - "rel": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_am" - }, - "columns": [ + }, { - "name": "tableoid", + "name": "aggmfinalextra", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_am" + "name": "pg_aggregate" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -1935,24 +1919,24 @@ "array_dims": 0 }, { - "name": "cmax", + "name": "aggfinalmodify", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_am" + "name": "pg_aggregate" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, @@ -1961,24 +1945,24 @@ "array_dims": 0 }, { - "name": "xmax", + "name": "aggmfinalmodify", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_am" + "name": "pg_aggregate" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, @@ -1987,7 +1971,7 @@ "array_dims": 0 }, { - "name": "cmin", + "name": "aggsortop", "not_null": true, "is_array": false, "comment": "", @@ -1998,13 +1982,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_am" + "name": "pg_aggregate" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2013,7 +1997,7 @@ "array_dims": 0 }, { - "name": "xmin", + "name": "aggtranstype", "not_null": true, "is_array": false, "comment": "", @@ -2024,13 +2008,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_am" + "name": "pg_aggregate" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2039,24 +2023,24 @@ "array_dims": 0 }, { - "name": "ctid", + "name": "aggtransspace", "not_null": true, "is_array": false, "comment": "", - "length": 6, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_am" + "name": "pg_aggregate" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "tid" + "name": "int4" }, "is_sqlc_slice": false, "embed_table": null, @@ -2065,7 +2049,7 @@ "array_dims": 0 }, { - "name": "oid", + "name": "aggmtranstype", "not_null": true, "is_array": false, "comment": "", @@ -2076,7 +2060,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_am" + "name": "pg_aggregate" }, "table_alias": "", "type": { @@ -2091,24 +2075,24 @@ "array_dims": 0 }, { - "name": "amname", + "name": "aggmtransspace", "not_null": true, "is_array": false, "comment": "", - "length": 64, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_am" + "name": "pg_aggregate" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "name" + "name": "int4" }, "is_sqlc_slice": false, "embed_table": null, @@ -2117,24 +2101,24 @@ "array_dims": 0 }, { - "name": "amhandler", - "not_null": true, + "name": "agginitval", + "not_null": false, "is_array": false, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_am" + "name": "pg_aggregate" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "regproc" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -2143,24 +2127,24 @@ "array_dims": 0 }, { - "name": "amtype", - "not_null": true, + "name": "aggminitval", + "not_null": false, "is_array": false, "comment": "", - "length": 1, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_am" + "name": "pg_aggregate" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "char" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -2175,7 +2159,7 @@ "rel": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amop" + "name": "pg_am" }, "columns": [ { @@ -2190,7 +2174,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amop" + "name": "pg_am" }, "table_alias": "", "type": { @@ -2216,7 +2200,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amop" + "name": "pg_am" }, "table_alias": "", "type": { @@ -2242,7 +2226,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amop" + "name": "pg_am" }, "table_alias": "", "type": { @@ -2268,7 +2252,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amop" + "name": "pg_am" }, "table_alias": "", "type": { @@ -2294,7 +2278,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amop" + "name": "pg_am" }, "table_alias": "", "type": { @@ -2320,7 +2304,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amop" + "name": "pg_am" }, "table_alias": "", "type": { @@ -2346,7 +2330,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amop" + "name": "pg_am" }, "table_alias": "", "type": { @@ -2361,7 +2345,33 @@ "array_dims": 0 }, { - "name": "amopfamily", + "name": "amname", + "not_null": true, + "is_array": false, + "comment": "", + "length": 64, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_am" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "name" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "amhandler", "not_null": true, "is_array": false, "comment": "", @@ -2372,13 +2382,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amop" + "name": "pg_am" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "regproc" }, "is_sqlc_slice": false, "embed_table": null, @@ -2387,7 +2397,43 @@ "array_dims": 0 }, { - "name": "amoplefttype", + "name": "amtype", + "not_null": true, + "is_array": false, + "comment": "", + "length": 1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_am" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "char" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + } + ], + "comment": "" + }, + { + "rel": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_amop" + }, + "columns": [ + { + "name": "tableoid", "not_null": true, "is_array": false, "comment": "", @@ -2413,7 +2459,7 @@ "array_dims": 0 }, { - "name": "amoprighttype", + "name": "cmax", "not_null": true, "is_array": false, "comment": "", @@ -2430,7 +2476,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2439,11 +2485,11 @@ "array_dims": 0 }, { - "name": "amopstrategy", + "name": "xmax", "not_null": true, "is_array": false, "comment": "", - "length": 2, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -2456,7 +2502,7 @@ "type": { "catalog": "", "schema": "", - "name": "int2" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2465,11 +2511,11 @@ "array_dims": 0 }, { - "name": "amoppurpose", + "name": "cmin", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -2482,7 +2528,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2491,7 +2537,7 @@ "array_dims": 0 }, { - "name": "amopopr", + "name": "xmin", "not_null": true, "is_array": false, "comment": "", @@ -2508,7 +2554,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2517,7 +2563,33 @@ "array_dims": 0 }, { - "name": "amopmethod", + "name": "ctid", + "not_null": true, + "is_array": false, + "comment": "", + "length": 6, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_amop" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "tid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "oid", "not_null": true, "is_array": false, "comment": "", @@ -2543,7 +2615,7 @@ "array_dims": 0 }, { - "name": "amopsortfamily", + "name": "amopfamily", "not_null": true, "is_array": false, "comment": "", @@ -2567,19 +2639,9 @@ "original_name": "", "unsigned": false, "array_dims": 0 - } - ], - "comment": "" - }, - { - "rel": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_amproc" - }, - "columns": [ + }, { - "name": "tableoid", + "name": "amoplefttype", "not_null": true, "is_array": false, "comment": "", @@ -2590,7 +2652,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amproc" + "name": "pg_amop" }, "table_alias": "", "type": { @@ -2605,7 +2667,7 @@ "array_dims": 0 }, { - "name": "cmax", + "name": "amoprighttype", "not_null": true, "is_array": false, "comment": "", @@ -2616,13 +2678,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amproc" + "name": "pg_amop" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2631,24 +2693,24 @@ "array_dims": 0 }, { - "name": "xmax", + "name": "amopstrategy", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amproc" + "name": "pg_amop" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, @@ -2657,24 +2719,24 @@ "array_dims": 0 }, { - "name": "cmin", + "name": "amoppurpose", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amproc" + "name": "pg_amop" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, @@ -2683,7 +2745,7 @@ "array_dims": 0 }, { - "name": "xmin", + "name": "amopopr", "not_null": true, "is_array": false, "comment": "", @@ -2694,13 +2756,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amproc" + "name": "pg_amop" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2709,24 +2771,24 @@ "array_dims": 0 }, { - "name": "ctid", + "name": "amopmethod", "not_null": true, "is_array": false, "comment": "", - "length": 6, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amproc" + "name": "pg_amop" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "tid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2735,7 +2797,7 @@ "array_dims": 0 }, { - "name": "oid", + "name": "amopsortfamily", "not_null": true, "is_array": false, "comment": "", @@ -2746,7 +2808,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_amproc" + "name": "pg_amop" }, "table_alias": "", "type": { @@ -2759,9 +2821,19 @@ "original_name": "", "unsigned": false, "array_dims": 0 - }, + } + ], + "comment": "" + }, + { + "rel": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_amproc" + }, + "columns": [ { - "name": "amprocfamily", + "name": "tableoid", "not_null": true, "is_array": false, "comment": "", @@ -2787,7 +2859,7 @@ "array_dims": 0 }, { - "name": "amproclefttype", + "name": "cmax", "not_null": true, "is_array": false, "comment": "", @@ -2804,7 +2876,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2813,7 +2885,7 @@ "array_dims": 0 }, { - "name": "amprocrighttype", + "name": "xmax", "not_null": true, "is_array": false, "comment": "", @@ -2830,7 +2902,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2839,11 +2911,11 @@ "array_dims": 0 }, { - "name": "amprocnum", + "name": "cmin", "not_null": true, "is_array": false, "comment": "", - "length": 2, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -2856,7 +2928,7 @@ "type": { "catalog": "", "schema": "", - "name": "int2" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2865,7 +2937,7 @@ "array_dims": 0 }, { - "name": "amproc", + "name": "xmin", "not_null": true, "is_array": false, "comment": "", @@ -2882,43 +2954,33 @@ "type": { "catalog": "", "schema": "", - "name": "regproc" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - } - ], - "comment": "" - }, - { - "rel": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_attrdef" - }, - "columns": [ + }, { - "name": "tableoid", + "name": "ctid", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 6, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attrdef" + "name": "pg_amproc" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "tid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2927,7 +2989,7 @@ "array_dims": 0 }, { - "name": "cmax", + "name": "oid", "not_null": true, "is_array": false, "comment": "", @@ -2938,13 +3000,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attrdef" + "name": "pg_amproc" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2953,7 +3015,7 @@ "array_dims": 0 }, { - "name": "xmax", + "name": "amprocfamily", "not_null": true, "is_array": false, "comment": "", @@ -2964,13 +3026,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attrdef" + "name": "pg_amproc" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -2979,7 +3041,7 @@ "array_dims": 0 }, { - "name": "cmin", + "name": "amproclefttype", "not_null": true, "is_array": false, "comment": "", @@ -2990,13 +3052,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attrdef" + "name": "pg_amproc" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -3005,7 +3067,7 @@ "array_dims": 0 }, { - "name": "xmin", + "name": "amprocrighttype", "not_null": true, "is_array": false, "comment": "", @@ -3016,13 +3078,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attrdef" + "name": "pg_amproc" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -3031,24 +3093,24 @@ "array_dims": 0 }, { - "name": "ctid", + "name": "amprocnum", "not_null": true, "is_array": false, "comment": "", - "length": 6, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attrdef" + "name": "pg_amproc" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "tid" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, @@ -3057,7 +3119,7 @@ "array_dims": 0 }, { - "name": "oid", + "name": "amproc", "not_null": true, "is_array": false, "comment": "", @@ -3068,22 +3130,32 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attrdef" + "name": "pg_amproc" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "regproc" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - }, + } + ], + "comment": "" + }, + { + "rel": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_attrdef" + }, + "columns": [ { - "name": "adrelid", + "name": "tableoid", "not_null": true, "is_array": false, "comment": "", @@ -3108,94 +3180,6 @@ "unsigned": false, "array_dims": 0 }, - { - "name": "adnum", - "not_null": true, - "is_array": false, - "comment": "", - "length": 2, - "is_named_param": false, - "is_func_call": false, - "scope": "", - "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_attrdef" - }, - "table_alias": "", - "type": { - "catalog": "", - "schema": "", - "name": "int2" - }, - "is_sqlc_slice": false, - "embed_table": null, - "original_name": "", - "unsigned": false, - "array_dims": 0 - }, - { - "name": "adbin", - "not_null": true, - "is_array": false, - "comment": "", - "length": -1, - "is_named_param": false, - "is_func_call": false, - "scope": "", - "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_attrdef" - }, - "table_alias": "", - "type": { - "catalog": "", - "schema": "", - "name": "pg_node_tree" - }, - "is_sqlc_slice": false, - "embed_table": null, - "original_name": "", - "unsigned": false, - "array_dims": 0 - } - ], - "comment": "" - }, - { - "rel": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_attribute" - }, - "columns": [ - { - "name": "tableoid", - "not_null": true, - "is_array": false, - "comment": "", - "length": 4, - "is_named_param": false, - "is_func_call": false, - "scope": "", - "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_attribute" - }, - "table_alias": "", - "type": { - "catalog": "", - "schema": "", - "name": "oid" - }, - "is_sqlc_slice": false, - "embed_table": null, - "original_name": "", - "unsigned": false, - "array_dims": 0 - }, { "name": "cmax", "not_null": true, @@ -3208,7 +3192,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attribute" + "name": "pg_attrdef" }, "table_alias": "", "type": { @@ -3234,7 +3218,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attribute" + "name": "pg_attrdef" }, "table_alias": "", "type": { @@ -3260,7 +3244,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attribute" + "name": "pg_attrdef" }, "table_alias": "", "type": { @@ -3286,7 +3270,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attribute" + "name": "pg_attrdef" }, "table_alias": "", "type": { @@ -3312,7 +3296,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attribute" + "name": "pg_attrdef" }, "table_alias": "", "type": { @@ -3327,7 +3311,7 @@ "array_dims": 0 }, { - "name": "attrelid", + "name": "oid", "not_null": true, "is_array": false, "comment": "", @@ -3338,7 +3322,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attribute" + "name": "pg_attrdef" }, "table_alias": "", "type": { @@ -3353,33 +3337,7 @@ "array_dims": 0 }, { - "name": "attname", - "not_null": true, - "is_array": false, - "comment": "", - "length": 64, - "is_named_param": false, - "is_func_call": false, - "scope": "", - "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_attribute" - }, - "table_alias": "", - "type": { - "catalog": "", - "schema": "", - "name": "name" - }, - "is_sqlc_slice": false, - "embed_table": null, - "original_name": "", - "unsigned": false, - "array_dims": 0 - }, - { - "name": "atttypid", + "name": "adrelid", "not_null": true, "is_array": false, "comment": "", @@ -3390,7 +3348,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attribute" + "name": "pg_attrdef" }, "table_alias": "", "type": { @@ -3405,33 +3363,7 @@ "array_dims": 0 }, { - "name": "attstattarget", - "not_null": true, - "is_array": false, - "comment": "", - "length": 4, - "is_named_param": false, - "is_func_call": false, - "scope": "", - "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_attribute" - }, - "table_alias": "", - "type": { - "catalog": "", - "schema": "", - "name": "int4" - }, - "is_sqlc_slice": false, - "embed_table": null, - "original_name": "", - "unsigned": false, - "array_dims": 0 - }, - { - "name": "attlen", + "name": "adnum", "not_null": true, "is_array": false, "comment": "", @@ -3442,7 +3374,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attribute" + "name": "pg_attrdef" }, "table_alias": "", "type": { @@ -3457,33 +3389,43 @@ "array_dims": 0 }, { - "name": "attnum", + "name": "adbin", "not_null": true, "is_array": false, "comment": "", - "length": 2, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_attribute" + "name": "pg_attrdef" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "int2" + "name": "pg_node_tree" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - }, + } + ], + "comment": "" + }, + { + "rel": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_attribute" + }, + "columns": [ { - "name": "attndims", + "name": "tableoid", "not_null": true, "is_array": false, "comment": "", @@ -3500,7 +3442,7 @@ "type": { "catalog": "", "schema": "", - "name": "int4" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -3509,7 +3451,7 @@ "array_dims": 0 }, { - "name": "attcacheoff", + "name": "cmax", "not_null": true, "is_array": false, "comment": "", @@ -3526,7 +3468,7 @@ "type": { "catalog": "", "schema": "", - "name": "int4" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -3535,7 +3477,7 @@ "array_dims": 0 }, { - "name": "atttypmod", + "name": "xmax", "not_null": true, "is_array": false, "comment": "", @@ -3552,7 +3494,7 @@ "type": { "catalog": "", "schema": "", - "name": "int4" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -3561,11 +3503,11 @@ "array_dims": 0 }, { - "name": "attbyval", + "name": "cmin", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3578,7 +3520,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -3587,11 +3529,11 @@ "array_dims": 0 }, { - "name": "attalign", + "name": "xmin", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3604,7 +3546,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -3613,11 +3555,11 @@ "array_dims": 0 }, { - "name": "attstorage", + "name": "ctid", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 6, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3630,7 +3572,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "tid" }, "is_sqlc_slice": false, "embed_table": null, @@ -3639,11 +3581,11 @@ "array_dims": 0 }, { - "name": "attcompression", + "name": "attrelid", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3656,7 +3598,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -3665,11 +3607,11 @@ "array_dims": 0 }, { - "name": "attnotnull", + "name": "attname", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3682,7 +3624,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, @@ -3691,11 +3633,11 @@ "array_dims": 0 }, { - "name": "atthasdef", + "name": "atttypid", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3708,7 +3650,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -3717,11 +3659,11 @@ "array_dims": 0 }, { - "name": "atthasmissing", + "name": "attstattarget", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3734,7 +3676,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "int4" }, "is_sqlc_slice": false, "embed_table": null, @@ -3743,11 +3685,11 @@ "array_dims": 0 }, { - "name": "attidentity", + "name": "attlen", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3760,7 +3702,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, @@ -3769,11 +3711,11 @@ "array_dims": 0 }, { - "name": "attgenerated", + "name": "attnum", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 2, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3786,7 +3728,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "int2" }, "is_sqlc_slice": false, "embed_table": null, @@ -3795,11 +3737,11 @@ "array_dims": 0 }, { - "name": "attisdropped", + "name": "attndims", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3812,7 +3754,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "int4" }, "is_sqlc_slice": false, "embed_table": null, @@ -3821,11 +3763,11 @@ "array_dims": 0 }, { - "name": "attislocal", + "name": "attcacheoff", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3838,7 +3780,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "int4" }, "is_sqlc_slice": false, "embed_table": null, @@ -3847,7 +3789,7 @@ "array_dims": 0 }, { - "name": "attinhcount", + "name": "atttypmod", "not_null": true, "is_array": false, "comment": "", @@ -3873,11 +3815,11 @@ "array_dims": 0 }, { - "name": "attcollation", + "name": "attbyval", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3890,7 +3832,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -3899,11 +3841,11 @@ "array_dims": 0 }, { - "name": "attacl", - "not_null": false, - "is_array": true, + "name": "attalign", + "not_null": true, + "is_array": false, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3916,7 +3858,7 @@ "type": { "catalog": "", "schema": "", - "name": "_aclitem" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, @@ -3925,11 +3867,11 @@ "array_dims": 0 }, { - "name": "attoptions", - "not_null": false, - "is_array": true, + "name": "attstorage", + "not_null": true, + "is_array": false, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3942,7 +3884,7 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, @@ -3951,11 +3893,11 @@ "array_dims": 0 }, { - "name": "attfdwoptions", - "not_null": false, - "is_array": true, + "name": "attcompression", + "not_null": true, + "is_array": false, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3968,7 +3910,7 @@ "type": { "catalog": "", "schema": "", - "name": "_text" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, @@ -3977,11 +3919,11 @@ "array_dims": 0 }, { - "name": "attmissingval", - "not_null": false, + "name": "attnotnull", + "not_null": true, "is_array": false, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -3994,43 +3936,33 @@ "type": { "catalog": "", "schema": "", - "name": "anyarray" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - } - ], - "comment": "" - }, - { - "rel": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_auth_members" - }, - "columns": [ + }, { - "name": "tableoid", + "name": "atthasdef", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_auth_members" + "name": "pg_attribute" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -4039,24 +3971,24 @@ "array_dims": 0 }, { - "name": "cmax", + "name": "atthasmissing", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_auth_members" + "name": "pg_attribute" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -4065,24 +3997,24 @@ "array_dims": 0 }, { - "name": "xmax", + "name": "attidentity", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_auth_members" + "name": "pg_attribute" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, @@ -4091,24 +4023,24 @@ "array_dims": 0 }, { - "name": "cmin", + "name": "attgenerated", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_auth_members" + "name": "pg_attribute" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "char" }, "is_sqlc_slice": false, "embed_table": null, @@ -4117,24 +4049,24 @@ "array_dims": 0 }, { - "name": "xmin", + "name": "attisdropped", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_auth_members" + "name": "pg_attribute" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -4143,24 +4075,24 @@ "array_dims": 0 }, { - "name": "ctid", + "name": "attislocal", "not_null": true, "is_array": false, "comment": "", - "length": 6, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_auth_members" + "name": "pg_attribute" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "tid" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -4169,7 +4101,7 @@ "array_dims": 0 }, { - "name": "roleid", + "name": "attinhcount", "not_null": true, "is_array": false, "comment": "", @@ -4180,13 +4112,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_auth_members" + "name": "pg_attribute" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "int4" }, "is_sqlc_slice": false, "embed_table": null, @@ -4195,7 +4127,7 @@ "array_dims": 0 }, { - "name": "member", + "name": "attcollation", "not_null": true, "is_array": false, "comment": "", @@ -4206,7 +4138,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_auth_members" + "name": "pg_attribute" }, "table_alias": "", "type": { @@ -4221,24 +4153,24 @@ "array_dims": 0 }, { - "name": "grantor", - "not_null": true, - "is_array": false, + "name": "attacl", + "not_null": false, + "is_array": true, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_auth_members" + "name": "pg_attribute" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "_aclitem" }, "is_sqlc_slice": false, "embed_table": null, @@ -4247,24 +4179,76 @@ "array_dims": 0 }, { - "name": "admin_option", - "not_null": true, + "name": "attoptions", + "not_null": false, + "is_array": true, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_attribute" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "_text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "attfdwoptions", + "not_null": false, + "is_array": true, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_attribute" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "_text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "attmissingval", + "not_null": false, "is_array": false, "comment": "", - "length": 1, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_auth_members" + "name": "pg_attribute" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "anyarray" }, "is_sqlc_slice": false, "embed_table": null, @@ -4279,7 +4263,7 @@ "rel": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_authid" + "name": "pg_auth_members" }, "columns": [ { @@ -4294,7 +4278,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_authid" + "name": "pg_auth_members" }, "table_alias": "", "type": { @@ -4320,7 +4304,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_authid" + "name": "pg_auth_members" }, "table_alias": "", "type": { @@ -4346,7 +4330,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_authid" + "name": "pg_auth_members" }, "table_alias": "", "type": { @@ -4372,7 +4356,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_authid" + "name": "pg_auth_members" }, "table_alias": "", "type": { @@ -4398,7 +4382,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_authid" + "name": "pg_auth_members" }, "table_alias": "", "type": { @@ -4424,7 +4408,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_authid" + "name": "pg_auth_members" }, "table_alias": "", "type": { @@ -4439,7 +4423,121 @@ "array_dims": 0 }, { - "name": "oid", + "name": "roleid", + "not_null": true, + "is_array": false, + "comment": "", + "length": 4, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_auth_members" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "oid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "member", + "not_null": true, + "is_array": false, + "comment": "", + "length": 4, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_auth_members" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "oid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "grantor", + "not_null": true, + "is_array": false, + "comment": "", + "length": 4, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_auth_members" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "oid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "admin_option", + "not_null": true, + "is_array": false, + "comment": "", + "length": 1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_auth_members" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "bool" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + } + ], + "comment": "" + }, + { + "rel": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_authid" + }, + "columns": [ + { + "name": "tableoid", "not_null": true, "is_array": false, "comment": "", @@ -4465,11 +4563,11 @@ "array_dims": 0 }, { - "name": "rolname", + "name": "cmax", "not_null": true, "is_array": false, "comment": "", - "length": 64, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4482,7 +4580,7 @@ "type": { "catalog": "", "schema": "", - "name": "name" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -4491,11 +4589,11 @@ "array_dims": 0 }, { - "name": "rolsuper", + "name": "xmax", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4508,7 +4606,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -4517,11 +4615,11 @@ "array_dims": 0 }, { - "name": "rolinherit", + "name": "cmin", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4534,7 +4632,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -4543,11 +4641,11 @@ "array_dims": 0 }, { - "name": "rolcreaterole", + "name": "xmin", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4560,7 +4658,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -4569,11 +4667,11 @@ "array_dims": 0 }, { - "name": "rolcreatedb", + "name": "ctid", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 6, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4586,7 +4684,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "tid" }, "is_sqlc_slice": false, "embed_table": null, @@ -4595,11 +4693,11 @@ "array_dims": 0 }, { - "name": "rolcanlogin", + "name": "oid", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4612,7 +4710,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -4621,11 +4719,11 @@ "array_dims": 0 }, { - "name": "rolreplication", + "name": "rolname", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4638,7 +4736,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, @@ -4647,7 +4745,7 @@ "array_dims": 0 }, { - "name": "rolbypassrls", + "name": "rolsuper", "not_null": true, "is_array": false, "comment": "", @@ -4673,37 +4771,11 @@ "array_dims": 0 }, { - "name": "rolconnlimit", + "name": "rolinherit", "not_null": true, "is_array": false, "comment": "", - "length": 4, - "is_named_param": false, - "is_func_call": false, - "scope": "", - "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_authid" - }, - "table_alias": "", - "type": { - "catalog": "", - "schema": "", - "name": "int4" - }, - "is_sqlc_slice": false, - "embed_table": null, - "original_name": "", - "unsigned": false, - "array_dims": 0 - }, - { - "name": "rolpassword", - "not_null": false, - "is_array": false, - "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4716,7 +4788,7 @@ "type": { "catalog": "", "schema": "", - "name": "text" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -4725,11 +4797,11 @@ "array_dims": 0 }, { - "name": "rolvaliduntil", - "not_null": false, + "name": "rolcreaterole", + "not_null": true, "is_array": false, "comment": "", - "length": 8, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -4742,69 +4814,7 @@ "type": { "catalog": "", "schema": "", - "name": "timestamptz" - }, - "is_sqlc_slice": false, - "embed_table": null, - "original_name": "", - "unsigned": false, - "array_dims": 0 - } - ], - "comment": "" - }, - { - "rel": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_available_extension_versions" - }, - "columns": [ - { - "name": "name", - "not_null": false, - "is_array": false, - "comment": "", - "length": 64, - "is_named_param": false, - "is_func_call": false, - "scope": "", - "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_available_extension_versions" - }, - "table_alias": "", - "type": { - "catalog": "", - "schema": "", - "name": "name" - }, - "is_sqlc_slice": false, - "embed_table": null, - "original_name": "", - "unsigned": false, - "array_dims": 0 - }, - { - "name": "version", - "not_null": false, - "is_array": false, - "comment": "", - "length": -1, - "is_named_param": false, - "is_func_call": false, - "scope": "", - "table": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_available_extension_versions" - }, - "table_alias": "", - "type": { - "catalog": "", - "schema": "", - "name": "text" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -4813,8 +4823,8 @@ "array_dims": 0 }, { - "name": "installed", - "not_null": false, + "name": "rolcreatedb", + "not_null": true, "is_array": false, "comment": "", "length": 1, @@ -4824,7 +4834,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extension_versions" + "name": "pg_authid" }, "table_alias": "", "type": { @@ -4839,8 +4849,8 @@ "array_dims": 0 }, { - "name": "superuser", - "not_null": false, + "name": "rolcanlogin", + "not_null": true, "is_array": false, "comment": "", "length": 1, @@ -4850,7 +4860,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extension_versions" + "name": "pg_authid" }, "table_alias": "", "type": { @@ -4865,8 +4875,8 @@ "array_dims": 0 }, { - "name": "trusted", - "not_null": false, + "name": "rolreplication", + "not_null": true, "is_array": false, "comment": "", "length": 1, @@ -4876,7 +4886,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extension_versions" + "name": "pg_authid" }, "table_alias": "", "type": { @@ -4891,8 +4901,8 @@ "array_dims": 0 }, { - "name": "relocatable", - "not_null": false, + "name": "rolbypassrls", + "not_null": true, "is_array": false, "comment": "", "length": 1, @@ -4902,7 +4912,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extension_versions" + "name": "pg_authid" }, "table_alias": "", "type": { @@ -4917,24 +4927,24 @@ "array_dims": 0 }, { - "name": "schema", - "not_null": false, + "name": "rolconnlimit", + "not_null": true, "is_array": false, "comment": "", - "length": 64, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extension_versions" + "name": "pg_authid" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "name" + "name": "int4" }, "is_sqlc_slice": false, "embed_table": null, @@ -4943,9 +4953,9 @@ "array_dims": 0 }, { - "name": "requires", + "name": "rolpassword", "not_null": false, - "is_array": true, + "is_array": false, "comment": "", "length": -1, "is_named_param": false, @@ -4954,13 +4964,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extension_versions" + "name": "pg_authid" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "_name" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -4969,24 +4979,24 @@ "array_dims": 0 }, { - "name": "comment", + "name": "rolvaliduntil", "not_null": false, "is_array": false, "comment": "", - "length": -1, + "length": 8, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extension_versions" + "name": "pg_authid" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "text" + "name": "timestamptz" }, "is_sqlc_slice": false, "embed_table": null, @@ -5001,7 +5011,7 @@ "rel": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extensions" + "name": "pg_available_extension_versions" }, "columns": [ { @@ -5016,7 +5026,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extensions" + "name": "pg_available_extension_versions" }, "table_alias": "", "type": { @@ -5031,7 +5041,7 @@ "array_dims": 0 }, { - "name": "default_version", + "name": "version", "not_null": false, "is_array": false, "comment": "", @@ -5042,7 +5052,7 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extensions" + "name": "pg_available_extension_versions" }, "table_alias": "", "type": { @@ -5057,24 +5067,24 @@ "array_dims": 0 }, { - "name": "installed_version", + "name": "installed", "not_null": false, "is_array": false, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extensions" + "name": "pg_available_extension_versions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "text" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -5083,60 +5093,50 @@ "array_dims": 0 }, { - "name": "comment", + "name": "superuser", "not_null": false, "is_array": false, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_available_extensions" + "name": "pg_available_extension_versions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "text" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - } - ], - "comment": "" - }, - { - "rel": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_backend_memory_contexts" - }, - "columns": [ + }, { - "name": "name", + "name": "trusted", "not_null": false, "is_array": false, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_backend_memory_contexts" + "name": "pg_available_extension_versions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "text" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -5145,24 +5145,24 @@ "array_dims": 0 }, { - "name": "ident", + "name": "relocatable", "not_null": false, "is_array": false, "comment": "", - "length": -1, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_backend_memory_contexts" + "name": "pg_available_extension_versions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "text" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -5171,24 +5171,24 @@ "array_dims": 0 }, { - "name": "parent", + "name": "schema", "not_null": false, "is_array": false, "comment": "", - "length": -1, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_backend_memory_contexts" + "name": "pg_available_extension_versions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "text" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, @@ -5197,24 +5197,24 @@ "array_dims": 0 }, { - "name": "level", + "name": "requires", "not_null": false, - "is_array": false, + "is_array": true, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_backend_memory_contexts" + "name": "pg_available_extension_versions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "int4" + "name": "_name" }, "is_sqlc_slice": false, "embed_table": null, @@ -5223,50 +5223,60 @@ "array_dims": 0 }, { - "name": "total_bytes", + "name": "comment", "not_null": false, "is_array": false, "comment": "", - "length": 8, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_backend_memory_contexts" + "name": "pg_available_extension_versions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "int8" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - }, + } + ], + "comment": "" + }, + { + "rel": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_available_extensions" + }, + "columns": [ { - "name": "total_nblocks", + "name": "name", "not_null": false, "is_array": false, "comment": "", - "length": 8, + "length": 64, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_backend_memory_contexts" + "name": "pg_available_extensions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "int8" + "name": "name" }, "is_sqlc_slice": false, "embed_table": null, @@ -5275,24 +5285,24 @@ "array_dims": 0 }, { - "name": "free_bytes", + "name": "default_version", "not_null": false, "is_array": false, "comment": "", - "length": 8, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_backend_memory_contexts" + "name": "pg_available_extensions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "int8" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -5301,24 +5311,24 @@ "array_dims": 0 }, { - "name": "free_chunks", + "name": "installed_version", "not_null": false, "is_array": false, "comment": "", - "length": 8, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_backend_memory_contexts" + "name": "pg_available_extensions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "int8" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -5327,24 +5337,24 @@ "array_dims": 0 }, { - "name": "used_bytes", + "name": "comment", "not_null": false, "is_array": false, "comment": "", - "length": 8, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_backend_memory_contexts" + "name": "pg_available_extensions" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "int8" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -5359,28 +5369,28 @@ "rel": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_cast" + "name": "pg_backend_memory_contexts" }, "columns": [ { - "name": "tableoid", - "not_null": true, + "name": "name", + "not_null": false, "is_array": false, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_cast" + "name": "pg_backend_memory_contexts" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -5389,24 +5399,24 @@ "array_dims": 0 }, { - "name": "cmax", - "not_null": true, + "name": "ident", + "not_null": false, "is_array": false, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_cast" + "name": "pg_backend_memory_contexts" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -5415,24 +5425,24 @@ "array_dims": 0 }, { - "name": "xmax", - "not_null": true, + "name": "parent", + "not_null": false, "is_array": false, "comment": "", - "length": 4, + "length": -1, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_cast" + "name": "pg_backend_memory_contexts" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "text" }, "is_sqlc_slice": false, "embed_table": null, @@ -5441,8 +5451,8 @@ "array_dims": 0 }, { - "name": "cmin", - "not_null": true, + "name": "level", + "not_null": false, "is_array": false, "comment": "", "length": 4, @@ -5452,13 +5462,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_cast" + "name": "pg_backend_memory_contexts" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "int4" }, "is_sqlc_slice": false, "embed_table": null, @@ -5467,24 +5477,24 @@ "array_dims": 0 }, { - "name": "xmin", - "not_null": true, + "name": "total_bytes", + "not_null": false, "is_array": false, "comment": "", - "length": 4, + "length": 8, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_cast" + "name": "pg_backend_memory_contexts" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "int8" }, "is_sqlc_slice": false, "embed_table": null, @@ -5493,24 +5503,24 @@ "array_dims": 0 }, { - "name": "ctid", - "not_null": true, + "name": "total_nblocks", + "not_null": false, "is_array": false, "comment": "", - "length": 6, + "length": 8, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_cast" + "name": "pg_backend_memory_contexts" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "tid" + "name": "int8" }, "is_sqlc_slice": false, "embed_table": null, @@ -5519,24 +5529,24 @@ "array_dims": 0 }, { - "name": "oid", - "not_null": true, + "name": "free_bytes", + "not_null": false, "is_array": false, "comment": "", - "length": 4, + "length": 8, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_cast" + "name": "pg_backend_memory_contexts" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "int8" }, "is_sqlc_slice": false, "embed_table": null, @@ -5545,24 +5555,24 @@ "array_dims": 0 }, { - "name": "castsource", - "not_null": true, + "name": "free_chunks", + "not_null": false, "is_array": false, "comment": "", - "length": 4, + "length": 8, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_cast" + "name": "pg_backend_memory_contexts" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "int8" }, "is_sqlc_slice": false, "embed_table": null, @@ -5571,33 +5581,43 @@ "array_dims": 0 }, { - "name": "casttarget", - "not_null": true, + "name": "used_bytes", + "not_null": false, "is_array": false, "comment": "", - "length": 4, + "length": 8, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_cast" + "name": "pg_backend_memory_contexts" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "int8" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - }, + } + ], + "comment": "" + }, + { + "rel": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_cast" + }, + "columns": [ { - "name": "castfunc", + "name": "tableoid", "not_null": true, "is_array": false, "comment": "", @@ -5623,11 +5643,11 @@ "array_dims": 0 }, { - "name": "castcontext", + "name": "cmax", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -5640,7 +5660,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5649,11 +5669,11 @@ "array_dims": 0 }, { - "name": "castmethod", + "name": "xmax", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -5666,26 +5686,16 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, "original_name": "", "unsigned": false, "array_dims": 0 - } - ], - "comment": "" - }, - { - "rel": { - "catalog": "pg_catalog", - "schema": "pg_catalog", - "name": "pg_class" - }, - "columns": [ + }, { - "name": "tableoid", + "name": "cmin", "not_null": true, "is_array": false, "comment": "", @@ -5696,13 +5706,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_class" + "name": "pg_cast" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5711,7 +5721,7 @@ "array_dims": 0 }, { - "name": "cmax", + "name": "xmin", "not_null": true, "is_array": false, "comment": "", @@ -5722,13 +5732,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_class" + "name": "pg_cast" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5737,7 +5747,33 @@ "array_dims": 0 }, { - "name": "xmax", + "name": "ctid", + "not_null": true, + "is_array": false, + "comment": "", + "length": 6, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_cast" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "tid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "oid", "not_null": true, "is_array": false, "comment": "", @@ -5748,13 +5784,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_class" + "name": "pg_cast" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5763,7 +5799,7 @@ "array_dims": 0 }, { - "name": "cmin", + "name": "castsource", "not_null": true, "is_array": false, "comment": "", @@ -5774,13 +5810,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_class" + "name": "pg_cast" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "cid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5789,7 +5825,7 @@ "array_dims": 0 }, { - "name": "xmin", + "name": "casttarget", "not_null": true, "is_array": false, "comment": "", @@ -5800,13 +5836,13 @@ "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_class" + "name": "pg_cast" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "xid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5815,24 +5851,24 @@ "array_dims": 0 }, { - "name": "ctid", + "name": "castfunc", "not_null": true, "is_array": false, "comment": "", - "length": 6, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", "table": { "catalog": "pg_catalog", "schema": "pg_catalog", - "name": "pg_class" + "name": "pg_cast" }, "table_alias": "", "type": { "catalog": "", "schema": "", - "name": "tid" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5841,7 +5877,69 @@ "array_dims": 0 }, { - "name": "oid", + "name": "castcontext", + "not_null": true, + "is_array": false, + "comment": "", + "length": 1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_cast" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "char" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "castmethod", + "not_null": true, + "is_array": false, + "comment": "", + "length": 1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_cast" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "char" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + } + ], + "comment": "" + }, + { + "rel": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_class" + }, + "columns": [ + { + "name": "tableoid", "not_null": true, "is_array": false, "comment": "", @@ -5867,11 +5965,11 @@ "array_dims": 0 }, { - "name": "relname", + "name": "cmax", "not_null": true, "is_array": false, "comment": "", - "length": 64, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -5884,7 +5982,7 @@ "type": { "catalog": "", "schema": "", - "name": "name" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5893,7 +5991,7 @@ "array_dims": 0 }, { - "name": "relnamespace", + "name": "xmax", "not_null": true, "is_array": false, "comment": "", @@ -5910,7 +6008,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5919,7 +6017,7 @@ "array_dims": 0 }, { - "name": "reltype", + "name": "cmin", "not_null": true, "is_array": false, "comment": "", @@ -5936,7 +6034,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "cid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5945,7 +6043,7 @@ "array_dims": 0 }, { - "name": "reloftype", + "name": "xmin", "not_null": true, "is_array": false, "comment": "", @@ -5962,7 +6060,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "xid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5971,11 +6069,11 @@ "array_dims": 0 }, { - "name": "relowner", + "name": "ctid", "not_null": true, "is_array": false, "comment": "", - "length": 4, + "length": 6, "is_named_param": false, "is_func_call": false, "scope": "", @@ -5988,7 +6086,7 @@ "type": { "catalog": "", "schema": "", - "name": "oid" + "name": "tid" }, "is_sqlc_slice": false, "embed_table": null, @@ -5997,7 +6095,7 @@ "array_dims": 0 }, { - "name": "relam", + "name": "oid", "not_null": true, "is_array": false, "comment": "", @@ -6023,7 +6121,33 @@ "array_dims": 0 }, { - "name": "relfilenode", + "name": "relname", + "not_null": true, + "is_array": false, + "comment": "", + "length": 64, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_class" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "name" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "relnamespace", "not_null": true, "is_array": false, "comment": "", @@ -6049,7 +6173,7 @@ "array_dims": 0 }, { - "name": "reltablespace", + "name": "reltype", "not_null": true, "is_array": false, "comment": "", @@ -6075,7 +6199,7 @@ "array_dims": 0 }, { - "name": "relpages", + "name": "reloftype", "not_null": true, "is_array": false, "comment": "", @@ -6092,7 +6216,7 @@ "type": { "catalog": "", "schema": "", - "name": "int4" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -6101,7 +6225,7 @@ "array_dims": 0 }, { - "name": "reltuples", + "name": "relowner", "not_null": true, "is_array": false, "comment": "", @@ -6118,7 +6242,7 @@ "type": { "catalog": "", "schema": "", - "name": "float4" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -6127,7 +6251,7 @@ "array_dims": 0 }, { - "name": "relallvisible", + "name": "relam", "not_null": true, "is_array": false, "comment": "", @@ -6144,7 +6268,7 @@ "type": { "catalog": "", "schema": "", - "name": "int4" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -6153,7 +6277,7 @@ "array_dims": 0 }, { - "name": "reltoastrelid", + "name": "relfilenode", "not_null": true, "is_array": false, "comment": "", @@ -6179,11 +6303,11 @@ "array_dims": 0 }, { - "name": "relhasindex", + "name": "reltablespace", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6196,7 +6320,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -6205,11 +6329,11 @@ "array_dims": 0 }, { - "name": "relisshared", + "name": "relpages", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6222,7 +6346,7 @@ "type": { "catalog": "", "schema": "", - "name": "bool" + "name": "int4" }, "is_sqlc_slice": false, "embed_table": null, @@ -6231,11 +6355,11 @@ "array_dims": 0 }, { - "name": "relpersistence", + "name": "reltuples", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6248,7 +6372,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "float4" }, "is_sqlc_slice": false, "embed_table": null, @@ -6257,11 +6381,11 @@ "array_dims": 0 }, { - "name": "relkind", + "name": "relallvisible", "not_null": true, "is_array": false, "comment": "", - "length": 1, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6274,7 +6398,7 @@ "type": { "catalog": "", "schema": "", - "name": "char" + "name": "int4" }, "is_sqlc_slice": false, "embed_table": null, @@ -6283,11 +6407,11 @@ "array_dims": 0 }, { - "name": "relnatts", + "name": "reltoastrelid", "not_null": true, "is_array": false, "comment": "", - "length": 2, + "length": 4, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6300,7 +6424,7 @@ "type": { "catalog": "", "schema": "", - "name": "int2" + "name": "oid" }, "is_sqlc_slice": false, "embed_table": null, @@ -6309,11 +6433,11 @@ "array_dims": 0 }, { - "name": "relchecks", + "name": "relhasindex", "not_null": true, "is_array": false, "comment": "", - "length": 2, + "length": 1, "is_named_param": false, "is_func_call": false, "scope": "", @@ -6326,7 +6450,7 @@ "type": { "catalog": "", "schema": "", - "name": "int2" + "name": "bool" }, "is_sqlc_slice": false, "embed_table": null, @@ -6335,7 +6459,137 @@ "array_dims": 0 }, { - "name": "relhasrules", + "name": "relisshared", + "not_null": true, + "is_array": false, + "comment": "", + "length": 1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_class" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "bool" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "relpersistence", + "not_null": true, + "is_array": false, + "comment": "", + "length": 1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_class" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "char" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "relkind", + "not_null": true, + "is_array": false, + "comment": "", + "length": 1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_class" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "char" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "relnatts", + "not_null": true, + "is_array": false, + "comment": "", + "length": 2, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_class" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "int2" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "relchecks", + "not_null": true, + "is_array": false, + "comment": "", + "length": 2, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "pg_catalog", + "schema": "pg_catalog", + "name": "pg_class" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "int2" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "relhasrules", "not_null": true, "is_array": false, "comment": "", @@ -72558,6 +72812,1264 @@ "comments": [], "filename": "queries.sql", "insert_into_table": null + }, + { + "text": "\nINSERT INTO links (endpoint_url, dest_url, oid)\nVALUES ($1, $2, $3)\nRETURNING lid, endpoint_url, dest_url, oid, created_at", + "name": "CreateLink", + "cmd": ":one", + "columns": [ + { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "endpoint_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "endpoint_url", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "dest_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "dest_url", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "oid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "oid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "created_at", + "not_null": false, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "pg_catalog", + "name": "timestamp" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "created_at", + "unsigned": false, + "array_dims": 0 + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "endpoint_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "public", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "endpoint_url", + "unsigned": false, + "array_dims": 0 + } + }, + { + "number": 2, + "column": { + "name": "dest_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "public", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "dest_url", + "unsigned": false, + "array_dims": 0 + } + }, + { + "number": 3, + "column": { + "name": "oid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "public", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "oid", + "unsigned": false, + "array_dims": 0 + } + } + ], + "comments": [ + " Link Queries" + ], + "filename": "queries.sql", + "insert_into_table": { + "catalog": "", + "schema": "", + "name": "links" + } + }, + { + "text": "SELECT lid, endpoint_url, dest_url, oid, created_at FROM links WHERE lid = $1", + "name": "GetLinkByLID", + "cmd": ":one", + "columns": [ + { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "endpoint_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "endpoint_url", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "dest_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "dest_url", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "oid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "oid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "created_at", + "not_null": false, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "pg_catalog", + "name": "timestamp" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "created_at", + "unsigned": false, + "array_dims": 0 + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + } + } + ], + "comments": [], + "filename": "queries.sql", + "insert_into_table": null + }, + { + "text": "SELECT lid, endpoint_url, dest_url, oid, created_at FROM links WHERE endpoint_url = $1", + "name": "GetLinkByEndpointURL", + "cmd": ":one", + "columns": [ + { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "endpoint_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "endpoint_url", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "dest_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "dest_url", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "oid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "oid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "created_at", + "not_null": false, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "pg_catalog", + "name": "timestamp" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "created_at", + "unsigned": false, + "array_dims": 0 + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "endpoint_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "endpoint_url", + "unsigned": false, + "array_dims": 0 + } + } + ], + "comments": [], + "filename": "queries.sql", + "insert_into_table": null + }, + { + "text": "UPDATE links\nSET endpoint_url = COALESCE($2, endpoint_url),\n dest_url = COALESCE($3, dest_url)\nWHERE lid = $1\nRETURNING lid, endpoint_url, dest_url, oid, created_at", + "name": "UpdateLink", + "cmd": ":one", + "columns": [ + { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "endpoint_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "endpoint_url", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "dest_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "dest_url", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "oid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "oid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "created_at", + "not_null": false, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "pg_catalog", + "name": "timestamp" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "created_at", + "unsigned": false, + "array_dims": 0 + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + } + }, + { + "number": 2, + "column": { + "name": "endpoint_url", + "not_null": false, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": true, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "public", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "endpoint_url", + "unsigned": false, + "array_dims": 0 + } + }, + { + "number": 3, + "column": { + "name": "dest_url", + "not_null": false, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": true, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "public", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "dest_url", + "unsigned": false, + "array_dims": 0 + } + } + ], + "comments": [], + "filename": "queries.sql", + "insert_into_table": null + }, + { + "text": "DELETE FROM links WHERE lid = $1", + "name": "DeleteLink", + "cmd": ":exec", + "columns": [], + "params": [ + { + "number": 1, + "column": { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + } + } + ], + "comments": [], + "filename": "queries.sql", + "insert_into_table": null + }, + { + "text": "SELECT lid, endpoint_url, dest_url, oid, created_at FROM links WHERE oid = $1 ORDER BY created_at DESC", + "name": "ListLinksByOrg", + "cmd": ":many", + "columns": [ + { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "endpoint_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "endpoint_url", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "dest_url", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "text" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "dest_url", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "oid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "oid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "created_at", + "not_null": false, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "pg_catalog", + "name": "timestamp" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "created_at", + "unsigned": false, + "array_dims": 0 + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "oid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "links" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "oid", + "unsigned": false, + "array_dims": 0 + } + } + ], + "comments": [], + "filename": "queries.sql", + "insert_into_table": null + }, + { + "text": "INSERT INTO link_visits (lid, uid)\nVALUES ($1, $2)\nRETURNING lvid, lid, uid, created_at", + "name": "LogLinkVisit", + "cmd": ":one", + "columns": [ + { + "name": "lvid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "link_visits" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lvid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "link_visits" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "uid", + "not_null": false, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "link_visits" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "uid", + "unsigned": false, + "array_dims": 0 + }, + { + "name": "created_at", + "not_null": false, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "link_visits" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "pg_catalog", + "name": "timestamp" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "created_at", + "unsigned": false, + "array_dims": 0 + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "public", + "name": "link_visits" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + } + }, + { + "number": 2, + "column": { + "name": "uid", + "not_null": false, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "public", + "name": "link_visits" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "uid", + "unsigned": false, + "array_dims": 0 + } + } + ], + "comments": [], + "filename": "queries.sql", + "insert_into_table": { + "catalog": "", + "schema": "", + "name": "link_visits" + } + }, + { + "text": "SELECT COUNT(*) FROM link_visits WHERE lid = $1", + "name": "GetTotalVisits", + "cmd": ":one", + "columns": [ + { + "name": "count", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": true, + "scope": "", + "table": null, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "bigint" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "", + "unsigned": false, + "array_dims": 0 + } + ], + "params": [ + { + "number": 1, + "column": { + "name": "lid", + "not_null": true, + "is_array": false, + "comment": "", + "length": -1, + "is_named_param": false, + "is_func_call": false, + "scope": "", + "table": { + "catalog": "", + "schema": "", + "name": "link_visits" + }, + "table_alias": "", + "type": { + "catalog": "", + "schema": "", + "name": "uuid" + }, + "is_sqlc_slice": false, + "embed_table": null, + "original_name": "lid", + "unsigned": false, + "array_dims": 0 + } + } + ], + "comments": [], + "filename": "queries.sql", + "insert_into_table": null } ], "sqlc_version": "v1.30.0", diff --git a/go.mod b/go.mod index 848d0b0..7bd1a22 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,8 @@ require ( github.com/swaggo/swag v1.16.6 github.com/testcontainers/testcontainers-go v0.40.0 github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 + github.com/yeqown/go-qrcode/v2 v2.2.5 + github.com/yeqown/go-qrcode/writer/standard v1.3.0 golang.org/x/crypto v0.47.0 golang.org/x/oauth2 v0.34.0 ) @@ -39,6 +41,7 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/ebitengine/purego v0.8.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fogleman/gg v1.3.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect @@ -46,6 +49,7 @@ require ( github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/spec v0.20.6 // indirect github.com/go-openapi/swag v0.19.15 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect @@ -75,6 +79,7 @@ require ( github.com/swaggo/files/v2 v2.0.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect + github.com/yeqown/reedsolomon v1.0.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect @@ -83,6 +88,7 @@ require ( go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect + golang.org/x/image v0.10.0 // indirect golang.org/x/mod v0.31.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.40.0 // indirect diff --git a/go.sum b/go.sum index c5248b8..45ee0bd 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,8 @@ github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0o github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -68,6 +70,8 @@ github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63Y github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= @@ -168,6 +172,13 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/yeqown/go-qrcode/v2 v2.2.5 h1:HCOe2bSjkhZyYoyyNaXNzh4DJZll6inVJQQw+8228Zk= +github.com/yeqown/go-qrcode/v2 v2.2.5/go.mod h1:uHpt9CM0V1HeXLz+Wg5MN50/sI/fQhfkZlOM+cOTHxw= +github.com/yeqown/go-qrcode/writer/standard v1.3.0 h1:chdyhEfRtUPgQtuPeaWVGQ/TQx4rE1PqeoW3U+53t34= +github.com/yeqown/go-qrcode/writer/standard v1.3.0/go.mod h1:O4MbzsotGCvy8upYPCR91j81dr5XLT7heuljcNXW+oQ= +github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0= +github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= @@ -190,32 +201,64 @@ go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJr go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/image v0.10.0 h1:gXjUUtwtx5yOE0VKWq1CH4IJAClq4UGgUA3i+rpON9M= +golang.org/x/image v0.10.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M= diff --git a/internal/database/mocks/Querier.go b/internal/database/mocks/Querier.go index 3baf283..fa0b713 100644 --- a/internal/database/mocks/Querier.go +++ b/internal/database/mocks/Querier.go @@ -110,6 +110,34 @@ func (_m *Querier) CreateEvent(ctx context.Context, arg database.CreateEventPara return r0, r1 } +// CreateLink provides a mock function with given fields: ctx, arg +func (_m *Querier) CreateLink(ctx context.Context, arg database.CreateLinkParams) (database.Link, error) { + ret := _m.Called(ctx, arg) + + if len(ret) == 0 { + panic("no return value specified for CreateLink") + } + + var r0 database.Link + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, database.CreateLinkParams) (database.Link, error)); ok { + return rf(ctx, arg) + } + if rf, ok := ret.Get(0).(func(context.Context, database.CreateLinkParams) database.Link); ok { + r0 = rf(ctx, arg) + } else { + r0 = ret.Get(0).(database.Link) + } + + if rf, ok := ret.Get(1).(func(context.Context, database.CreateLinkParams) error); ok { + r1 = rf(ctx, arg) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // CreateOrganization provides a mock function with given fields: ctx, name func (_m *Querier) CreateOrganization(ctx context.Context, name string) (database.Organization, error) { ret := _m.Called(ctx, name) @@ -184,6 +212,24 @@ func (_m *Querier) DeleteEvent(ctx context.Context, eid uuid.UUID) error { return r0 } +// DeleteLink provides a mock function with given fields: ctx, lid +func (_m *Querier) DeleteLink(ctx context.Context, lid uuid.UUID) error { + ret := _m.Called(ctx, lid) + + if len(ret) == 0 { + panic("no return value specified for DeleteLink") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) error); ok { + r0 = rf(ctx, lid) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // DeleteOrganization provides a mock function with given fields: ctx, oid func (_m *Querier) DeleteOrganization(ctx context.Context, oid uuid.UUID) error { ret := _m.Called(ctx, oid) @@ -306,6 +352,62 @@ func (_m *Querier) GetEventRegistrations(ctx context.Context, eid uuid.UUID) ([] return r0, r1 } +// GetLinkByEndpointURL provides a mock function with given fields: ctx, endpointUrl +func (_m *Querier) GetLinkByEndpointURL(ctx context.Context, endpointUrl string) (database.Link, error) { + ret := _m.Called(ctx, endpointUrl) + + if len(ret) == 0 { + panic("no return value specified for GetLinkByEndpointURL") + } + + var r0 database.Link + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (database.Link, error)); ok { + return rf(ctx, endpointUrl) + } + if rf, ok := ret.Get(0).(func(context.Context, string) database.Link); ok { + r0 = rf(ctx, endpointUrl) + } else { + r0 = ret.Get(0).(database.Link) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, endpointUrl) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetLinkByLID provides a mock function with given fields: ctx, lid +func (_m *Querier) GetLinkByLID(ctx context.Context, lid uuid.UUID) (database.Link, error) { + ret := _m.Called(ctx, lid) + + if len(ret) == 0 { + panic("no return value specified for GetLinkByLID") + } + + var r0 database.Link + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) (database.Link, error)); ok { + return rf(ctx, lid) + } + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) database.Link); ok { + r0 = rf(ctx, lid) + } else { + r0 = ret.Get(0).(database.Link) + } + + if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID) error); ok { + r1 = rf(ctx, lid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetOrgMembers provides a mock function with given fields: ctx, oid func (_m *Querier) GetOrgMembers(ctx context.Context, oid uuid.UUID) ([]database.GetOrgMembersRow, error) { ret := _m.Called(ctx, oid) @@ -364,6 +466,34 @@ func (_m *Querier) GetOrganizationByID(ctx context.Context, oid uuid.UUID) (data return r0, r1 } +// GetTotalVisits provides a mock function with given fields: ctx, lid +func (_m *Querier) GetTotalVisits(ctx context.Context, lid uuid.UUID) (int64, error) { + ret := _m.Called(ctx, lid) + + if len(ret) == 0 { + panic("no return value specified for GetTotalVisits") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) (int64, error)); ok { + return rf(ctx, lid) + } + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) int64); ok { + r0 = rf(ctx, lid) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID) error); ok { + r1 = rf(ctx, lid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetUserByEmail provides a mock function with given fields: ctx, personalEmail func (_m *Querier) GetUserByEmail(ctx context.Context, personalEmail pgtype.Text) (database.User, error) { ret := _m.Called(ctx, personalEmail) @@ -626,6 +756,36 @@ func (_m *Querier) ListEventsByOrg(ctx context.Context, arg database.ListEventsB return r0, r1 } +// ListLinksByOrg provides a mock function with given fields: ctx, oid +func (_m *Querier) ListLinksByOrg(ctx context.Context, oid uuid.UUID) ([]database.Link, error) { + ret := _m.Called(ctx, oid) + + if len(ret) == 0 { + panic("no return value specified for ListLinksByOrg") + } + + var r0 []database.Link + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) ([]database.Link, error)); ok { + return rf(ctx, oid) + } + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) []database.Link); ok { + r0 = rf(ctx, oid) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]database.Link) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID) error); ok { + r1 = rf(ctx, oid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // ListOrganizations provides a mock function with given fields: ctx, arg func (_m *Querier) ListOrganizations(ctx context.Context, arg database.ListOrganizationsParams) ([]database.Organization, error) { ret := _m.Called(ctx, arg) @@ -686,6 +846,34 @@ func (_m *Querier) ListUsers(ctx context.Context, arg database.ListUsersParams) return r0, r1 } +// LogLinkVisit provides a mock function with given fields: ctx, arg +func (_m *Querier) LogLinkVisit(ctx context.Context, arg database.LogLinkVisitParams) (database.LinkVisit, error) { + ret := _m.Called(ctx, arg) + + if len(ret) == 0 { + panic("no return value specified for LogLinkVisit") + } + + var r0 database.LinkVisit + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, database.LogLinkVisitParams) (database.LinkVisit, error)); ok { + return rf(ctx, arg) + } + if rf, ok := ret.Get(0).(func(context.Context, database.LogLinkVisitParams) database.LinkVisit); ok { + r0 = rf(ctx, arg) + } else { + r0 = ret.Get(0).(database.LinkVisit) + } + + if rf, ok := ret.Get(1).(func(context.Context, database.LogLinkVisitParams) error); ok { + r1 = rf(ctx, arg) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // RegisterForEvent provides a mock function with given fields: ctx, arg func (_m *Querier) RegisterForEvent(ctx context.Context, arg database.RegisterForEventParams) error { ret := _m.Called(ctx, arg) @@ -804,6 +992,34 @@ func (_m *Querier) UpdateEvent(ctx context.Context, arg database.UpdateEventPara return r0, r1 } +// UpdateLink provides a mock function with given fields: ctx, arg +func (_m *Querier) UpdateLink(ctx context.Context, arg database.UpdateLinkParams) (database.Link, error) { + ret := _m.Called(ctx, arg) + + if len(ret) == 0 { + panic("no return value specified for UpdateLink") + } + + var r0 database.Link + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, database.UpdateLinkParams) (database.Link, error)); ok { + return rf(ctx, arg) + } + if rf, ok := ret.Get(0).(func(context.Context, database.UpdateLinkParams) database.Link); ok { + r0 = rf(ctx, arg) + } else { + r0 = ret.Get(0).(database.Link) + } + + if rf, ok := ret.Get(1).(func(context.Context, database.UpdateLinkParams) error); ok { + r1 = rf(ctx, arg) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // UpdateOrganization provides a mock function with given fields: ctx, arg func (_m *Querier) UpdateOrganization(ctx context.Context, arg database.UpdateOrganizationParams) (database.Organization, error) { ret := _m.Called(ctx, arg) diff --git a/internal/database/models.go b/internal/database/models.go index 16ba637..4363da1 100644 --- a/internal/database/models.go +++ b/internal/database/models.go @@ -90,6 +90,21 @@ type EventRegistration struct { DateRegistered pgtype.Date `json:"date_registered"` } +type Link struct { + Lid uuid.UUID `json:"lid"` + EndpointUrl string `json:"endpoint_url"` + DestUrl string `json:"dest_url"` + Oid uuid.UUID `json:"oid"` + CreatedAt pgtype.Timestamp `json:"created_at"` +} + +type LinkVisit struct { + Lvid uuid.UUID `json:"lvid"` + Lid uuid.UUID `json:"lid"` + Uid pgtype.UUID `json:"uid"` + CreatedAt pgtype.Timestamp `json:"created_at"` +} + type OrgMember struct { Uid uuid.UUID `json:"uid"` Oid uuid.UUID `json:"oid"` diff --git a/internal/database/querier.go b/internal/database/querier.go index 1a39c35..7284a32 100644 --- a/internal/database/querier.go +++ b/internal/database/querier.go @@ -16,17 +16,23 @@ type Querier interface { AddOrgMember(ctx context.Context, arg AddOrgMemberParams) error CreateBotToken(ctx context.Context, arg CreateBotTokenParams) (BotToken, error) CreateEvent(ctx context.Context, arg CreateEventParams) (Event, error) + // Link Queries + CreateLink(ctx context.Context, arg CreateLinkParams) (Link, error) CreateOrganization(ctx context.Context, name string) (Organization, error) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) DeleteEvent(ctx context.Context, eid uuid.UUID) error + DeleteLink(ctx context.Context, lid uuid.UUID) error DeleteOrganization(ctx context.Context, oid uuid.UUID) error DeleteUser(ctx context.Context, uid uuid.UUID) error // Bot Token Queries GetBotTokenByID(ctx context.Context, tokenID uuid.UUID) (BotToken, error) GetEventByID(ctx context.Context, eid uuid.UUID) (Event, error) GetEventRegistrations(ctx context.Context, eid uuid.UUID) ([]GetEventRegistrationsRow, error) + GetLinkByEndpointURL(ctx context.Context, endpointUrl string) (Link, error) + GetLinkByLID(ctx context.Context, lid uuid.UUID) (Link, error) GetOrgMembers(ctx context.Context, oid uuid.UUID) ([]GetOrgMembersRow, error) GetOrganizationByID(ctx context.Context, oid uuid.UUID) (Organization, error) + GetTotalVisits(ctx context.Context, lid uuid.UUID) (int64, error) GetUserByEmail(ctx context.Context, personalEmail pgtype.Text) (User, error) GetUserByID(ctx context.Context, uid uuid.UUID) (User, error) GetUserEvents(ctx context.Context, uid uuid.UUID) ([]GetUserEventsRow, error) @@ -36,14 +42,17 @@ type Querier interface { ListBotTokens(ctx context.Context) ([]ListBotTokensRow, error) ListEvents(ctx context.Context, arg ListEventsParams) ([]Event, error) ListEventsByOrg(ctx context.Context, arg ListEventsByOrgParams) ([]Event, error) + ListLinksByOrg(ctx context.Context, oid uuid.UUID) ([]Link, error) ListOrganizations(ctx context.Context, arg ListOrganizationsParams) ([]Organization, error) ListUsers(ctx context.Context, arg ListUsersParams) ([]User, error) + LogLinkVisit(ctx context.Context, arg LogLinkVisitParams) (LinkVisit, error) RegisterForEvent(ctx context.Context, arg RegisterForEventParams) error RemoveOrgMember(ctx context.Context, arg RemoveOrgMemberParams) error RevokeBotToken(ctx context.Context, tokenID uuid.UUID) error UnregisterFromEvent(ctx context.Context, arg UnregisterFromEventParams) error UpdateBotTokenLastUsed(ctx context.Context, tokenID uuid.UUID) error UpdateEvent(ctx context.Context, arg UpdateEventParams) (Event, error) + UpdateLink(ctx context.Context, arg UpdateLinkParams) (Link, error) UpdateOrganization(ctx context.Context, arg UpdateOrganizationParams) (Organization, error) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error) } diff --git a/internal/database/queries.sql b/internal/database/queries.sql index 3344cfd..9b8c28f 100644 --- a/internal/database/queries.sql +++ b/internal/database/queries.sql @@ -166,3 +166,37 @@ UPDATE bot_tokens SET is_active = false WHERE token_id = $1; -- name: UpdateBotTokenLastUsed :exec UPDATE bot_tokens SET last_used_at = CURRENT_TIMESTAMP WHERE token_id = $1; + +-- Link Queries + +-- name: CreateLink :one +INSERT INTO links (endpoint_url, dest_url, oid) +VALUES ($1, $2, $3) +RETURNING *; + +-- name: GetLinkByLID :one +SELECT * FROM links WHERE lid = $1; + +-- name: GetLinkByEndpointURL :one +SELECT * FROM links WHERE endpoint_url = $1; + +-- name: UpdateLink :one +UPDATE links +SET endpoint_url = COALESCE(sqlc.narg('endpoint_url'), endpoint_url), + dest_url = COALESCE(sqlc.narg('dest_url'), dest_url) +WHERE lid = $1 +RETURNING *; + +-- name: DeleteLink :exec +DELETE FROM links WHERE lid = $1; + +-- name: ListLinksByOrg :many +SELECT * FROM links WHERE oid = $1 ORDER BY created_at DESC; + +-- name: LogLinkVisit :one +INSERT INTO link_visits (lid, uid) +VALUES ($1, $2) +RETURNING *; + +-- name: GetTotalVisits :one +SELECT COUNT(*) FROM link_visits WHERE lid = $1; diff --git a/internal/database/queries.sql.go b/internal/database/queries.sql.go index 457aa5b..a8a4824 100644 --- a/internal/database/queries.sql.go +++ b/internal/database/queries.sql.go @@ -105,6 +105,33 @@ func (q *Queries) CreateEvent(ctx context.Context, arg CreateEventParams) (Event return i, err } +const createLink = `-- name: CreateLink :one + +INSERT INTO links (endpoint_url, dest_url, oid) +VALUES ($1, $2, $3) +RETURNING lid, endpoint_url, dest_url, oid, created_at +` + +type CreateLinkParams struct { + EndpointUrl string `json:"endpoint_url"` + DestUrl string `json:"dest_url"` + Oid uuid.UUID `json:"oid"` +} + +// Link Queries +func (q *Queries) CreateLink(ctx context.Context, arg CreateLinkParams) (Link, error) { + row := q.db.QueryRow(ctx, createLink, arg.EndpointUrl, arg.DestUrl, arg.Oid) + var i Link + err := row.Scan( + &i.Lid, + &i.EndpointUrl, + &i.DestUrl, + &i.Oid, + &i.CreatedAt, + ) + return i, err +} + const createOrganization = `-- name: CreateOrganization :one INSERT INTO organizations (name) VALUES ($1) @@ -174,6 +201,15 @@ func (q *Queries) DeleteEvent(ctx context.Context, eid uuid.UUID) error { return err } +const deleteLink = `-- name: DeleteLink :exec +DELETE FROM links WHERE lid = $1 +` + +func (q *Queries) DeleteLink(ctx context.Context, lid uuid.UUID) error { + _, err := q.db.Exec(ctx, deleteLink, lid) + return err +} + const deleteOrganization = `-- name: DeleteOrganization :exec DELETE FROM organizations WHERE oid = $1 ` @@ -290,6 +326,40 @@ func (q *Queries) GetEventRegistrations(ctx context.Context, eid uuid.UUID) ([]G return items, nil } +const getLinkByEndpointURL = `-- name: GetLinkByEndpointURL :one +SELECT lid, endpoint_url, dest_url, oid, created_at FROM links WHERE endpoint_url = $1 +` + +func (q *Queries) GetLinkByEndpointURL(ctx context.Context, endpointUrl string) (Link, error) { + row := q.db.QueryRow(ctx, getLinkByEndpointURL, endpointUrl) + var i Link + err := row.Scan( + &i.Lid, + &i.EndpointUrl, + &i.DestUrl, + &i.Oid, + &i.CreatedAt, + ) + return i, err +} + +const getLinkByLID = `-- name: GetLinkByLID :one +SELECT lid, endpoint_url, dest_url, oid, created_at FROM links WHERE lid = $1 +` + +func (q *Queries) GetLinkByLID(ctx context.Context, lid uuid.UUID) (Link, error) { + row := q.db.QueryRow(ctx, getLinkByLID, lid) + var i Link + err := row.Scan( + &i.Lid, + &i.EndpointUrl, + &i.DestUrl, + &i.Oid, + &i.CreatedAt, + ) + return i, err +} + const getOrgMembers = `-- name: GetOrgMembers :many SELECT u.uid, u.first_name, u.last_name, u.personal_email, u.school_email, u.phone, u.grad_year, u.role, u.date_created, u.date_modified, om.is_admin, om.date_joined, om.last_active FROM users u @@ -364,6 +434,17 @@ func (q *Queries) GetOrganizationByID(ctx context.Context, oid uuid.UUID) (Organ return i, err } +const getTotalVisits = `-- name: GetTotalVisits :one +SELECT COUNT(*) FROM link_visits WHERE lid = $1 +` + +func (q *Queries) GetTotalVisits(ctx context.Context, lid uuid.UUID) (int64, error) { + row := q.db.QueryRow(ctx, getTotalVisits, lid) + var count int64 + err := row.Scan(&count) + return count, err +} + const getUserByEmail = `-- name: GetUserByEmail :one SELECT uid, first_name, last_name, personal_email, school_email, phone, grad_year, role, date_created, date_modified FROM users WHERE personal_email = $1 OR school_email = $1 ` @@ -670,6 +751,36 @@ func (q *Queries) ListEventsByOrg(ctx context.Context, arg ListEventsByOrgParams return items, nil } +const listLinksByOrg = `-- name: ListLinksByOrg :many +SELECT lid, endpoint_url, dest_url, oid, created_at FROM links WHERE oid = $1 ORDER BY created_at DESC +` + +func (q *Queries) ListLinksByOrg(ctx context.Context, oid uuid.UUID) ([]Link, error) { + rows, err := q.db.Query(ctx, listLinksByOrg, oid) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Link{} + for rows.Next() { + var i Link + if err := rows.Scan( + &i.Lid, + &i.EndpointUrl, + &i.DestUrl, + &i.Oid, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const listOrganizations = `-- name: ListOrganizations :many SELECT oid, name, date_created, date_modified FROM organizations ORDER BY name LIMIT $1 OFFSET $2 ` @@ -744,6 +855,29 @@ func (q *Queries) ListUsers(ctx context.Context, arg ListUsersParams) ([]User, e return items, nil } +const logLinkVisit = `-- name: LogLinkVisit :one +INSERT INTO link_visits (lid, uid) +VALUES ($1, $2) +RETURNING lvid, lid, uid, created_at +` + +type LogLinkVisitParams struct { + Lid uuid.UUID `json:"lid"` + Uid pgtype.UUID `json:"uid"` +} + +func (q *Queries) LogLinkVisit(ctx context.Context, arg LogLinkVisitParams) (LinkVisit, error) { + row := q.db.QueryRow(ctx, logLinkVisit, arg.Lid, arg.Uid) + var i LinkVisit + err := row.Scan( + &i.Lvid, + &i.Lid, + &i.Uid, + &i.CreatedAt, + ) + return i, err +} + const registerForEvent = `-- name: RegisterForEvent :exec INSERT INTO event_registrations (uid, eid, is_attending) VALUES ($1, $2, $3) @@ -842,6 +976,33 @@ func (q *Queries) UpdateEvent(ctx context.Context, arg UpdateEventParams) (Event return i, err } +const updateLink = `-- name: UpdateLink :one +UPDATE links +SET endpoint_url = COALESCE($2, endpoint_url), + dest_url = COALESCE($3, dest_url) +WHERE lid = $1 +RETURNING lid, endpoint_url, dest_url, oid, created_at +` + +type UpdateLinkParams struct { + Lid uuid.UUID `json:"lid"` + EndpointUrl pgtype.Text `json:"endpoint_url"` + DestUrl pgtype.Text `json:"dest_url"` +} + +func (q *Queries) UpdateLink(ctx context.Context, arg UpdateLinkParams) (Link, error) { + row := q.db.QueryRow(ctx, updateLink, arg.Lid, arg.EndpointUrl, arg.DestUrl) + var i Link + err := row.Scan( + &i.Lid, + &i.EndpointUrl, + &i.DestUrl, + &i.Oid, + &i.CreatedAt, + ) + return i, err +} + const updateOrganization = `-- name: UpdateOrganization :one UPDATE organizations SET name = COALESCE($2, name) diff --git a/internal/dto/dto.go b/internal/dto/dto.go index 692c076..7fe4d91 100644 --- a/internal/dto/dto.go +++ b/internal/dto/dto.go @@ -118,6 +118,34 @@ type RegisterEventRequest struct { IsAttending bool `json:"is_attending"` } +// ============================================================================ +// Link DTOs +// ============================================================================ + +type CreateLinkRequest struct { + EndpointURL string `json:"endpoint_url" validate:"required,alphanumhyphen"` + DestURL string `json:"dest_url" validate:"required,url"` + OrgID uuid.UUID `json:"org_id" validate:"required"` +} + +type UpdateLinkRequest struct { + EndpointURL *string `json:"endpoint_url,omitempty" validate:"omitempty,alphanumhyphen"` + DestURL *string `json:"dest_url,omitempty" validate:"omitempty,url"` +} + +type LinkResponse struct { + LID uuid.UUID `json:"lid"` + EndpointURL string `json:"endpoint_url"` + DestURL string `json:"dest_url"` + OrgID uuid.UUID `json:"org_id"` + CreatedAt *time.Time `json:"created_at,omitempty"` +} + +type VisitCountResponse struct { + LID uuid.UUID `json:"lid"` + Count int64 `json:"count"` +} + // ============================================================================ // Pagination // ============================================================================ diff --git a/internal/handler/links.go b/internal/handler/links.go new file mode 100644 index 0000000..57c13b0 --- /dev/null +++ b/internal/handler/links.go @@ -0,0 +1,323 @@ +package handler + +import ( + "context" + "encoding/json" + "io" + "log/slog" + "net/http" + + "github.com/capyrpi/api/internal/database" + "github.com/capyrpi/api/internal/dto" + "github.com/capyrpi/api/internal/middleware" + "github.com/go-chi/chi/v5" + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" + "github.com/yeqown/go-qrcode/v2" + "github.com/yeqown/go-qrcode/writer/standard" +) + +const QR_FG_COLOR = "#067b76" +const QR_BG_COLOR = "#fcfdfe" + +// TODO this should be a global variable, this is very brittle +const PUBLIC_LINK_ENDPOINT = "www.capyrpi.org/api/r/" + +// CreateLink creates a new dynamic link +// @Summary Create link +// @Description Creates a new dynamic link for an organization. Requires org_admin role. +// @Tags links +// @Accept json +// @Produce json +// @Param body body dto.CreateLinkRequest true "Link data" +// @Success 201 {object} dto.LinkResponse +// @Failure 400 {object} ErrorResponse +// @Failure 403 {object} ErrorResponse +// @Security CookieAuth +// @Router /links [post] +func (h *Handler) CreateLink(w http.ResponseWriter, r *http.Request) { + var req dto.CreateLinkRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + h.respondError(w, http.StatusBadRequest, "Invalid request body") + return + } + + if req.OrgID == uuid.Nil { + h.respondError(w, http.StatusBadRequest, "org_id is required") + return + } + + // Check if user is admin of the org + claims, ok := middleware.GetUserClaims(r.Context()) + if !ok { + h.respondError(w, http.StatusUnauthorized, "Unauthorized") + return + } + uid, _ := uuid.Parse(claims.UserID) + + isAdmin, err := h.queries.IsOrgAdmin(r.Context(), database.IsOrgAdminParams{ + Uid: uid, + Oid: req.OrgID, + }) + if err != nil { + h.handleDBError(w, err) + return + } + if !isAdmin.Bool { + h.respondError(w, http.StatusForbidden, "Only org admins can create links") + return + } + + link, err := h.queries.CreateLink(r.Context(), database.CreateLinkParams{ + EndpointUrl: req.EndpointURL, + DestUrl: req.DestURL, + Oid: req.OrgID, + }) + if err != nil { + h.handleDBError(w, err) + return + } + + h.respondJSON(w, http.StatusCreated, toLinkResponse(link)) +} + +// UpdateLink updates an existing dynamic link +// @Summary Update link +// @Description Updates a dynamic link's destination or endpoint URL. Requires org_admin role. +// @Tags links +// @Accept json +// @Produce json +// @Param lid path string true "Link UUID" +// @Param body body dto.UpdateLinkRequest true "Update data" +// @Success 200 {object} dto.LinkResponse +// @Failure 400 {object} ErrorResponse +// @Failure 403 {object} ErrorResponse +// @Failure 404 {object} ErrorResponse +// @Security CookieAuth +// @Router /links/{lid} [put] +func (h *Handler) UpdateLink(w http.ResponseWriter, r *http.Request) { + lidStr := chi.URLParam(r, "lid") + lid, err := uuid.Parse(lidStr) + if err != nil { + h.respondError(w, http.StatusBadRequest, "Invalid link ID") + return + } + + var req dto.UpdateLinkRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + h.respondError(w, http.StatusBadRequest, "Invalid request body") + return + } + + link, err := h.queries.GetLinkByLID(r.Context(), lid) + if err != nil { + h.handleDBError(w, err) + return + } + + // Permission check + claims, ok := middleware.GetUserClaims(r.Context()) + if !ok { + h.respondError(w, http.StatusUnauthorized, "Unauthorized") + return + } + uid, _ := uuid.Parse(claims.UserID) + + isAdmin, err := h.queries.IsOrgAdmin(r.Context(), database.IsOrgAdminParams{ + Uid: uid, + Oid: link.Oid, + }) + if err != nil { + h.handleDBError(w, err) + return + } + if !isAdmin.Bool { + h.respondError(w, http.StatusForbidden, "Only org admins can update links") + return + } + + updatedLink, err := h.queries.UpdateLink(r.Context(), database.UpdateLinkParams{ + Lid: lid, + EndpointUrl: toPgText(req.EndpointURL), + DestUrl: toPgText(req.DestURL), + }) + if err != nil { + h.handleDBError(w, err) + return + } + + h.respondJSON(w, http.StatusOK, toLinkResponse(updatedLink)) +} + +// ResolveLink resolves a dynamic link, logs a visit, and redirects +// @Summary Resolve link +// @Description Redirects to the destination URL and logs a visit +// @Tags links +// @Param endpoint_url path string true "Dynamic link endpoint URL" +// @Success 302 +// @Failure 404 {object} ErrorResponse +// @Router /r/{endpoint_url} [get] +func (h *Handler) ResolveLink(w http.ResponseWriter, r *http.Request) { + endpointURL := chi.URLParam(r, "endpoint_url") + + link, err := h.queries.GetLinkByEndpointURL(r.Context(), endpointURL) + if err != nil { + h.handleDBError(w, err) + return + } + + // Log visit asynchronously to not block the redirect + go func() { + // Create a detached context so the DB query isn't cancelled when the HTTP request ends + ctx := context.Background() + + var uid pgtype.UUID + claims, ok := middleware.GetUserClaims(r.Context()) + if ok { + parsedUID, err := uuid.Parse(claims.UserID) + if err == nil { + uid = pgtype.UUID{Bytes: parsedUID, Valid: true} + } + } + + _, err := h.queries.LogLinkVisit(ctx, database.LogLinkVisitParams{ + Lid: link.Lid, + Uid: uid, + }) + if err != nil { + slog.Error("failed to log link visit", "lid", link.Lid, "error", err) + } + }() + + http.Redirect(w, r, link.DestUrl, http.StatusFound) +} + +// ListOrgLinks lists all links for an organization +// @Summary List org links +// @Description Returns all dynamic links owned by an organization +// @Tags links +// @Accept json +// @Produce json +// @Param oid path string true "Organization UUID" +// @Success 200 {array} dto.LinkResponse +// @Failure 404 {object} ErrorResponse +// @Security CookieAuth +// @Router /organizations/{oid}/links [get] +func (h *Handler) ListOrgLinks(w http.ResponseWriter, r *http.Request) { + oidStr := chi.URLParam(r, "oid") + oid, err := uuid.Parse(oidStr) + if err != nil { + h.respondError(w, http.StatusBadRequest, "Invalid organization ID") + return + } + + links, err := h.queries.ListLinksByOrg(r.Context(), oid) + if err != nil { + h.handleDBError(w, err) + return + } + + response := make([]dto.LinkResponse, len(links)) + for i, l := range links { + response[i] = toLinkResponse(l) + } + + h.respondJSON(w, http.StatusOK, response) +} + +// GetTotalVisits returns the total number of visits for a link +// @Summary Get visit count +// @Description Returns the total number of visits logged for a link +// @Tags links +// @Produce json +// @Param lid path string true "Link UUID" +// @Success 200 {object} dto.VisitCountResponse +// @Failure 404 {object} ErrorResponse +// @Security CookieAuth +// @Router /links/{lid}/visits [get] +func (h *Handler) GetTotalVisits(w http.ResponseWriter, r *http.Request) { + lidStr := chi.URLParam(r, "lid") + lid, err := uuid.Parse(lidStr) + if err != nil { + h.respondError(w, http.StatusBadRequest, "Invalid link ID") + return + } + + count, err := h.queries.GetTotalVisits(r.Context(), lid) + if err != nil { + h.handleDBError(w, err) + return + } + + h.respondJSON(w, http.StatusOK, dto.VisitCountResponse{ + LID: lid, + Count: count, + }) +} + +type nopWriteCloser struct { + io.Writer +} + +func (nopWriteCloser) Close() error { return nil } + +// GetQRCode generates a QR code for a link's destination URL +// @Summary Get QR code +// @Description Generates and returns a QR code image for the link's destination URL +// @Tags links +// @Produce image/png +// @Param lid path string true "Link UUID" +// @Success 200 {file} image/png +// @Failure 404 {object} ErrorResponse +// @Router /links/{lid}/qrcode [get] +func (h *Handler) GetQRCode(w http.ResponseWriter, r *http.Request) { + lidStr := chi.URLParam(r, "lid") + lid, err := uuid.Parse(lidStr) + if err != nil { + h.respondError(w, http.StatusBadRequest, "Invalid link ID") + return + } + + link, err := h.queries.GetLinkByLID(r.Context(), lid) + if err != nil { + h.handleDBError(w, err) + return + } + + qrc, err := qrcode.NewWith(PUBLIC_LINK_ENDPOINT + link.EndpointUrl) + if err != nil { + slog.Error("failed to generate QR code", "error", err) + h.respondError(w, http.StatusInternalServerError, "Failed to generate QR code") + return + } + + qrcOpts := []standard.ImageOption{ + standard.WithBgColorRGBHex(QR_BG_COLOR), + standard.WithFgColorRGBHex(QR_FG_COLOR), + // standard.WithCircleShape(), + } + + w.Header().Set("Content-Type", "image/png") + wr := standard.NewWithWriter(nopWriteCloser{w}, qrcOpts...) + if err != nil { + slog.Error("failed to create standard writer for QR code", "error", err) + h.respondError(w, http.StatusInternalServerError, "Failed to create QR code writer") + return + } + + if err = qrc.Save(wr); err != nil { + slog.Error("failed to write QR code to response", "error", err) + // Header already set, but we can't do much now if it partially wrote + } +} + +// Helper functions for link conversion +func toLinkResponse(link database.Link) dto.LinkResponse { + return dto.LinkResponse{ + LID: link.Lid, + EndpointURL: link.EndpointUrl, + DestURL: link.DestUrl, + OrgID: link.Oid, + CreatedAt: fromPgTimestamp(link.CreatedAt), + } +} diff --git a/internal/handler/links_test.go b/internal/handler/links_test.go new file mode 100644 index 0000000..7744488 --- /dev/null +++ b/internal/handler/links_test.go @@ -0,0 +1,180 @@ +package handler_test + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/capyrpi/api/internal/config" + "github.com/capyrpi/api/internal/database" + "github.com/capyrpi/api/internal/database/mocks" + "github.com/capyrpi/api/internal/dto" + "github.com/capyrpi/api/internal/handler" + "github.com/capyrpi/api/internal/middleware" + "github.com/go-chi/chi/v5" + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestCreateLink(t *testing.T) { + uid := uuid.New() + oid := uuid.New() + lid := uuid.New() + + tests := []struct { + name string + requestBody interface{} + setupMock func(*mocks.Querier) + setupContext func() context.Context + expectedStatus int + }{ + { + name: "Success", + requestBody: dto.CreateLinkRequest{ + EndpointURL: "promo-2024", + DestURL: "https://capyrpi.org/promo", + OrgID: oid, + }, + setupMock: func(m *mocks.Querier) { + m.On("IsOrgAdmin", mock.Anything, database.IsOrgAdminParams{ + Uid: uid, + Oid: oid, + }).Return(pgtype.Bool{Bool: true, Valid: true}, nil) + + m.On("CreateLink", mock.Anything, database.CreateLinkParams{ + EndpointUrl: "promo-2024", + DestUrl: "https://capyrpi.org/promo", + Oid: oid, + }).Return(database.Link{ + Lid: lid, + EndpointUrl: "promo-2024", + DestUrl: "https://capyrpi.org/promo", + Oid: oid, + }, nil) + }, + setupContext: func() context.Context { + ctx := context.Background() + claims := &middleware.UserClaims{UserID: uid.String()} + return context.WithValue(ctx, middleware.UserClaimsKey, claims) + }, + expectedStatus: http.StatusCreated, + }, + { + name: "Forbidden - Not Admin", + requestBody: dto.CreateLinkRequest{ + EndpointURL: "promo-2024", + DestURL: "https://capyrpi.org/promo", + OrgID: oid, + }, + setupMock: func(m *mocks.Querier) { + m.On("IsOrgAdmin", mock.Anything, database.IsOrgAdminParams{ + Uid: uid, + Oid: oid, + }).Return(pgtype.Bool{Bool: false, Valid: true}, nil) + }, + setupContext: func() context.Context { + ctx := context.Background() + claims := &middleware.UserClaims{UserID: uid.String()} + return context.WithValue(ctx, middleware.UserClaimsKey, claims) + }, + expectedStatus: http.StatusForbidden, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockQueries := mocks.NewQuerier(t) + if tt.setupMock != nil { + tt.setupMock(mockQueries) + } + + h := handler.New(mockQueries, &config.Config{}) + + body, _ := json.Marshal(tt.requestBody) + req := httptest.NewRequest("POST", "/links", bytes.NewBuffer(body)) + req = req.WithContext(tt.setupContext()) + rr := httptest.NewRecorder() + + http.HandlerFunc(h.CreateLink).ServeHTTP(rr, req) + + assert.Equal(t, tt.expectedStatus, rr.Code) + if tt.expectedStatus == http.StatusCreated { + var res dto.LinkResponse + err := json.Unmarshal(rr.Body.Bytes(), &res) + assert.NoError(t, err) + assert.Equal(t, lid, res.LID) + assert.Equal(t, "promo-2024", res.EndpointURL) + } + }) + } +} + +func TestResolveLink(t *testing.T) { + lid := uuid.New() + endpoint := "my-link" + dest := "https://example.com" + + tests := []struct { + name string + endpointParam string + setupMock func(*mocks.Querier) + setupContext func() context.Context + expectedStatus int + expectedLoc string + }{ + { + name: "Success Redirect", + endpointParam: endpoint, + setupMock: func(m *mocks.Querier) { + m.On("GetLinkByEndpointURL", mock.Anything, endpoint).Return(database.Link{ + Lid: lid, + EndpointUrl: endpoint, + DestUrl: dest, + }, nil) + + // We don't strictly mock the background Context visit log here + // since it happens in a goroutine and is hard to sync without sleep or waitgroups, + // but let's mock it to avoid panic if the mock is strict. + m.On("LogLinkVisit", mock.Anything, mock.MatchedBy(func(p database.LogLinkVisitParams) bool { + return p.Lid == lid + })).Return(database.LinkVisit{}, nil).Maybe() + }, + setupContext: func() context.Context { + return context.Background() + }, + expectedStatus: http.StatusFound, // 302 + expectedLoc: dest, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockQueries := mocks.NewQuerier(t) + tt.setupMock(mockQueries) + + h := handler.New(mockQueries, &config.Config{}) + + req := httptest.NewRequest("GET", "/r/"+tt.endpointParam, nil) + req = req.WithContext(tt.setupContext()) + + // Setup chi router context so chi.URLParam works + rctx := chi.NewRouteContext() + rctx.URLParams.Add("endpoint_url", tt.endpointParam) + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + rr := httptest.NewRecorder() + + http.HandlerFunc(h.ResolveLink).ServeHTTP(rr, req) + + assert.Equal(t, tt.expectedStatus, rr.Code) + if tt.expectedStatus == http.StatusFound { + assert.Equal(t, tt.expectedLoc, rr.Header().Get("Location")) + } + }) + } +} diff --git a/internal/router/router.go b/internal/router/router.go index 6e2ee5e..f70a12b 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -32,6 +32,7 @@ func mountProtectedRoutes(r chi.Router, h *handler.Handler, jwtSecret string) { r.Post("/{oid}/members", h.AddOrgMember) r.Delete("/{oid}/members/{uid}", h.RemoveOrgMember) r.Get("/{oid}/events", h.ListOrgEvents) + r.Get("/{oid}/links", h.ListOrgLinks) }) r.Route("/events", func(r chi.Router) { @@ -46,6 +47,14 @@ func mountProtectedRoutes(r chi.Router, h *handler.Handler, jwtSecret string) { r.Delete("/{eid}/register", h.UnregisterFromEvent) }) + // Links + r.Route("/links", func(r chi.Router) { + r.Post("/", h.CreateLink) + r.Put("/{lid}", h.UpdateLink) + r.Get("/{lid}/visits", h.GetTotalVisits) + r.Get("/{lid}/qrcode", h.GetQRCode) + }) + r.Route("/bot/tokens", func(r chi.Router) { r.Get("/", h.ListBotTokens) r.Post("/", h.CreateBotToken) @@ -71,6 +80,10 @@ func New(h *handler.Handler, queries database.Querier, jwtSecret string, allowed // Health check (public) r.Get("/health", h.Health) + // Link resolution (public) + // TODO Use a global variable to link this with links.go + r.Get("/r/{endpoint_url}", h.ResolveLink) + // Swagger UI (public) - Only in non-production environments if h.Config.Env != "production" { r.Get("/swagger/*", httpSwagger.WrapHandler) @@ -118,6 +131,7 @@ func New(h *handler.Handler, queries database.Querier, jwtSecret string, allowed r.Get("/organizations/{oid}/members", h.ListOrgMembers) r.Post("/organizations/{oid}/members", h.AddOrgMember) r.Delete("/organizations/{oid}/members/{uid}", h.RemoveOrgMember) + r.Get("/{oid}/links", h.ListOrgLinks) // Events (full access) r.Get("/events", h.ListEvents) @@ -128,6 +142,14 @@ func New(h *handler.Handler, queries database.Querier, jwtSecret string, allowed r.Get("/events/{eid}/registrations", h.ListEventRegistrations) r.Post("/events/{eid}/register", h.RegisterForEvent) r.Delete("/events/{eid}/register", h.UnregisterFromEvent) + + // Links + r.Route("/links", func(r chi.Router) { + r.Post("/", h.CreateLink) + r.Put("/{lid}", h.UpdateLink) + r.Get("/{lid}/visits", h.GetTotalVisits) + r.Get("/{lid}/qrcode", h.GetQRCode) + }) }) }) }) diff --git a/migrations/20260326224918_add_links.down.sql b/migrations/20260326224918_add_links.down.sql new file mode 100644 index 0000000..108a49b --- /dev/null +++ b/migrations/20260326224918_add_links.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS link_visits; +DROP TABLE IF EXISTS links; diff --git a/migrations/20260326224918_add_links.up.sql b/migrations/20260326224918_add_links.up.sql new file mode 100644 index 0000000..8d15324 --- /dev/null +++ b/migrations/20260326224918_add_links.up.sql @@ -0,0 +1,14 @@ +CREATE TABLE IF NOT EXISTS links ( + lid UUID PRIMARY KEY DEFAULT gen_random_uuid(), + endpoint_url TEXT NOT NULL UNIQUE, + dest_url TEXT NOT NULL, + oid UUID NOT NULL REFERENCES organizations(oid) ON DELETE CASCADE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS link_visits ( + lvid UUID PRIMARY KEY DEFAULT gen_random_uuid(), + lid UUID NOT NULL REFERENCES links(lid) ON DELETE CASCADE, + uid UUID REFERENCES users(uid) ON DELETE SET NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/schema.sql b/schema.sql index d67c444..e648e17 100644 --- a/schema.sql +++ b/schema.sql @@ -78,6 +78,21 @@ CREATE TABLE IF NOT EXISTS bot_tokens ( is_active BOOLEAN DEFAULT TRUE ); +CREATE TABLE IF NOT EXISTS links ( + lid UUID PRIMARY KEY DEFAULT gen_random_uuid(), + endpoint_url TEXT NOT NULL UNIQUE, + dest_url TEXT NOT NULL, + oid UUID NOT NULL REFERENCES organizations(oid) ON DELETE CASCADE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS link_visits ( + lvid UUID PRIMARY KEY DEFAULT gen_random_uuid(), + lid UUID NOT NULL REFERENCES links(lid) ON DELETE CASCADE, + uid UUID REFERENCES users(uid) ON DELETE SET NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + CREATE INDEX IF NOT EXISTS idx_bot_tokens_active ON bot_tokens(is_active) WHERE is_active = TRUE; -- 4. Triggers diff --git a/tests/integration/links_test.go b/tests/integration/links_test.go new file mode 100644 index 0000000..bead82a --- /dev/null +++ b/tests/integration/links_test.go @@ -0,0 +1,177 @@ +//go:build integration + +package integration + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/capyrpi/api/internal/config" + "github.com/capyrpi/api/internal/database" + "github.com/capyrpi/api/internal/dto" + "github.com/capyrpi/api/internal/handler" + "github.com/capyrpi/api/internal/middleware" + "github.com/capyrpi/api/internal/router" + "github.com/capyrpi/api/internal/testutils" + "github.com/golang-jwt/jwt/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestLinkFlow(t *testing.T) { + // 1. Setup DB and Server + pool := testutils.SetupTestDB(t) + defer pool.Close() + + queries := database.New(pool) + cfg := &config.Config{JWT: config.JWTConfig{Secret: "test-secret", ExpiryHours: 1}} + h := handler.New(queries, cfg) + r := router.New(h, queries, cfg.JWT.Secret, []string{}) + server := httptest.NewServer(r) + defer server.Close() + client := server.Client() + + // Disable redirects on the client so we can test the 302 response directly + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + + ctx := context.Background() + + // 2. Create User + user, err := queries.CreateUser(ctx, database.CreateUserParams{ + FirstName: "Link", + LastName: "Tester", + Role: database.NullUserRole{UserRole: database.UserRoleStudent, Valid: true}, + }) + require.NoError(t, err) + + // 3. Generate Auth Token + claims := middleware.UserClaims{ + UserID: user.Uid.String(), + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)), + }, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + tokenString, err := token.SignedString([]byte(cfg.JWT.Secret)) + require.NoError(t, err) + cookie := &http.Cookie{Name: "capy_auth", Value: tokenString} + + // 4. Create Organization + orgBody := []byte(`{"name":"Link Org","slug":"link-org"}`) + req, _ := http.NewRequest("POST", server.URL+"/v1/organizations", bytes.NewBuffer(orgBody)) + req.AddCookie(cookie) + req.Header.Set("Content-Type", "application/json") + resp, err := client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, http.StatusCreated, resp.StatusCode) + + var orgResp dto.OrganizationResponse + err = json.NewDecoder(resp.Body).Decode(&orgResp) + require.NoError(t, err) + oid := orgResp.OID.String() + + // 5. Create Link + linkReq := dto.CreateLinkRequest{ + EndpointURL: "my-promo", + DestURL: "https://example.com/dest", + OrgID: orgResp.OID, + } + linkBody, _ := json.Marshal(linkReq) + req, _ = http.NewRequest("POST", server.URL+"/v1/links", bytes.NewBuffer(linkBody)) + req.AddCookie(cookie) + req.Header.Set("Content-Type", "application/json") + + resp, err = client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, http.StatusCreated, resp.StatusCode) + + var linkResp dto.LinkResponse + err = json.NewDecoder(resp.Body).Decode(&linkResp) + require.NoError(t, err) + require.Equal(t, "my-promo", linkResp.EndpointURL) + lid := linkResp.LID.String() + + // 6. Resolve Link (Simulate user clicking it) + req, _ = http.NewRequest("GET", server.URL+"/r/my-promo", nil) + resp, err = client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + + // Check redirect status and location + assert.Equal(t, http.StatusFound, resp.StatusCode) + assert.Equal(t, "https://example.com/dest", resp.Header.Get("Location")) + + // Give the async goroutine a tiny bit of time to log the visit in DB + time.Sleep(100 * time.Millisecond) + + // 7. Check Visit Count + req, _ = http.NewRequest("GET", fmt.Sprintf("%s/v1/links/%s/visits", server.URL, lid), nil) + req.AddCookie(cookie) + resp, err = client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, http.StatusOK, resp.StatusCode) + + var visitResp dto.VisitCountResponse + err = json.NewDecoder(resp.Body).Decode(&visitResp) + require.NoError(t, err) + assert.Equal(t, int64(1), visitResp.Count) + + // 8. Update Link + updateReq := dto.UpdateLinkRequest{ + EndpointURL: nil, + DestURL: toPtr("https://example.com/updated"), + } + updateBody, _ := json.Marshal(updateReq) + req, _ = http.NewRequest("PUT", fmt.Sprintf("%s/v1/links/%s", server.URL, lid), bytes.NewBuffer(updateBody)) + req.AddCookie(cookie) + req.Header.Set("Content-Type", "application/json") + + resp, err = client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, http.StatusOK, resp.StatusCode) + + var updatedLink dto.LinkResponse + err = json.NewDecoder(resp.Body).Decode(&updatedLink) + require.NoError(t, err) + assert.Equal(t, "https://example.com/updated", updatedLink.DestURL) + + // 9. List Org Links + req, _ = http.NewRequest("GET", fmt.Sprintf("%s/v1/organizations/%s/links", server.URL, oid), nil) + req.AddCookie(cookie) + resp, err = client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, http.StatusOK, resp.StatusCode) + + var links []dto.LinkResponse + err = json.NewDecoder(resp.Body).Decode(&links) + require.NoError(t, err) + require.Len(t, links, 1) + + // 10. Get QR Code + req, _ = http.NewRequest("GET", fmt.Sprintf("%s/v1/links/%s/qrcode", server.URL, lid), nil) + // We don't usually need auth for QR code, but the endpoint currently requires CookieAuth based on swagger tags + // Actually looking at router.go, /links/{lid}/qrcode is under protected group. + req.AddCookie(cookie) + resp, err = client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, "image/png", resp.Header.Get("Content-Type")) +} + +func toPtr(s string) *string { + return &s +}