Skip to content

Commit

Permalink
Merge pull request #3587 from mathesar-foundation/architectural_overhaul
Browse files Browse the repository at this point in the history
Architectural overhaul
  • Loading branch information
seancolsen committed Jun 4, 2024
2 parents 5bbcbbc + bb111fc commit 389fc7e
Show file tree
Hide file tree
Showing 33 changed files with 1,781 additions and 140 deletions.
5 changes: 4 additions & 1 deletion config/settings/common_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ def pipe_delim(pipe_string):
ROOT_URLCONF = "config.urls"

MODERNRPC_METHODS_MODULES = [
'mathesar.rpc.connections'
'mathesar.rpc.connections',
'mathesar.rpc.columns',
'mathesar.rpc.schemas',
'mathesar.rpc.tables'
]

TEMPLATES = [
Expand Down
22 changes: 18 additions & 4 deletions db/columns/operations/drop.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"""The function in this module wraps SQL functions that drop columns."""
"""The functions in this module wrap SQL functions that drop columns."""
from db import connection as db_conn


def drop_column(table_oid, column_attnum, engine):
"""
Drop the given columns from the given table.
Drop the given column from the given table.
Args:
table_oid: OID of the table whose columns we'll drop.
column_attnum: The attnums of the columns to drop.
table_oid: OID of the table whose column we'll drop.
column_attnum: The attnum of the column to drop.
engine: SQLAlchemy engine object for connecting.
Returns:
Expand All @@ -17,3 +17,17 @@ def drop_column(table_oid, column_attnum, engine):
return db_conn.execute_msar_func_with_engine(
engine, 'drop_columns', table_oid, column_attnum
).fetchone()[0]


def drop_columns_from_table(table_oid, column_attnums, conn):
"""
Drop the given columns from the given table.
Args:
table_oid: OID of the table whose columns we'll drop.
column_attnums: The attnums of the columns to drop.
conn: A psycopg connection to the relevant database.
"""
return db_conn.exec_msar_func(
conn, 'drop_columns', table_oid, *column_attnums
).fetchone()[0]
39 changes: 38 additions & 1 deletion db/columns/operations/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,48 @@
from sqlalchemy import and_, asc, cast, select, text, exists, Identity

from db.columns.exceptions import DynamicDefaultWarning
from db.connection import execute_msar_func_with_engine
from db.connection import execute_msar_func_with_engine, exec_msar_func
from db.tables.operations.select import reflect_table_from_oid
from db.utils import execute_statement, get_pg_catalog_table


def get_column_info_for_table(table, conn):
"""
Return a list of dictionaries describing the columns of the table.
The `table` can be given as either a "qualified name", or an OID.
The OID is the preferred identifier, since it's much more robust.
The returned list contains dictionaries of the following form:
{
"id": <int>,
"name": <str>,
"type": <str>,
"type_options": {
"precision": <int>,
"scale": <int>,
"fields": <str>,
"length": <int>,
"item_type": <str>,
},
"nullable": <bool>,
"primary_key": <bool>,
"valid_target_types": [<str>, <str>, ..., <str>]
"default": {"value": <str>, "is_dynamic": <bool>},
"has_dependents": <bool>,
"description": <str>
}
The fields of the "type_options" dictionary are all optional,
depending on the "type" value.
Args:
table: The table for which we want column info.
"""
return exec_msar_func(conn, 'get_column_info', table).fetchone()[0]


def get_column_description(oid, attnum, engine):
cursor = execute_msar_func_with_engine(engine, 'col_description', oid, attnum)
row = cursor.fetchone()
Expand Down
15 changes: 15 additions & 0 deletions db/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ def execute_msar_func_with_psycopg2_conn(conn, func_name, *args):
return conn.execute(stmt)


def exec_msar_func(conn, func_name, *args):
"""
Execute an msar function using a psycopg (3) connection.
Args:
conn: a psycopg connection
func_name: The unqualified msar_function name (danger; not sanitized)
*args: The list of parameters to pass
"""
# Returns a cursor
return conn.execute(
f"SELECT msar.{func_name}({','.join(['%s']*len(args))})", args
)


def load_file_with_engine(engine, file_handle):
"""Run an SQL script from a file, using psycopg."""
conn_str = str(engine.url)
Expand Down
20 changes: 15 additions & 5 deletions db/constants.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
MATHESAR_PREFIX = "mathesar_"
ID = "id"
ID_ORIGINAL = "id_original"
INFERENCE_SCHEMA = f"{MATHESAR_PREFIX}inference_schema"
COLUMN_NAME_TEMPLATE = 'Column ' # auto generated column name 'Column 1' (no undescore)
MSAR_PUBLIC = 'msar'
MSAR_PRIVAT = f"__{MSAR_PUBLIC}"
MSAR_VIEWS = f"{MSAR_PUBLIC}_views"

MATHESAR_PREFIX = "mathesar_"
MSAR_PUBLIC_SCHEMA = 'msar'
MSAR_PRIVATE_SCHEMA = f"__{MSAR_PUBLIC_SCHEMA}"
TYPES_SCHEMA = f"{MATHESAR_PREFIX}types"
INFERENCE_SCHEMA = f"{MATHESAR_PREFIX}inference_schema"
VIEWS_SCHEMA = f"{MSAR_PUBLIC_SCHEMA}_views"

INTERNAL_SCHEMAS = {
TYPES_SCHEMA,
MSAR_PUBLIC_SCHEMA,
MSAR_PRIVATE_SCHEMA,
VIEWS_SCHEMA,
INFERENCE_SCHEMA
}
23 changes: 7 additions & 16 deletions db/schemas/operations/select.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
from sqlalchemy import select, and_, not_, or_, func

from db import constants
from db import types
from db.constants import INTERNAL_SCHEMAS
from db.utils import get_pg_catalog_table
from db.metadata import get_empty_metadata
from db.connection import exec_msar_func

TYPES_SCHEMA = types.base.SCHEMA
TEMP_INFER_SCHEMA = constants.INFERENCE_SCHEMA
MSAR_PUBLIC = constants.MSAR_PUBLIC
MSAR_PRIVAT = constants.MSAR_PRIVAT
MSAR_VIEWS = constants.MSAR_VIEWS
EXCLUDED_SCHEMATA = [
"information_schema",
MSAR_PRIVAT,
MSAR_PUBLIC,
MSAR_VIEWS,
TEMP_INFER_SCHEMA,
TYPES_SCHEMA,
]

def get_schemas(conn):
return exec_msar_func(conn, 'get_schemas').fetchone()[0]


def reflect_schema(engine, name=None, oid=None, metadata=None):
Expand Down Expand Up @@ -46,7 +36,8 @@ def get_mathesar_schemas_with_oids(engine):
select(pg_namespace.c.nspname.label('schema'), pg_namespace.c.oid)
.where(
and_(
*[pg_namespace.c.nspname != schema for schema in EXCLUDED_SCHEMATA],
*[pg_namespace.c.nspname != schema for schema in INTERNAL_SCHEMAS],
pg_namespace.c.nspname != "information_schema",
not_(pg_namespace.c.nspname.like("pg_%"))
)
)
Expand Down
Loading

0 comments on commit 389fc7e

Please sign in to comment.