Skip to content

Commit be63f61

Browse files
committed
Allow users to customize ofType columns during table creation #223
1 parent 5103c47 commit be63f61

9 files changed

Lines changed: 1474 additions & 781 deletions

File tree

web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,20 @@ def get_oftype(self, gid, sid, did, scid, tid=None):
797797
if not status:
798798
return internal_server_error(errormsg=type_cols)
799799

800+
# Mark columns as inherited from type (not table)
801+
# so the UI allows editing defaults/constraints
802+
# Also store original values for comparison later
803+
for col in type_cols['rows']:
804+
if 'inheritedfrom' in col:
805+
col['inheritedfromtype'] = col['inheritedfrom']
806+
# Keep inheritedfrom for backward compatibility
807+
# but UI will check inheritedfromtype first
808+
809+
# Store original values from the composite type
810+
# This allows backend to detect actual modifications
811+
col['original_defval'] = col.get('defval')
812+
col['original_attnotnull'] = col.get('attnotnull', False)
813+
800814
res.append({
801815
'label': row['typname'],
802816
'value': row['typname'],

web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/static/js/column.ui.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ export default class ColumnSchema extends BaseUISchema {
160160
return { cell: this.attlenRange(state) ? 'int' : '' };
161161
}
162162

163+
isInheritedFromType(state) {
164+
return !isEmptyString(state.inheritedfromtype);
165+
}
166+
163167
get baseFields() {
164168
let obj = this;
165169

@@ -284,6 +288,30 @@ export default class ColumnSchema extends BaseUISchema {
284288
}
285289
return false;
286290
},
291+
},{
292+
/* This field is used to track inheritance from composite types */
293+
id: 'inheritedfromtype',
294+
label: gettext('Inherited from type'),
295+
type: 'text',
296+
visible: false,
297+
},{
298+
/* This field is used to track inheritance from parent tables */
299+
id: 'inheritedfromtable',
300+
label: gettext('Inherited from table'),
301+
type: 'text',
302+
visible: false,
303+
},{
304+
/* Store original DEFAULT from composite type to detect modifications */
305+
id: 'original_defval',
306+
label: gettext('Original Default'),
307+
type: 'text',
308+
visible: false,
309+
},{
310+
/* Store original NOT NULL from composite type to detect modifications */
311+
id: 'original_attnotnull',
312+
label: gettext('Original NOT NULL'),
313+
type: 'boolean',
314+
visible: false,
287315
},{
288316
id:'geometry', label: gettext('Geometry Type'), deps: ['cltype'],
289317
group: gettext('Definition'), type: 'select', options: this.geometryTypes,
@@ -712,4 +740,4 @@ export default class ColumnSchema extends BaseUISchema {
712740

713741
return false;
714742
}
715-
}
743+
}

web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,60 @@ def parse_format_columns(data, mode=None):
364364
# tables 'CREATE' mode
365365
final_columns = []
366366

367+
# Get list of columns in primary key constraint
368+
pk_columns = set()
369+
if 'primary_key' in data and len(data['primary_key']) > 0:
370+
for pk in data['primary_key']:
371+
if 'columns' in pk:
372+
for col in pk['columns']:
373+
if 'column' in col:
374+
pk_columns.add(col['column'])
375+
367376
for c in columns:
377+
# Include non-inherited columns
368378
if c.get('inheritedfrom', None) is None:
369379
final_columns.append(c)
380+
# Also include columns inherited from composite types (OF TYPE)
381+
# that have modifications (WITH OPTIONS clause)
382+
elif c.get('inheritedfromtype', None) is not None:
383+
# Check if column has been modified or is in a constraint
384+
has_modifications = False
385+
386+
# Check if column is in PRIMARY KEY constraint
387+
# Note: We don't include the column for PRIMARY KEY because
388+
# it's added as a separate table-level constraint
389+
# Uncomment this if you want column-level PRIMARY KEY:
390+
# if c.get('name') in pk_columns:
391+
# has_modifications = True
392+
393+
# Check for PRIMARY KEY (marked via is_primary_key checkbox)
394+
if c.get('is_primary_key'):
395+
has_modifications = True
396+
397+
# Check if DEFAULT value was actually modified
398+
# (different from type)
399+
original_defval = c.get('original_defval')
400+
current_defval = c.get('defval')
401+
# Compare as strings, treating None and empty string
402+
# as equivalent
403+
orig_val = str(original_defval) \
404+
if original_defval is not None else ''
405+
curr_val = str(current_defval) \
406+
if current_defval is not None else ''
407+
if orig_val != curr_val:
408+
has_modifications = True
409+
410+
# Check if NOT NULL was actually modified
411+
# (different from type)
412+
original_attnotnull = c.get('original_attnotnull', False)
413+
current_attnotnull = c.get('attnotnull', False)
414+
if original_attnotnull != current_attnotnull:
415+
has_modifications = True
416+
417+
if has_modifications:
418+
# Mark this column to use WITH OPTIONS syntax in template
419+
c['has_with_options'] = True
420+
final_columns.append(c)
370421

371422
# Now we have all lis of columns which we need
372423
# to include in our create definition, Let's format them

0 commit comments

Comments
 (0)