diff --git a/docs/docs/api/rpc.md b/docs/docs/api/rpc.md index 37efba2c64..2ec24382f0 100644 --- a/docs/docs/api/rpc.md +++ b/docs/docs/api/rpc.md @@ -80,9 +80,9 @@ To use an RPC function: options: members: - list_ - - patch - - TableMetaData - - SettableTableMetaData + - set_ + - TableMetaDataBlob + - TableMetaDataRecord ## Columns diff --git a/mathesar/migrations/0010_alter_tablemetadata_column_order_and_more.py b/mathesar/migrations/0010_alter_tablemetadata_column_order_and_more.py new file mode 100644 index 0000000000..8c11c8fdf3 --- /dev/null +++ b/mathesar/migrations/0010_alter_tablemetadata_column_order_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.11 on 2024-07-10 18:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mathesar', '0009_add_column_metadata_model'), + ] + + operations = [ + migrations.AlterField( + model_name='tablemetadata', + name='column_order', + field=models.JSONField(null=True), + ), + migrations.AlterField( + model_name='tablemetadata', + name='import_verified', + field=models.BooleanField(null=True), + ), + migrations.AlterField( + model_name='tablemetadata', + name='record_summary_customized', + field=models.BooleanField(null=True), + ), + migrations.AlterField( + model_name='tablemetadata', + name='record_summary_template', + field=models.CharField(max_length=255, null=True), + ), + ] diff --git a/mathesar/models/base.py b/mathesar/models/base.py index 1ea3b0be70..3781f5d98c 100644 --- a/mathesar/models/base.py +++ b/mathesar/models/base.py @@ -126,10 +126,10 @@ class Meta: class TableMetaData(BaseModel): database = models.ForeignKey('Database', on_delete=models.CASCADE) table_oid = models.PositiveBigIntegerField() - import_verified = models.BooleanField(default=False) - column_order = models.JSONField(default=list) - record_summary_customized = models.BooleanField(default=False) - record_summary_template = models.CharField(max_length=255, blank=True) + import_verified = models.BooleanField(null=True) + column_order = models.JSONField(null=True) + record_summary_customized = models.BooleanField(null=True) + record_summary_template = models.CharField(max_length=255, null=True) class Meta: constraints = [ diff --git a/mathesar/rpc/tables/base.py b/mathesar/rpc/tables/base.py index 408e6dbff9..30f3710a0a 100644 --- a/mathesar/rpc/tables/base.py +++ b/mathesar/rpc/tables/base.py @@ -14,7 +14,9 @@ from mathesar.rpc.columns import CreatableColumnInfo, SettableColumnInfo, PreviewableColumnInfo from mathesar.rpc.constraints import CreatableConstraintInfo from mathesar.rpc.exceptions.handlers import handle_rpc_exceptions +from mathesar.rpc.tables.metadata import TableMetaDataBlob from mathesar.rpc.utils import connect +from mathesar.utils.tables import get_tables_meta_data class TableInfo(TypedDict): @@ -231,3 +233,29 @@ def get_import_preview( user = kwargs.get(REQUEST_KEY).user with connect(database_id, user) as conn: return get_preview(table_oid, columns, conn, limit) + + +@rpc_method(name="tables.list_with_metadata") +@http_basic_auth_login_required +@handle_rpc_exceptions +def list_with_metadata(*, schema_oid: int, database_id: int, **kwargs) -> list: + """ + List tables in a schema, along with the metadata associated with each table + + Args: + schema_oid: PostgreSQL OID of the schema containing the tables. + database_id: The Django id of the database containing the table. + + Returns: + A list of table details. + """ + user = kwargs.get(REQUEST_KEY).user + with connect(database_id, user) as conn: + tables = get_table_info(schema_oid, conn) + + metadata_records = get_tables_meta_data(database_id) + metadata_map = { + r.table_oid: TableMetaDataBlob.from_model(r) for r in metadata_records + } + + return [table | {"metadata": metadata_map.get(table["oid"])} for table in tables] diff --git a/mathesar/rpc/tables/metadata.py b/mathesar/rpc/tables/metadata.py index 2bc28382c8..7a6481b81b 100644 --- a/mathesar/rpc/tables/metadata.py +++ b/mathesar/rpc/tables/metadata.py @@ -7,10 +7,10 @@ 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_tables_meta_data, patch_table_meta_data +from mathesar.utils.tables import get_tables_meta_data, set_table_meta_data -class TableMetaData(TypedDict): +class TableMetaDataRecord(TypedDict): """ Metadata for a table in a database. @@ -46,9 +46,9 @@ def from_model(cls, model): ) -class SettableTableMetaData(TypedDict): +class TableMetaDataBlob(TypedDict): """ - Settable metadata fields for a table in a database. + The metadata fields which can be set on a table Attributes: import_verified: Specifies whether a file has been successfully imported into a table. @@ -61,11 +61,20 @@ class SettableTableMetaData(TypedDict): record_summary_customized: Optional[bool] record_summary_template: Optional[str] + @classmethod + def from_model(cls, model): + return cls( + import_verified=model.import_verified, + column_order=model.column_order, + record_summary_customized=model.record_summary_customized, + record_summary_template=model.record_summary_template, + ) + @rpc_method(name="tables.metadata.list") @http_basic_auth_login_required @handle_rpc_exceptions -def list_(*, database_id: int, **kwargs) -> list[TableMetaData]: +def list_(*, database_id: int, **kwargs) -> list[TableMetaDataRecord]: """ List metadata associated with tables for a database. @@ -77,26 +86,22 @@ def list_(*, database_id: int, **kwargs) -> list[TableMetaData]: """ table_meta_data = get_tables_meta_data(database_id) return [ - TableMetaData.from_model(model) for model in table_meta_data + TableMetaDataRecord.from_model(model) for model in table_meta_data ] -@rpc_method(name="tables.metadata.patch") +@rpc_method(name="tables.metadata.set") @http_basic_auth_login_required @handle_rpc_exceptions -def patch( - *, table_oid: int, metadata_dict: SettableTableMetaData, database_id: int, **kwargs -) -> TableMetaData: +def set_( + *, table_oid: int, metadata: TableMetaDataBlob, database_id: int, **kwargs +) -> None: """ - Alter metadata settings associated with a table for a database. + Set metadata for a table. Args: - table_oid: Identity of the table whose metadata we'll modify. - metadata_dict: The dict describing desired table metadata alterations. + table_oid: The PostgreSQL OID of the table. + metadata: A TableMetaDataBlob object describing desired table metadata to set. database_id: The Django id of the database containing the table. - - Returns: - Altered metadata object. """ - table_meta_data = patch_table_meta_data(table_oid, metadata_dict, database_id) - return TableMetaData.from_model(table_meta_data) + set_table_meta_data(table_oid, metadata, database_id) diff --git a/mathesar/tests/rpc/tables/test_t_metadata.py b/mathesar/tests/rpc/tables/test_t_metadata.py index faad49b703..c25753ffbc 100644 --- a/mathesar/tests/rpc/tables/test_t_metadata.py +++ b/mathesar/tests/rpc/tables/test_t_metadata.py @@ -29,12 +29,12 @@ def mock_get_tables_meta_data(_database_id): monkeypatch.setattr(metadata, "get_tables_meta_data", mock_get_tables_meta_data) expect_metadata_list = [ - metadata.TableMetaData( + metadata.TableMetaDataRecord( id=1, database_id=database_id, table_oid=1234, import_verified=True, column_order=[8, 9, 10], record_summary_customized=False, record_summary_template="{5555}" ), - metadata.TableMetaData( + metadata.TableMetaDataRecord( id=2, database_id=database_id, table_oid=4567, import_verified=False, column_order=[], record_summary_customized=True, record_summary_template="{5512} {1223}" @@ -42,26 +42,3 @@ def mock_get_tables_meta_data(_database_id): ] actual_metadata_list = metadata.list_(database_id=database_id) assert actual_metadata_list == expect_metadata_list - - -def test_tables_meta_data_patch(monkeypatch): - database_id = 2 - metadata_dict = {'import_verified': True, 'column_order': [1, 4, 12]} - - def mock_patch_tables_meta_data(table_oid, metadata_dict, _database_id): - server_model = Server(id=2, host='example.com', port=5432) - db_model = Database(id=_database_id, name='mymathesardb', server=server_model) - return TableMetaData( - id=1, database=db_model, table_oid=1234, - import_verified=True, column_order=[1, 4, 12], record_summary_customized=False, - record_summary_template="{5555}" - ) - monkeypatch.setattr(metadata, "patch_table_meta_data", mock_patch_tables_meta_data) - - expect_metadata_object = metadata.TableMetaData( - id=1, database_id=database_id, table_oid=1234, - import_verified=True, column_order=[1, 4, 12], record_summary_customized=False, - record_summary_template="{5555}" - ) - actual_metadata_object = metadata.patch(table_oid=1234, metadata_dict=metadata_dict, database_id=2) - assert actual_metadata_object == expect_metadata_object diff --git a/mathesar/tests/rpc/test_endpoints.py b/mathesar/tests/rpc/test_endpoints.py index ca91d17b2e..1ff2f365d4 100644 --- a/mathesar/tests/rpc/test_endpoints.py +++ b/mathesar/tests/rpc/test_endpoints.py @@ -106,6 +106,11 @@ "tables.list", [user_is_authenticated] ), + ( + tables.list_with_metadata, + "tables.list_with_metadata", + [user_is_authenticated] + ), ( tables.get, "tables.get", @@ -142,8 +147,8 @@ [user_is_authenticated] ), ( - tables.metadata.patch, - "tables.metadata.patch", + tables.metadata.set_, + "tables.metadata.set", [user_is_authenticated] ) ] diff --git a/mathesar/utils/tables.py b/mathesar/utils/tables.py index 87d350a20e..8c0664fa63 100644 --- a/mathesar/utils/tables.py +++ b/mathesar/utils/tables.py @@ -5,7 +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.models.base import Database, TableMetaData from mathesar.state.django import reflect_columns_from_tables from mathesar.state import get_cached_metadata @@ -90,13 +90,9 @@ def get_tables_meta_data(database_id): return TableMetaData.objects.filter(database__id=database_id) -def patch_table_meta_data(table_oid, metadata_dict, database_id): - metadata_model = TableMetaData.objects.get(database__id=database_id, table_oid=table_oid) - alterable_fields = ( - 'import_verified', 'column_order', 'record_summary_customized', 'record_summary_template' +def set_table_meta_data(table_oid, metadata, database_id): + TableMetaData.objects.update_or_create( + database=Database.objects.get(id=database_id), + table_oid=table_oid, + defaults=metadata, ) - for field, value in metadata_dict.items(): - if field in alterable_fields: - setattr(metadata_model, field, value) - metadata_model.save() - return metadata_model