From e3daa059e04d857c61adcd02955ae99e88529824 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Fri, 21 Jun 2024 23:10:29 +0530 Subject: [PATCH 01/13] implement sql and python functions for getting import preview --- db/sql/00_msar.sql | 50 +++++++++++++++++++++++++++- db/tables/operations/import_.py | 10 ++++++ mathesar/rpc/columns.py | 6 ++++ mathesar/rpc/tables.py | 20 +++++++++-- mathesar/tests/rpc/test_endpoints.py | 5 +++ 5 files changed, 88 insertions(+), 3 deletions(-) diff --git a/db/sql/00_msar.sql b/db/sql/00_msar.sql index 2351a6e17e..2ccf6d68ee 100644 --- a/db/sql/00_msar.sql +++ b/db/sql/00_msar.sql @@ -105,6 +105,18 @@ __msar.build_text_tuple(text[]) RETURNS text AS $$ SELECT '(' || string_agg(col, ', ') || ')' FROM unnest($1) x(col); $$ LANGUAGE sql RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION +__msar.exec_dql(command text) RETURNS jsonb AS $$ +DECLARE + records jsonb; +BEGIN + EXECUTE 'WITH cte AS (' || command || ') + SELECT jsonb_agg(row_to_json(cte.*)) FROM cte' INTO records; + RETURN records; +END; +$$ LANGUAGE plpgsql RETURNS NULL ON NULL INPUT; + ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -- INFO FUNCTIONS @@ -1301,7 +1313,7 @@ $$ LANGUAGE plpgsql RETURNS NULL ON NULL INPUT; DROP TYPE IF EXISTS __msar.col_def CASCADE; CREATE TYPE __msar.col_def AS ( name_ text, -- The name of the column to create, quoted. - type_ text, -- The type of the column to create, fully specced with arguments. + type_ jsonb, -- The type of the column to create, fully specced with arguments. not_null boolean, -- A boolean to describe whether the column is nullable or not. default_ text, -- Text SQL giving the default value for the column. identity_ boolean, -- A boolean giving whether the column is an identity pkey column. @@ -2392,6 +2404,42 @@ END; $$ LANGUAGE plpgsql; +CREATE OR REPLACE FUNCTION +msar.get_preview( + tab_id oid, + col_cast_def jsonb, + rec_limit integer +) RETURNS jsonb AS $$ +DECLARE + tab_name text; + sel_query text; + result jsonb; +BEGIN + tab_name := __msar.get_relation_name(tab_id); + WITH preview_cte AS ( + SELECT string_agg( + 'CAST(' || + __msar.build_cast_expr(msar.get_column_name(tab_id, (col_cast ->> 'attnum')::integer), col_cast -> 'type' ->> 'name') || + ' AS ' || + msar.build_type_text(col_cast -> 'type') || + ')'|| ' AS ' || msar.get_column_name(tab_id, (col_cast ->> 'attnum')::integer), + ', ' + ) AS cast_expr + FROM jsonb_array_elements(col_cast_def) AS col_cast + WHERE NOT msar.is_mathesar_id_column(tab_id, (col_cast ->> 'attnum')::integer) + ) + SELECT + CASE WHEN rec_limit IS NOT NULL THEN + format('SELECT id, %s FROM %s LIMIT %s', cast_expr, tab_name, rec_limit) + ELSE + format('SELECT id, %s FROM %s', cast_expr, tab_name) + END + INTO sel_query FROM preview_cte; + RETURN __msar.exec_dql(sel_query); +END; +$$ LANGUAGE plpgsql; + + ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -- COLUMN ALTERATION FUNCTIONS diff --git a/db/tables/operations/import_.py b/db/tables/operations/import_.py index a22ec9121c..39ec1a2d77 100644 --- a/db/tables/operations/import_.py +++ b/db/tables/operations/import_.py @@ -1,6 +1,11 @@ +import json import tempfile + import clevercsv as csv from psycopg import sql + +from db.connection import exec_msar_func +from db.columns.operations.alter import _transform_column_alter_dict from db.tables.operations.create import prepare_table_for_import from db.encoding_utils import get_sql_compatible_encoding from mathesar.models.deprecated import DataFile @@ -89,3 +94,8 @@ def insert_csv_records( with cursor.copy(copy_sql) as copy: while data := temp_file.read(): copy.write(data) + + +def get_preview(table_oid, column_list, conn, limit=20): + transformed_column_data = [_transform_column_alter_dict(col) for col in column_list] + return exec_msar_func(conn, 'get_preview', table_oid, json.dumps(transformed_column_data), limit).fetchone()[0] diff --git a/mathesar/rpc/columns.py b/mathesar/rpc/columns.py index 6f198d8553..84890af53c 100644 --- a/mathesar/rpc/columns.py +++ b/mathesar/rpc/columns.py @@ -131,6 +131,12 @@ class SettableColumnInfo(TypedDict): description: Optional[str] +class PreviewableColumnInfo(TypedDict): + id: int + type: Optional[str] + type_options: Optional[TypeOptions] + + class ColumnInfo(TypedDict): """ Information about a column. Extends the settable fields. diff --git a/mathesar/rpc/tables.py b/mathesar/rpc/tables.py index 1516e12ad6..ae692b8c56 100644 --- a/mathesar/rpc/tables.py +++ b/mathesar/rpc/tables.py @@ -7,8 +7,8 @@ from db.tables.operations.drop import drop_table_from_database from db.tables.operations.create import create_table_on_database from db.tables.operations.alter import alter_table_on_database -from db.tables.operations.import_ import import_csv -from mathesar.rpc.columns import CreatableColumnInfo, SettableColumnInfo +from db.tables.operations.import_ import import_csv, get_preview +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.utils import connect @@ -200,3 +200,19 @@ def import_( user = kwargs.get(REQUEST_KEY).user with connect(database_id, user) as conn: return import_csv(data_file_id, table_name, schema_oid, conn, comment) + + +@rpc_method(name="tables.get_import_preview") +@http_basic_auth_login_required +@handle_rpc_exceptions +def get_import_preview( + *, + table_oid: int, + columns: PreviewableColumnInfo, + database_id: int, + limit: int = 20, + **kwargs +): + user = kwargs.get(REQUEST_KEY).user + with connect(database_id, user) as conn: + return get_preview(table_oid, columns, conn, limit) diff --git a/mathesar/tests/rpc/test_endpoints.py b/mathesar/tests/rpc/test_endpoints.py index ae18825f41..288aa6257c 100644 --- a/mathesar/tests/rpc/test_endpoints.py +++ b/mathesar/tests/rpc/test_endpoints.py @@ -93,6 +93,11 @@ tables.import_, "tables.import", [user_is_authenticated] + ), + ( + tables.get_import_preview, + "tables.get_import_preview", + [user_is_authenticated] ) ] From 21ea0dd69b3d813e2da1dc0bc668382e5738edd0 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Fri, 21 Jun 2024 23:23:24 +0530 Subject: [PATCH 02/13] revert col_def --- db/sql/00_msar.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/sql/00_msar.sql b/db/sql/00_msar.sql index 2ccf6d68ee..ca4799a570 100644 --- a/db/sql/00_msar.sql +++ b/db/sql/00_msar.sql @@ -1313,7 +1313,7 @@ $$ LANGUAGE plpgsql RETURNS NULL ON NULL INPUT; DROP TYPE IF EXISTS __msar.col_def CASCADE; CREATE TYPE __msar.col_def AS ( name_ text, -- The name of the column to create, quoted. - type_ jsonb, -- The type of the column to create, fully specced with arguments. + type_ text, -- The type of the column to create, fully specced with arguments. not_null boolean, -- A boolean to describe whether the column is nullable or not. default_ text, -- Text SQL giving the default value for the column. identity_ boolean, -- A boolean giving whether the column is an identity pkey column. From d9371db00047c414b3b5263562b70bc177fb4608 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Fri, 21 Jun 2024 23:30:09 +0530 Subject: [PATCH 03/13] update docs --- docs/docs/api/rpc.md | 5 ++++- mathesar/rpc/tables.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/docs/api/rpc.md b/docs/docs/api/rpc.md index d9a727120f..356cde63bc 100644 --- a/docs/docs/api/rpc.md +++ b/docs/docs/api/rpc.md @@ -68,6 +68,7 @@ To use an RPC function: - delete - patch - import_ + - get_import_preview - TableInfo - SettableTableInfo @@ -80,8 +81,10 @@ To use an RPC function: - add - patch - delete - - ColumnListReturn - ColumnInfo + - ColumnListReturn + - CreatableColumnInfo + - PreviewableColumnInfo - SettableColumnInfo - TypeOptions - ColumnDefault diff --git a/mathesar/rpc/tables.py b/mathesar/rpc/tables.py index ae692b8c56..40837bfded 100644 --- a/mathesar/rpc/tables.py +++ b/mathesar/rpc/tables.py @@ -212,7 +212,7 @@ def get_import_preview( database_id: int, limit: int = 20, **kwargs -): +) -> list[dict]: user = kwargs.get(REQUEST_KEY).user with connect(database_id, user) as conn: return get_preview(table_oid, columns, conn, limit) From 38f5f763fea48197680f1e7216582f8f4c34c1d2 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Sat, 22 Jun 2024 02:20:44 +0530 Subject: [PATCH 04/13] improve formatting --- db/sql/00_msar.sql | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/db/sql/00_msar.sql b/db/sql/00_msar.sql index ca4799a570..8e3e2d782f 100644 --- a/db/sql/00_msar.sql +++ b/db/sql/00_msar.sql @@ -2419,7 +2419,9 @@ BEGIN WITH preview_cte AS ( SELECT string_agg( 'CAST(' || - __msar.build_cast_expr(msar.get_column_name(tab_id, (col_cast ->> 'attnum')::integer), col_cast -> 'type' ->> 'name') || + __msar.build_cast_expr( + msar.get_column_name(tab_id, (col_cast ->> 'attnum')::integer), col_cast -> 'type' ->> 'name' + ) || ' AS ' || msar.build_type_text(col_cast -> 'type') || ')'|| ' AS ' || msar.get_column_name(tab_id, (col_cast ->> 'attnum')::integer), @@ -2428,12 +2430,8 @@ BEGIN FROM jsonb_array_elements(col_cast_def) AS col_cast WHERE NOT msar.is_mathesar_id_column(tab_id, (col_cast ->> 'attnum')::integer) ) - SELECT - CASE WHEN rec_limit IS NOT NULL THEN - format('SELECT id, %s FROM %s LIMIT %s', cast_expr, tab_name, rec_limit) - ELSE - format('SELECT id, %s FROM %s', cast_expr, tab_name) - END + SELECT + format('SELECT id, %s FROM %s LIMIT %L', cast_expr, tab_name, rec_limit) INTO sel_query FROM preview_cte; RETURN __msar.exec_dql(sel_query); END; From 183dfe4b0987e7eefb87c9925e6a33f0514c0ba4 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Mon, 24 Jun 2024 23:24:32 +0530 Subject: [PATCH 05/13] add docstrings --- db/sql/00_msar.sql | 99 +++++++++++++++++++++++++++++++-- db/tables/operations/import_.py | 11 ++++ mathesar/rpc/columns.py | 8 +++ mathesar/rpc/tables.py | 14 ++++- 4 files changed, 125 insertions(+), 7 deletions(-) diff --git a/db/sql/00_msar.sql b/db/sql/00_msar.sql index 8e3e2d782f..50b64ea1f1 100644 --- a/db/sql/00_msar.sql +++ b/db/sql/00_msar.sql @@ -106,8 +106,33 @@ SELECT '(' || string_agg(col, ', ') || ')' FROM unnest($1) x(col); $$ LANGUAGE sql RETURNS NULL ON NULL INPUT; +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +-- GENERAL DQL FUNCTIONS +-- +-- Functions in this section are quite general, and are the basis of the others. +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- + + CREATE OR REPLACE FUNCTION -__msar.exec_dql(command text) RETURNS jsonb AS $$ +__msar.exec_dql(command text) RETURNS jsonb AS $$/* +Execute the given command, returning a JSON object describing the records in the following form: +[ + {"id": 1, "col1_name": "value1", "col2_name": "value2"}, + {"id": 2, "col1_name": "value1", "col2_name": "value2"}, + {"id": 3, "col1_name": "value1", "col2_name": "value2"}, + ... +] + +Useful for SELECTing from tables. Most useful when you're performing DQL. + +Note that you always have to include the primary key column(`id` in case of a Mathesar table) in the +command_template for the returned records to be uniquely identifiable. + +Args: + command: Raw string that will be executed as a command. +*/ DECLARE records jsonb; BEGIN @@ -117,6 +142,35 @@ BEGIN END; $$ LANGUAGE plpgsql RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION +__msar.exec_dql(command_template text, arguments variadic anynonarray) RETURNS jsonb AS $$/* +Execute a templated command, returning a JSON object describing the records in the following form: +[ + {"id": 1, "col1_name": "value1", "col2_name": "value2"}, + {"id": 2, "col1_name": "value1", "col2_name": "value2"}, + {"id": 3, "col1_name": "value1", "col2_name": "value2"}, + ... +] + +The template is given in the first argument, and all further arguments are used to fill in the +template. Useful for SELECTing from tables. Most useful when you're performing DQL. + +Note that you always have to include the primary key column(`id` in case of a Mathesar table) in the +command_template for the returned records to be uniquely identifiable. + +Args: + command_template: Raw string that will be executed as a command. + arguments: arguments that will be used to fill in the template. +*/ +DECLARE formatted_command TEXT; +BEGIN + formatted_command := format(command_template, VARIADIC arguments); + RETURN __msar.exec_dql(formatted_command); +END; +$$ LANGUAGE plpgsql RETURNS NULL ON NULL INPUT; + + ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -- INFO FUNCTIONS @@ -2409,13 +2463,46 @@ msar.get_preview( tab_id oid, col_cast_def jsonb, rec_limit integer -) RETURNS jsonb AS $$ +) RETURNS jsonb AS $$/* +Preview a table, applying different type casts and options to the underlying columns before import, +returning a JSON object describing the records of the table. + +Note that these casts are temporary and do not alter the data in the underlying table, +if you wish to alter these settings permanantly for the columns see msar.alter_columns. + +Args: + tab_id: The OID of the table to preview. + col_cast_def: A JSON object describing the column settings to apply. + rec_limit (optional): The upper limit for the number of records to return. + +The col_cast_def JSONB should have the form: +[ + { + "attnum": , + "type": { + "name": , + "options": { + "length": , + "precision": , + "scale": + "fields": , + "array": + } + }, + }, + { + ... + }, + ... +] +*/ DECLARE tab_name text; sel_query text; - result jsonb; + records jsonb; BEGIN tab_name := __msar.get_relation_name(tab_id); + sel_query := 'SELECT id, %s FROM %s LIMIT %L'; WITH preview_cte AS ( SELECT string_agg( 'CAST(' || @@ -2431,9 +2518,9 @@ BEGIN WHERE NOT msar.is_mathesar_id_column(tab_id, (col_cast ->> 'attnum')::integer) ) SELECT - format('SELECT id, %s FROM %s LIMIT %L', cast_expr, tab_name, rec_limit) - INTO sel_query FROM preview_cte; - RETURN __msar.exec_dql(sel_query); + __msar.exec_dql(sel_query, cast_expr, tab_name, rec_limit::text) + INTO records FROM preview_cte; + RETURN records; END; $$ LANGUAGE plpgsql; diff --git a/db/tables/operations/import_.py b/db/tables/operations/import_.py index 39ec1a2d77..70029587e7 100644 --- a/db/tables/operations/import_.py +++ b/db/tables/operations/import_.py @@ -97,5 +97,16 @@ def insert_csv_records( def get_preview(table_oid, column_list, conn, limit=20): + """ + Preview an imported table. Returning the records from the specified columns of the table. + + Args: + table_oid: Identity of the imported table in the user's database. + column_list: List of settings describing the casts to be applied to the columns. + limit: The upper limit for the number of records to return. + + Note that these casts are temporary and do not alter the data in the underlying table, + if you wish to alter these settings permanantly for the columns see tables/alter.py. + """ transformed_column_data = [_transform_column_alter_dict(col) for col in column_list] return exec_msar_func(conn, 'get_preview', table_oid, json.dumps(transformed_column_data), limit).fetchone()[0] diff --git a/mathesar/rpc/columns.py b/mathesar/rpc/columns.py index 84890af53c..b9833d7c8a 100644 --- a/mathesar/rpc/columns.py +++ b/mathesar/rpc/columns.py @@ -132,6 +132,14 @@ class SettableColumnInfo(TypedDict): class PreviewableColumnInfo(TypedDict): + """ + Information needed to preview a column. + + Attributes: + id: The `attnum` of the column in the table. + type: The new type to be applied to a column. + type_options: The options to be applied to the column type. + """ id: int type: Optional[str] type_options: Optional[TypeOptions] diff --git a/mathesar/rpc/tables.py b/mathesar/rpc/tables.py index 40837bfded..63f93dafe6 100644 --- a/mathesar/rpc/tables.py +++ b/mathesar/rpc/tables.py @@ -208,11 +208,23 @@ def import_( def get_import_preview( *, table_oid: int, - columns: PreviewableColumnInfo, + columns: list[PreviewableColumnInfo], database_id: int, limit: int = 20, **kwargs ) -> list[dict]: + """ + Preview an imported table. + + Args: + table_oid: Identity of the imported table in the user's database. + columns: List of settings describing the casts to be applied to the columns. + database_id: The Django id of the database containing the table. + limit: The upper limit for the number of records to return. + + Returns: + The records from the specified columns of the table. + """ user = kwargs.get(REQUEST_KEY).user with connect(database_id, user) as conn: return get_preview(table_oid, columns, conn, limit) From 7ae93e60dfc210c6ef1794a13820f5601c6f5c91 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Tue, 25 Jun 2024 01:00:35 +0530 Subject: [PATCH 06/13] fix exec_dql --- db/sql/00_msar.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/sql/00_msar.sql b/db/sql/00_msar.sql index 50b64ea1f1..2382a1b014 100644 --- a/db/sql/00_msar.sql +++ b/db/sql/00_msar.sql @@ -144,7 +144,7 @@ $$ LANGUAGE plpgsql RETURNS NULL ON NULL INPUT; CREATE OR REPLACE FUNCTION -__msar.exec_dql(command_template text, arguments variadic anynonarray) RETURNS jsonb AS $$/* +__msar.exec_dql(command_template text, arguments variadic anyarray) RETURNS jsonb AS $$/* Execute a templated command, returning a JSON object describing the records in the following form: [ {"id": 1, "col1_name": "value1", "col2_name": "value2"}, From 55d4a3ba8d7e072c4b304989f61b179f9092bb34 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Tue, 25 Jun 2024 01:39:51 +0530 Subject: [PATCH 07/13] add pytest --- mathesar/tests/rpc/test_tables.py | 42 +++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/mathesar/tests/rpc/test_tables.py b/mathesar/tests/rpc/test_tables.py index d0761730e5..1d25765168 100644 --- a/mathesar/tests/rpc/test_tables.py +++ b/mathesar/tests/rpc/test_tables.py @@ -5,6 +5,7 @@ rf(pytest-django): Provides mocked `Request` objects. monkeypatch(pytest): Lets you monkeypatch an object for testing. """ +from decimal import Decimal from contextlib import contextmanager from mathesar.rpc import tables @@ -225,3 +226,44 @@ def mock_table_import(_data_file_id, table_name, _schema_oid, conn, comment): request=request ) assert imported_table_oid == 1964474 + + +def test_tables_preview(rf, monkeypatch): + request = rf.post('/api/rpc/v0', data={}) + request.user = User(username='alice', password='pass1234') + table_oid = 1964474 + database_id = 11 + + @contextmanager + def mock_connect(_database_id, user): + if _database_id == database_id and user.username == 'alice': + try: + yield True + finally: + pass + else: + raise AssertionError('incorrect parameters passed') + + def mock_table_preview(_table_oid, columns, conn, limit): + if _table_oid != table_oid: + raise AssertionError('incorrect parameters passed') + return [ + {'id': 1, 'length': Decimal('2.0')}, + {'id': 2, 'length': Decimal('3.0')}, + {'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) + records = tables.get_import_preview( + table_oid=1964474, + columns=[{'attnum': 2, 'type': {'name': 'numeric', 'options': {'precision': 3, 'scale': 2}}}], + database_id=11, + request=request + ) + assert records == [ + {'id': 1, 'length': Decimal('2.0')}, + {'id': 2, 'length': Decimal('3.0')}, + {'id': 3, 'length': Decimal('4.0')}, + {'id': 4, 'length': Decimal('5.22')} + ] From 146949775f3f613b7415d2526601c65fb16f2353 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Tue, 25 Jun 2024 02:16:36 +0530 Subject: [PATCH 08/13] add sql test --- db/sql/test_00_msar.sql | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/db/sql/test_00_msar.sql b/db/sql/test_00_msar.sql index db10bb73e5..46fef76ece 100644 --- a/db/sql/test_00_msar.sql +++ b/db/sql/test_00_msar.sql @@ -1486,6 +1486,36 @@ END; $f$ LANGUAGE plpgsql; +CREATE OR REPLACE FUNCTION test_get_preview() RETURNS SETOF TEXT AS $f$ +DECLARE + col_cast_def jsonb := $j$[ + { + "attnum":2, + "type": {"name": "numeric", "options": {"precision":5, "scale":2}} + } + ]$j$; + want_records jsonb := $j$[ + {"id": 1, "length": 2.00}, + {"id": 2, "length": 3.00}, + {"id": 3, "length": 4.00}, + {"id": 4, "length": 5.22} + ] + $j$; + have_records jsonb; +BEGIN + PERFORM __setup_create_table(); + CREATE TABLE tab_create_schema.foo(id INTEGER GENERATED BY DEFAULT AS IDENTITY, length FLOAT8); + INSERT INTO tab_create_schema.foo(length) VALUES (2), (3), (4), (5.2225); + have_records := msar.get_preview( + tab_id => 'tab_create_schema.foo'::regclass::oid, + col_cast_def => col_cast_def, + rec_limit => NULL + ); + RETURN NEXT is(have_records, want_records); +END; +$f$ LANGUAGE plpgsql; + + CREATE OR REPLACE FUNCTION test_add_mathesar_table_comment() RETURNS SETOF TEXT AS $f$ DECLARE comment_ text := $c$my "Super;";'; DROP SCHEMA tab_create_schema;'$c$; From 084a4ee130db64d542bcdf94854eb42e54dd8167 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Wed, 26 Jun 2024 15:59:04 +0530 Subject: [PATCH 09/13] quote column names --- db/sql/00_msar.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/db/sql/00_msar.sql b/db/sql/00_msar.sql index 2382a1b014..931ec6afb2 100644 --- a/db/sql/00_msar.sql +++ b/db/sql/00_msar.sql @@ -2507,11 +2507,11 @@ BEGIN SELECT string_agg( 'CAST(' || __msar.build_cast_expr( - msar.get_column_name(tab_id, (col_cast ->> 'attnum')::integer), col_cast -> 'type' ->> 'name' + quote_ident(msar.get_column_name(tab_id, (col_cast ->> 'attnum')::integer)), col_cast -> 'type' ->> 'name' ) || ' AS ' || msar.build_type_text(col_cast -> 'type') || - ')'|| ' AS ' || msar.get_column_name(tab_id, (col_cast ->> 'attnum')::integer), + ')'|| ' AS ' || quote_ident(msar.get_column_name(tab_id, (col_cast ->> 'attnum')::integer)), ', ' ) AS cast_expr FROM jsonb_array_elements(col_cast_def) AS col_cast From ce0d8d2245a07c9fbc252d7935755164a9fc7530 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Wed, 26 Jun 2024 16:06:42 +0530 Subject: [PATCH 10/13] fix merge conflict --- db/tables/operations/import_.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/db/tables/operations/import_.py b/db/tables/operations/import_.py index d9fde5d6dc..7929bff2e3 100644 --- a/db/tables/operations/import_.py +++ b/db/tables/operations/import_.py @@ -2,13 +2,9 @@ import tempfile import clevercsv as csv -<<<<<<< import_preview -from psycopg import sql from db.connection import exec_msar_func from db.columns.operations.alter import _transform_column_alter_dict -======= ->>>>>>> develop from db.tables.operations.create import prepare_table_for_import from db.encoding_utils import get_sql_compatible_encoding from mathesar.models.deprecated import DataFile From 136b252a1ee59e2086b038d5223a276e2cd1d760 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Wed, 26 Jun 2024 16:10:23 +0530 Subject: [PATCH 11/13] fix function name --- db/sql/00_msar.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/sql/00_msar.sql b/db/sql/00_msar.sql index cc0fd6ec4c..260c37d5e1 100644 --- a/db/sql/00_msar.sql +++ b/db/sql/00_msar.sql @@ -2451,7 +2451,7 @@ DECLARE sel_query text; records jsonb; BEGIN - tab_name := __msar.get_relation_name(tab_id); + tab_name := __msar.get_qualified_relation_name(tab_id); sel_query := 'SELECT id, %s FROM %s LIMIT %L'; WITH preview_cte AS ( SELECT string_agg( From a20e663cba091f27a20f4e7b4c1caa3e4aaac1a2 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Wed, 26 Jun 2024 16:18:42 +0530 Subject: [PATCH 12/13] remove id requirement --- db/sql/00_msar.sql | 3 +-- db/sql/test_00_msar.sql | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/db/sql/00_msar.sql b/db/sql/00_msar.sql index 260c37d5e1..be7c43f42f 100644 --- a/db/sql/00_msar.sql +++ b/db/sql/00_msar.sql @@ -2452,7 +2452,7 @@ DECLARE records jsonb; BEGIN tab_name := __msar.get_qualified_relation_name(tab_id); - sel_query := 'SELECT id, %s FROM %s LIMIT %L'; + sel_query := 'SELECT %s FROM %s LIMIT %L'; WITH preview_cte AS ( SELECT string_agg( 'CAST(' || @@ -2465,7 +2465,6 @@ BEGIN ', ' ) AS cast_expr FROM jsonb_array_elements(col_cast_def) AS col_cast - WHERE NOT msar.is_mathesar_id_column(tab_id, (col_cast ->> 'attnum')::integer) ) SELECT __msar.exec_dql(sel_query, cast_expr, tab_name, rec_limit::text) diff --git a/db/sql/test_00_msar.sql b/db/sql/test_00_msar.sql index 86b59081e3..986e3a89e3 100644 --- a/db/sql/test_00_msar.sql +++ b/db/sql/test_00_msar.sql @@ -1482,6 +1482,10 @@ $f$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION test_get_preview() RETURNS SETOF TEXT AS $f$ DECLARE col_cast_def jsonb := $j$[ + { + "attnum": 1, + "type": {"name": "integer"} + }, { "attnum":2, "type": {"name": "numeric", "options": {"precision":5, "scale":2}} From cb78fe9f57d57e13d1282f7041fe83432a05dca0 Mon Sep 17 00:00:00 2001 From: Anish Umale Date: Wed, 26 Jun 2024 16:28:40 +0530 Subject: [PATCH 13/13] clear up documentation about id --- db/sql/00_msar.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/db/sql/00_msar.sql b/db/sql/00_msar.sql index be7c43f42f..b175c85681 100644 --- a/db/sql/00_msar.sql +++ b/db/sql/00_msar.sql @@ -72,8 +72,8 @@ Execute the given command, returning a JSON object describing the records in the Useful for SELECTing from tables. Most useful when you're performing DQL. -Note that you always have to include the primary key column(`id` in case of a Mathesar table) in the -command_template for the returned records to be uniquely identifiable. +Note that you must include the primary key column(`id` in case of a Mathesar table) in the +command_template if you want the returned records to be uniquely identifiable. Args: command: Raw string that will be executed as a command. @@ -101,8 +101,8 @@ Execute a templated command, returning a JSON object describing the records in t The template is given in the first argument, and all further arguments are used to fill in the template. Useful for SELECTing from tables. Most useful when you're performing DQL. -Note that you always have to include the primary key column(`id` in case of a Mathesar table) in the -command_template for the returned records to be uniquely identifiable. +Note that you must include the primary key column(`id` in case of a Mathesar table) in the +command_template if you want the returned records to be uniquely identifiable. Args: command_template: Raw string that will be executed as a command.