mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-22 00:37:36 -06:00
Reverse engineer serial columns when generating ERD for database/table. #6958
This commit is contained in:
parent
9611e06dcf
commit
115208c8d8
@ -17,6 +17,8 @@ from pgadmin.browser.server_groups.servers.databases.schemas.utils \
|
||||
import DataTypeReader
|
||||
from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
|
||||
parse_priv_to_db
|
||||
from pgadmin.browser.server_groups.servers.databases.utils \
|
||||
import make_object_name
|
||||
from functools import wraps
|
||||
|
||||
|
||||
@ -225,7 +227,8 @@ def parse_options_for_column(db_variables):
|
||||
|
||||
@get_template_path
|
||||
def get_formatted_columns(conn, tid, data, other_columns,
|
||||
table_or_type, template_path=None):
|
||||
table_or_type, template_path=None,
|
||||
with_serial=False):
|
||||
"""
|
||||
This function will iterate and return formatted data for all
|
||||
the columns.
|
||||
@ -254,6 +257,28 @@ def get_formatted_columns(conn, tid, data, other_columns,
|
||||
col['inheritedfrom' + table_or_type] = \
|
||||
other_col['inheritedfrom']
|
||||
|
||||
if with_serial:
|
||||
# Here we assume if a column is serial
|
||||
serial_seq_name = make_object_name(
|
||||
data['name'], col['name'], 'seq')
|
||||
# replace the escaped quotes for comparison
|
||||
defval = (col.get('defval', '') or '').replace("''", "'").\
|
||||
replace('""', '"')
|
||||
|
||||
if serial_seq_name in defval and defval.startswith("nextval('")\
|
||||
and col['typname'] in ('integer', 'smallint', 'bigint'):
|
||||
|
||||
serial_type = {
|
||||
'integer': 'serial',
|
||||
'smallint': 'smallserial',
|
||||
'bigint': 'bigserial'
|
||||
}[col['typname']]
|
||||
|
||||
col['displaytypname'] = serial_type
|
||||
col['cltype'] = serial_type
|
||||
col['typname'] = serial_type
|
||||
col['defval'] = ''
|
||||
|
||||
data['columns'] = all_columns
|
||||
|
||||
if 'columns' in data and len(data['columns']) > 0:
|
||||
|
@ -164,7 +164,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
|
||||
|
||||
return wrap
|
||||
|
||||
def _formatter(self, did, scid, tid, data):
|
||||
def _formatter(self, did, scid, tid, data, with_serial_cols=False):
|
||||
"""
|
||||
Args:
|
||||
data: dict of query result
|
||||
@ -234,7 +234,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
|
||||
# columns properties.sql, so we need to set template path
|
||||
data = column_utils.get_formatted_columns(self.conn, tid,
|
||||
data, other_columns,
|
||||
table_or_type)
|
||||
table_or_type,
|
||||
with_serial=with_serial_cols)
|
||||
|
||||
self._add_constrints_to_output(data, did, tid)
|
||||
|
||||
@ -493,7 +494,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
|
||||
|
||||
return condition
|
||||
|
||||
def fetch_tables(self, sid, did, scid, tid=None):
|
||||
def fetch_tables(self, sid, did, scid, tid=None, with_serial_cols=False):
|
||||
"""
|
||||
This function will fetch the list of all the tables
|
||||
and will be used by schema diff.
|
||||
@ -502,6 +503,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
|
||||
:param did: Database Id
|
||||
:param scid: Schema Id
|
||||
:param tid: Table Id
|
||||
:param with_serial_cols: Boolean
|
||||
:return: Table dataset
|
||||
"""
|
||||
|
||||
@ -513,7 +515,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
|
||||
|
||||
data = BaseTableView.properties(
|
||||
self, 0, sid, did, scid, tid, res=data,
|
||||
return_ajax_response=False
|
||||
with_serial_cols=with_serial_cols,
|
||||
return_ajax_response=False,
|
||||
)
|
||||
|
||||
return True, data
|
||||
@ -534,6 +537,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
|
||||
if status:
|
||||
data = BaseTableView.properties(
|
||||
self, 0, sid, did, scid, row['oid'], res=data,
|
||||
with_serial_cols=with_serial_cols,
|
||||
return_ajax_response=False
|
||||
)
|
||||
|
||||
@ -1750,6 +1754,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
|
||||
"""
|
||||
res = kwargs.get('res')
|
||||
return_ajax_response = kwargs.get('return_ajax_response', True)
|
||||
with_serial_cols = kwargs.get('with_serial_cols', False)
|
||||
|
||||
data = res['rows'][0]
|
||||
|
||||
@ -1768,7 +1773,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
|
||||
'vacuum_settings_str'
|
||||
].replace('=', ' = ')
|
||||
|
||||
data = self._formatter(did, scid, tid, data)
|
||||
data = self._formatter(did, scid, tid, data,
|
||||
with_serial_cols=with_serial_cols)
|
||||
|
||||
# Fetch partition of this table if it is partitioned table.
|
||||
if 'is_partitioned' in data and data['is_partitioned']:
|
||||
|
@ -126,3 +126,26 @@ def get_attributes_from_db_info(manager, kwargs):
|
||||
return datistemplate, datallowconn
|
||||
else:
|
||||
return False, True
|
||||
|
||||
|
||||
def make_object_name(name1: str, name2: str, label: str) -> str:
|
||||
"""
|
||||
This function is python port for makeObjectName in postgres.
|
||||
https://github.com/postgres/postgres/blob/master/src/backend/commands/indexcmds.c
|
||||
It is used by postgres to generate index name for auto index,
|
||||
sequence name for serial columns.
|
||||
:param name1: generally table name
|
||||
:param name2: generally column name
|
||||
:param label: a suffix
|
||||
:return: name string
|
||||
"""
|
||||
namedatalen: int = 63
|
||||
result = '{0}_{1}_{2}'.format(name1, name2, label)
|
||||
while len(result) > namedatalen:
|
||||
if len(name1) > len(name2):
|
||||
name1 = name1[:-1]
|
||||
else:
|
||||
name2 = name2[:-1]
|
||||
result = '{0}_{1}_{2}'.format(name1, name2, label)
|
||||
|
||||
return result
|
||||
|
@ -289,7 +289,7 @@ class TableNodeWidgetRaw extends React.Component {
|
||||
<Box margin="auto 0">
|
||||
<span data-test="column-name">{col.name}</span>
|
||||
{this.state.show_details &&
|
||||
<span data-test="column-type">{cltype}</span>}
|
||||
<span data-test="column-type">{cltype + (col.colconstype == 'i' ? ` (${gettext('IDENTITY')})`:'')}</span>}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box marginLeft="auto" padding="0" minHeight="0" display="flex" alignItems="center">
|
||||
|
@ -40,7 +40,8 @@ class ERDTableView(BaseTableView, DataTypeReader):
|
||||
all_tables = []
|
||||
for row in schemas['rows']:
|
||||
status, res = \
|
||||
BaseTableView.fetch_tables(self, sid, did, row['oid'])
|
||||
BaseTableView.fetch_tables(self, sid, did, row['oid'],
|
||||
with_serial_cols=True)
|
||||
if not status:
|
||||
return status, res
|
||||
|
||||
@ -53,7 +54,8 @@ class ERDTableView(BaseTableView, DataTypeReader):
|
||||
tid=None, related={}, maxdepth=0, currdepth=0):
|
||||
|
||||
status, res = \
|
||||
BaseTableView.fetch_tables(self, sid, did, scid, tid=tid)
|
||||
BaseTableView.fetch_tables(self, sid, did, scid, tid=tid,
|
||||
with_serial_cols=True)
|
||||
|
||||
if not status:
|
||||
return status, res
|
||||
|
Loading…
Reference in New Issue
Block a user