-
-
Notifications
You must be signed in to change notification settings - Fork 700
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
In-memory _schemas database tracking schemas of attached tables, closes
- Loading branch information
Showing
8 changed files
with
279 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
async def init_schemas(db): | ||
await db.execute_write( | ||
""" | ||
CREATE TABLE databases ( | ||
"database_name" TEXT PRIMARY KEY, | ||
"path" TEXT, | ||
"is_memory" INTEGER, | ||
"schema_version" INTEGER | ||
) | ||
""", | ||
block=True, | ||
) | ||
await db.execute_write( | ||
""" | ||
CREATE TABLE tables ( | ||
"database_name" TEXT, | ||
"table_name" TEXT, | ||
"rootpage" INTEGER, | ||
"sql" TEXT, | ||
PRIMARY KEY (database_name, table_name) | ||
) | ||
""", | ||
block=True, | ||
) | ||
await db.execute_write( | ||
""" | ||
CREATE TABLE columns ( | ||
"database_name" TEXT, | ||
"table_name" TEXT, | ||
"cid" INTEGER, | ||
"name" TEXT, | ||
"type" TEXT, | ||
"notnull" INTEGER, | ||
"default_value" TEXT, -- renamed from dflt_value | ||
"is_pk" INTEGER, -- renamed from pk | ||
"hidden" INTEGER, | ||
PRIMARY KEY (database_name, table_name, name) | ||
) | ||
""", | ||
block=True, | ||
) | ||
await db.execute_write( | ||
""" | ||
CREATE TABLE indexes ( | ||
"database_name" TEXT, | ||
"table_name" TEXT, | ||
"seq" INTEGER, | ||
"name" TEXT, | ||
"unique" INTEGER, | ||
"origin" TEXT, | ||
"partial" INTEGER, | ||
PRIMARY KEY (database_name, table_name, name) | ||
) | ||
""", | ||
block=True, | ||
) | ||
await db.execute_write( | ||
""" | ||
CREATE TABLE foreign_keys ( | ||
"database_name" TEXT, | ||
"table_name" TEXT, | ||
"id" INTEGER, | ||
"seq" INTEGER, | ||
"table" TEXT, | ||
"from" TEXT, | ||
"to" TEXT, | ||
"on_update" TEXT, | ||
"on_delete" TEXT, | ||
"match" TEXT | ||
) | ||
""", | ||
block=True, | ||
) | ||
|
||
|
||
async def populate_schema_tables(schema_db, db): | ||
database_name = db.name | ||
await schema_db.execute_write( | ||
"delete from tables where database_name = ?", [database_name], block=True | ||
) | ||
tables = (await db.execute("select * from sqlite_master where type = 'table'")).rows | ||
for table in tables: | ||
table_name = table["name"] | ||
await schema_db.execute_write( | ||
""" | ||
insert into tables (database_name, table_name, rootpage, sql) | ||
values (?, ?, ?, ?) | ||
""", | ||
[database_name, table_name, table["rootpage"], table["sql"]], | ||
block=True, | ||
) | ||
# And the columns | ||
await schema_db.execute_write( | ||
"delete from columns where database_name = ? and table_name = ?", | ||
[database_name, table_name], | ||
block=True, | ||
) | ||
columns = await db.table_column_details(table_name) | ||
for column in columns: | ||
params = { | ||
**{"database_name": database_name, "table_name": table_name}, | ||
**column._asdict(), | ||
} | ||
await schema_db.execute_write( | ||
""" | ||
insert into columns ( | ||
database_name, table_name, cid, name, type, "notnull", default_value, is_pk, hidden | ||
) VALUES ( | ||
:database_name, :table_name, :cid, :name, :type, :notnull, :default_value, :is_pk, :hidden | ||
) | ||
""", | ||
params, | ||
block=True, | ||
) | ||
# And the foreign_keys | ||
await schema_db.execute_write( | ||
"delete from foreign_keys where database_name = ? and table_name = ?", | ||
[database_name, table_name], | ||
block=True, | ||
) | ||
foreign_keys = ( | ||
await db.execute(f"PRAGMA foreign_key_list([{table_name}])") | ||
).rows | ||
for foreign_key in foreign_keys: | ||
params = { | ||
**{"database_name": database_name, "table_name": table_name}, | ||
**dict(foreign_key), | ||
} | ||
await schema_db.execute_write( | ||
""" | ||
insert into foreign_keys ( | ||
database_name, table_name, "id", seq, "table", "from", "to", on_update, on_delete, match | ||
) VALUES ( | ||
:database_name, :table_name, :id, :seq, :table, :from, :to, :on_update, :on_delete, :match | ||
) | ||
""", | ||
params, | ||
block=True, | ||
) | ||
# And the indexes | ||
await schema_db.execute_write( | ||
"delete from indexes where database_name = ? and table_name = ?", | ||
[database_name, table_name], | ||
block=True, | ||
) | ||
indexes = (await db.execute(f"PRAGMA index_list([{table_name}])")).rows | ||
for index in indexes: | ||
params = { | ||
**{"database_name": database_name, "table_name": table_name}, | ||
**dict(index), | ||
} | ||
await schema_db.execute_write( | ||
""" | ||
insert into indexes ( | ||
database_name, table_name, seq, name, "unique", origin, partial | ||
) VALUES ( | ||
:database_name, :table_name, :seq, :name, :unique, :origin, :partial | ||
) | ||
""", | ||
params, | ||
block=True, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
from .fixtures import app_client | ||
import pytest | ||
|
||
|
||
def test_schemas_only_available_to_root(app_client): | ||
cookie = app_client.actor_cookie({"id": "root"}) | ||
assert app_client.get("/_schemas").status == 403 | ||
assert app_client.get("/_schemas", cookies={"ds_actor": cookie}).status == 200 | ||
|
||
|
||
def test_schemas_databases(app_client): | ||
cookie = app_client.actor_cookie({"id": "root"}) | ||
databases = app_client.get( | ||
"/_schemas/databases.json?_shape=array", cookies={"ds_actor": cookie} | ||
).json | ||
assert len(databases) == 2 | ||
assert databases[0]["database_name"] == "_schemas" | ||
assert databases[1]["database_name"] == "fixtures" | ||
|
||
|
||
def test_schemas_tables(app_client): | ||
cookie = app_client.actor_cookie({"id": "root"}) | ||
tables = app_client.get( | ||
"/_schemas/tables.json?_shape=array", cookies={"ds_actor": cookie} | ||
).json | ||
assert len(tables) > 5 | ||
table = tables[0] | ||
assert set(table.keys()) == {"rootpage", "table_name", "database_name", "sql"} | ||
|
||
|
||
def test_schemas_indexes(app_client): | ||
cookie = app_client.actor_cookie({"id": "root"}) | ||
indexes = app_client.get( | ||
"/_schemas/indexes.json?_shape=array", cookies={"ds_actor": cookie} | ||
).json | ||
assert len(indexes) > 5 | ||
index = indexes[0] | ||
assert set(index.keys()) == { | ||
"partial", | ||
"name", | ||
"table_name", | ||
"unique", | ||
"seq", | ||
"database_name", | ||
"origin", | ||
} | ||
|
||
|
||
def test_schemas_foreign_keys(app_client): | ||
cookie = app_client.actor_cookie({"id": "root"}) | ||
foreign_keys = app_client.get( | ||
"/_schemas/foreign_keys.json?_shape=array", cookies={"ds_actor": cookie} | ||
).json | ||
assert len(foreign_keys) > 5 | ||
foreign_key = foreign_keys[0] | ||
assert set(foreign_key.keys()) == { | ||
"table", | ||
"seq", | ||
"on_update", | ||
"on_delete", | ||
"to", | ||
"rowid", | ||
"id", | ||
"match", | ||
"database_name", | ||
"table_name", | ||
"from", | ||
} |