Display empty schemas on the sidebar (#621)

* Display empty schemas on the sidebar
* Add schemas fetching test
* Skip pg_temp schemas
* Exclude pg_temp tables from other queries
This commit is contained in:
Dan Sosedoff 2022-12-19 13:26:13 -06:00 committed by GitHub
parent 69233cd769
commit 0cd61093b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 31 deletions

View File

@ -234,6 +234,12 @@ func testDatabases(t *testing.T) {
assertMatches(t, []string{"booktown", "postgres"}, res) assertMatches(t, []string{"booktown", "postgres"}, res)
} }
func testSchemas(t *testing.T) {
res, err := testClient.Schemas()
assert.NoError(t, err)
assert.Equal(t, []string{"public"}, res)
}
func testObjects(t *testing.T) { func testObjects(t *testing.T) {
res, err := testClient.Objects() res, err := testClient.Objects()
objects := ObjectsFromResult(res) objects := ObjectsFromResult(res)
@ -617,6 +623,7 @@ func TestAll(t *testing.T) {
testInfo(t) testInfo(t)
testActivity(t) testActivity(t)
testDatabases(t) testDatabases(t)
testSchemas(t)
testObjects(t) testObjects(t)
testTable(t) testTable(t)
testTableRows(t) testTableRows(t)

View File

@ -20,7 +20,7 @@ WITH all_objects AS (
pg_catalog.pg_namespace n ON n.oid = c.relnamespace pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE WHERE
c.relkind IN ('r','v','m','S','s','') c.relkind IN ('r','v','m','S','s','')
AND n.nspname !~ '^pg_toast' AND n.nspname !~ '^pg_(toast|temp)'
AND n.nspname NOT IN ('information_schema', 'pg_catalog') AND n.nspname NOT IN ('information_schema', 'pg_catalog')
AND has_schema_privilege(n.nspname, 'USAGE') AND has_schema_privilege(n.nspname, 'USAGE')
@ -38,7 +38,7 @@ WITH all_objects AS (
JOIN JOIN
pg_catalog.pg_proc p ON p.pronamespace = n.oid pg_catalog.pg_proc p ON p.pronamespace = n.oid
WHERE WHERE
n.nspname !~ '^pg_toast' n.nspname !~ '^pg_(toast|temp)'
AND n.nspname NOT IN ('information_schema', 'pg_catalog') AND n.nspname NOT IN ('information_schema', 'pg_catalog')
) )
SELECT * FROM all_objects SELECT * FROM all_objects

View File

@ -2,5 +2,8 @@ SELECT
schema_name schema_name
FROM FROM
information_schema.schemata information_schema.schemata
WHERE
schema_name NOT IN ('information_schema', 'pg_catalog')
AND schema_name !~ '^pg_(toast|temp)'
ORDER BY ORDER BY
schema_name ASC schema_name ASC

View File

@ -86,6 +86,7 @@ function apiCall(method, path, params, cb) {
function getInfo(cb) { apiCall("get", "/info", {}, cb); } function getInfo(cb) { apiCall("get", "/info", {}, cb); }
function getConnection(cb) { apiCall("get", "/connection", {}, cb); } function getConnection(cb) { apiCall("get", "/connection", {}, cb); }
function getSchemas(cb) { apiCall("get", "/schemas", {}, cb); }
function getObjects(cb) { apiCall("get", "/objects", {}, cb); } function getObjects(cb) { apiCall("get", "/objects", {}, cb); }
function getTables(cb) { apiCall("get", "/tables", {}, cb); } function getTables(cb) { apiCall("get", "/tables", {}, cb); }
function getTableRows(table, opts, cb) { apiCall("get", "/tables/" + table + "/rows", opts, cb); } function getTableRows(table, opts, cb) { apiCall("get", "/tables/" + table + "/rows", opts, cb); }
@ -161,44 +162,65 @@ function buildSchemaSection(name, objects) {
function loadSchemas() { function loadSchemas() {
$("#objects").html(""); $("#objects").html("");
getObjects(function(data) { var emptyObjectList = function() {
if (Object.keys(data).length == 0) { return {
data["public"] = { table: [],
table: [], view: [],
view: [], materialized_view: [],
materialized_view: [], function: [],
function: [], sequence: []
sequence: [] }
}; }
getSchemas(function(schemasData) {
if (schemasData.error) {
alert("Error while fetching schemas: " + schemasData.error);
return;
} }
for (schema in data) { getObjects(function(data) {
$(buildSchemaSection(schema, data[schema])).appendTo("#objects"); if (data.error) {
} alert("Error while fetching database objects: " + data.error);
return;
}
if (Object.keys(data).length == 1) { if (Object.keys(data).length == 0) {
$(".schema").addClass("expanded"); data["public"] = emptyObjectList();
} }
// Clear out all autocomplete objects for (schemaName of schemasData) {
autocompleteObjects = []; // Allow users to see empty schemas if we dont have any objects in them
for (schema in data) { if (!data[schemaName]) {
for (kind in data[schema]) { data[schemaName] = emptyObjectList();
if (!(kind == "table" || kind == "view" || kind == "materialized_view" || kind == "function")) {
continue
} }
for (item in data[schema][kind]) { $(buildSchemaSection(schemaName, data[schemaName])).appendTo("#objects");
autocompleteObjects.push({ }
caption: data[schema][kind][item].name,
value: data[schema][kind][item].name, if (Object.keys(data).length == 1) {
meta: kind $(".schema").addClass("expanded");
}); }
// Clear out all autocomplete objects
autocompleteObjects = [];
for (schema in data) {
for (kind in data[schema]) {
if (!(kind == "table" || kind == "view" || kind == "materialized_view" || kind == "function")) {
continue
}
for (item in data[schema][kind]) {
autocompleteObjects.push({
caption: data[schema][kind][item].name,
value: data[schema][kind][item].name,
meta: kind
});
}
} }
} }
}
bindContextMenus(); bindContextMenus();
});
}); });
} }