Skip to content

Commit

Permalink
add table metadata model and rpc endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
Anish9901 committed Jun 27, 2024
1 parent 6f003e5 commit 7c31e76
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 18 deletions.
3 changes: 2 additions & 1 deletion config/settings/common_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ def pipe_delim(pipe_string):
'mathesar.rpc.columns',
'mathesar.rpc.columns.metadata',
'mathesar.rpc.schemas',
'mathesar.rpc.tables'
'mathesar.rpc.tables',
'mathesar.rpc.tables.metadata'
]

TEMPLATES = [
Expand Down
43 changes: 43 additions & 0 deletions mathesar/migrations/0009_alter_columnmetadata_attnum_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by Django 4.2.11 on 2024-06-27 20:00

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('mathesar', '0008_add_metadata_models'),
]

operations = [
migrations.AlterField(
model_name='columnmetadata',
name='attnum',
field=models.SmallIntegerField(),
),
migrations.AlterField(
model_name='columnmetadata',
name='table_oid',
field=models.PositiveBigIntegerField(),
),
migrations.CreateModel(
name='TableMetaData',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('schema_oid', models.PositiveBigIntegerField()),
('table_oid', models.PositiveBigIntegerField()),
('import_verified', models.BooleanField(default=False)),
('column_order', models.JSONField(default=list)),
('preview_customized', models.BooleanField(default=False)),
('preview_template', models.CharField(blank=True, max_length=255)),
('database', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mathesar.database')),
],
),
migrations.AddConstraint(
model_name='tablemetadata',
constraint=models.UniqueConstraint(fields=('database', 'schema_oid', 'table_oid'), name='unique_table_metadata'),
),
]
22 changes: 20 additions & 2 deletions mathesar/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ def connection(self):

class ColumnMetaData(BaseModel):
database = models.ForeignKey('Database', on_delete=models.CASCADE)
table_oid = models.PositiveIntegerField()
attnum = models.PositiveIntegerField()
table_oid = models.PositiveBigIntegerField()
attnum = models.SmallIntegerField()
bool_input = models.CharField(
choices=[("dropdown", "dropdown"), ("checkbox", "checkbox")],
blank=True
Expand Down Expand Up @@ -121,3 +121,21 @@ class Meta:
name="frac_digits_integrity"
)
]


class TableMetaData(BaseModel):
database = models.ForeignKey('Database', on_delete=models.CASCADE)
schema_oid = models.PositiveBigIntegerField()
table_oid = models.PositiveBigIntegerField()
import_verified = models.BooleanField(default=False)
column_order = models.JSONField(default=list)
preview_customized = models.BooleanField(default=False)
preview_template = models.CharField(max_length=255, blank=True)

class Meta:
constraints = [
models.UniqueConstraint(
fields=["database", "schema_oid", "table_oid"],
name="unique_table_metadata"
)
]
2 changes: 1 addition & 1 deletion mathesar/rpc/columns/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class ColumnMetaData(TypedDict):
Attributes:
database_id: The Django id of the database containing the table.
table_oid: The OID of the table containing the column
table_oid: The OID of the table containing the column.
attnum: The attnum of the column in the table.
bool_input: How the input for a boolean column should be shown.
bool_true: A string to display for `true` values.
Expand Down
1 change: 1 addition & 0 deletions mathesar/rpc/tables/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .base import * # noqa
File renamed without changes.
66 changes: 66 additions & 0 deletions mathesar/rpc/tables/metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""
Classes and functions exposed to the RPC endpoint for managing table metadata.
"""
from typing import Optional, TypedDict

from modernrpc.core import rpc_method
from modernrpc.auth.basic import http_basic_auth_login_required

from mathesar.rpc.exceptions.handlers import handle_rpc_exceptions
from mathesar.utils.tables import get_table_meta_data


class TableMetaData(TypedDict):
"""
Metadata for a table in a database.
Only the `database`, `schema_oid`, and `table_oid` keys are required.
Attributes:
database_id: The Django id of the database containing the table.
schema_oid: The OID of the schema containing the table.
table_oid: The OID of the table in the database.
import_verified: Specifies whether a file has been successfully imported into a table.
column_order: The order in which columns of a table are displayed.
preview_customized: Specifies whether the preview has been customized.
preview_template: Preview template for a referent column.
"""
database_id: int
schema_oid: int
table_oid: int
import_verified: Optional[bool]
column_order: Optional[list[int]]
preview_customized: Optional[bool]
preview_template: Optional[str]

@classmethod
def from_model(cls, model):
return cls(
database_id=model.database.id,
schema_oid=model.schema_oid,
table_oid=model.table_oid,
import_verified=model.import_verified,
column_order=model.column_order,
preview_customized=model.preview_customized,
preview_template=model.preview_template,
)


@rpc_method(name="tables.metadata.get")
@http_basic_auth_login_required
@handle_rpc_exceptions
def list(*, schema_oid: int, database_id: int, **kwargs) -> list[TableMetaData]:
"""
List metadata associated with tables for a schema.
Args:
schema_oid: Identity of the schema in the user's database.
database_id: The Django id of the database containing the table.
Returns:
Metadata object for a given table oid.
"""
table_meta_data = get_table_meta_data(schema_oid, database_id)
return [
TableMetaData.from_model(model) for model in table_meta_data
]
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ def mock_table_info(_schema_oid, conn):
'description': None
}
]
monkeypatch.setattr(tables, 'connect', mock_connect)
monkeypatch.setattr(tables, 'get_table_info', mock_table_info)
monkeypatch.setattr(tables.base, 'connect', mock_connect)
monkeypatch.setattr(tables.base, 'get_table_info', mock_table_info)
expect_table_list = [
{
'oid': 17408,
Expand Down Expand Up @@ -90,8 +90,8 @@ def mock_table_get(_table_oid, conn):
'schema': 2200,
'description': 'a description on the authors table.'
}
monkeypatch.setattr(tables, 'connect', mock_connect)
monkeypatch.setattr(tables, 'get_table', mock_table_get)
monkeypatch.setattr(tables.base, 'connect', mock_connect)
monkeypatch.setattr(tables.base, 'get_table', mock_table_get)
expect_table_list = {
'oid': table_oid,
'name': 'Authors',
Expand Down Expand Up @@ -123,8 +123,8 @@ def mock_drop_table(_table_oid, conn, cascade):
raise AssertionError('incorrect parameters passed')
return 'public."Table 0"'

monkeypatch.setattr(tables, 'connect', mock_connect)
monkeypatch.setattr(tables, 'drop_table_from_database', mock_drop_table)
monkeypatch.setattr(tables.base, 'connect', mock_connect)
monkeypatch.setattr(tables.base, 'drop_table_from_database', mock_drop_table)
deleted_table = tables.delete(table_oid=1964474, database_id=11, request=request)
assert deleted_table == 'public."Table 0"'

Expand All @@ -149,8 +149,8 @@ def mock_table_add(table_name, _schema_oid, conn, column_data_list, constraint_d
if _schema_oid != schema_oid:
raise AssertionError('incorrect parameters passed')
return 1964474
monkeypatch.setattr(tables, 'connect', mock_connect)
monkeypatch.setattr(tables, 'create_table_on_database', mock_table_add)
monkeypatch.setattr(tables.base, 'connect', mock_connect)
monkeypatch.setattr(tables.base, 'create_table_on_database', mock_table_add)
actual_table_oid = tables.add(table_name='newtable', schema_oid=2200, database_id=11, request=request)
assert actual_table_oid == 1964474

Expand Down Expand Up @@ -180,8 +180,8 @@ def mock_table_patch(_table_oid, _table_data_dict, conn):
if _table_oid != table_oid and _table_data_dict != table_data_dict:
raise AssertionError('incorrect parameters passed')
return 'newtabname'
monkeypatch.setattr(tables, 'connect', mock_connect)
monkeypatch.setattr(tables, 'alter_table_on_database', mock_table_patch)
monkeypatch.setattr(tables.base, 'connect', mock_connect)
monkeypatch.setattr(tables.base, 'alter_table_on_database', mock_table_patch)
altered_table_name = tables.patch(
table_oid=1964474,
table_data_dict={
Expand Down Expand Up @@ -216,8 +216,8 @@ def mock_table_import(_data_file_id, table_name, _schema_oid, conn, comment):
if _schema_oid != schema_oid and _data_file_id != data_file_id:
raise AssertionError('incorrect parameters passed')
return 1964474
monkeypatch.setattr(tables, 'connect', mock_connect)
monkeypatch.setattr(tables, 'import_csv', mock_table_import)
monkeypatch.setattr(tables.base, 'connect', mock_connect)
monkeypatch.setattr(tables.base, 'import_csv', mock_table_import)
imported_table_oid = tables.import_(
data_file_id=10,
table_name='imported_table',
Expand Down Expand Up @@ -253,8 +253,8 @@ def mock_table_preview(_table_oid, columns, conn, limit):
{'id': 3, 'length': Decimal('4.0')},
{'id': 4, 'length': Decimal('5.22')}
]
monkeypatch.setattr(tables, 'connect', mock_connect)
monkeypatch.setattr(tables, 'get_preview', mock_table_preview)
monkeypatch.setattr(tables.base, 'connect', mock_connect)
monkeypatch.setattr(tables.base, 'get_preview', mock_table_preview)
records = tables.get_import_preview(
table_oid=1964474,
columns=[{'attnum': 2, 'type': {'name': 'numeric', 'options': {'precision': 3, 'scale': 2}}}],
Expand Down
Empty file.
5 changes: 5 additions & 0 deletions mathesar/tests/rpc/test_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@
tables.get_import_preview,
"tables.get_import_preview",
[user_is_authenticated]
),
(
tables.metadata.list_,
"tables.metadata.list",
[user_is_authenticated]
)
]

Expand Down
5 changes: 5 additions & 0 deletions mathesar/utils/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from mathesar.database.base import create_mathesar_engine
from mathesar.imports.base import create_table_from_data_file
from mathesar.models.deprecated import Table
from mathesar.models.base import TableMetaData
from mathesar.state.django import reflect_columns_from_tables
from mathesar.state import get_cached_metadata

Expand Down Expand Up @@ -83,3 +84,7 @@ def create_empty_table(name, schema, comment=None):
table, _ = Table.current_objects.get_or_create(oid=db_table_oid, schema=schema)
reflect_columns_from_tables([table], metadata=get_cached_metadata())
return table


def get_table_meta_data(schema_oid, database_id):
return TableMetaData.objects.filter(database__id=database_id, schema_oid=schema_oid)

0 comments on commit 7c31e76

Please sign in to comment.