Skip to content

Commit 080fcc1

Browse files
authored
Fix column ordering in unique/primary key constraint properties
The fromRaw formatter for the Columns field in unique constraint and primary key properties used _.filter(allOptions, ...), which preserved the order of allOptions (table column position) rather than the constraint-defined column order from backendVal. Replaced with _.find mapped over backendVal to preserve the correct constraint column order. Added unit tests for cell and type formatter functions to verify column ordering is preserved.
1 parent 93e2f23 commit 080fcc1

4 files changed

Lines changed: 102 additions & 6 deletions

File tree

web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/js/primary_key.ui.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,10 @@ export default class PrimaryKeySchema extends BaseUISchema {
125125
multiple: true,
126126
formatter: {
127127
fromRaw: (backendVal, allOptions)=>{
128-
/* remove the column key and pass as array */
129-
let optValues = (backendVal||[]).map((singleVal)=>singleVal.column);
130-
return _.filter(allOptions, (opt)=>optValues.indexOf(opt.value)>-1);
128+
/* remove the column key and pass as array preserving constraint column order */
129+
return (backendVal||[]).map((singleVal)=>
130+
_.find(allOptions, (opt)=>opt.value === singleVal.column)
131+
).filter(Boolean);
131132
},
132133
toRaw: (value)=>{
133134
/* take the array and convert to column key collection */

web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/js/unique_constraint.ui.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,10 @@ export default class UniqueConstraintSchema extends BaseUISchema {
125125
multiple: true,
126126
formatter: {
127127
fromRaw: (backendVal, allOptions) => {
128-
/* remove the column key and pass as array */
129-
let optValues = (backendVal||[]).map((singleVal) => singleVal.column);
130-
return _.filter(allOptions, (opt) => optValues.indexOf(opt.value)>-1);
128+
/* remove the column key and pass as array preserving constraint column order */
129+
return (backendVal||[]).map((singleVal) =>
130+
_.find(allOptions, (opt) => opt.value === singleVal.column)
131+
).filter(Boolean);
131132
},
132133
toRaw: (value)=>{
133134
/* take the array and convert to column key collection */

web/regression/javascript/schema_ui_files/primary_key.ui.spec.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,53 @@ describe('PrimaryKeySchema', ()=>{
138138

139139
});
140140

141+
it('columns cell formatter', ()=>{
142+
let cellFormatter = _.find(schemaObj.fields, (f)=>f.id=='columns').cell().controlProps.formatter;
143+
expect(cellFormatter.fromRaw([{
144+
column: 'user_id',
145+
},{
146+
column: 'client_order_id',
147+
}])).toBe('user_id,client_order_id');
148+
149+
expect(cellFormatter.fromRaw([])).toBe('');
150+
});
151+
152+
it('columns type formatter preserves constraint column order', ()=>{
153+
let typeFormatter = _.find(schemaObj.fields, (f)=>f.id=='columns').type().controlProps.formatter;
154+
155+
/* allOptions are in table column position order (alphabetical here) */
156+
let allOptions = [
157+
{value: 'alpha', label: 'alpha'},
158+
{value: 'beta', label: 'beta'},
159+
{value: 'gamma', label: 'gamma'},
160+
];
161+
162+
/* backendVal comes from the constraint definition in a different order */
163+
let backendVal = [{column: 'gamma'}, {column: 'alpha'}];
164+
165+
let result = typeFormatter.fromRaw(backendVal, allOptions);
166+
167+
/* result must preserve backendVal order, not allOptions order */
168+
expect(result).toEqual([
169+
{value: 'gamma', label: 'gamma'},
170+
{value: 'alpha', label: 'alpha'},
171+
]);
172+
173+
/* empty and null values should be handled gracefully */
174+
expect(typeFormatter.fromRaw([], allOptions)).toEqual([]);
175+
expect(typeFormatter.fromRaw(null, allOptions)).toEqual([]);
176+
});
177+
178+
it('columns type formatter toRaw', ()=>{
179+
let typeFormatter = _.find(schemaObj.fields, (f)=>f.id=='columns').type().controlProps.formatter;
180+
expect(typeFormatter.toRaw([{value: 'user_id'}, {value: 'client_order_id'}])).toEqual([
181+
{column: 'user_id'},
182+
{column: 'client_order_id'},
183+
]);
184+
expect(typeFormatter.toRaw([])).toEqual([]);
185+
expect(typeFormatter.toRaw(null)).toEqual([]);
186+
});
187+
141188
it('validate', ()=>{
142189
let state = {};
143190
let setError = jest.fn();

web/regression/javascript/schema_ui_files/unique_constraint.ui.spec.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,53 @@ describe('UniqueConstraintSchema', ()=>{
137137

138138
});
139139

140+
it('columns cell formatter', ()=>{
141+
let cellFormatter = _.find(schemaObj.fields, (f)=>f.id=='columns').cell().controlProps.formatter;
142+
expect(cellFormatter.fromRaw([{
143+
column: 'user_id',
144+
},{
145+
column: 'client_order_id',
146+
}])).toBe('user_id,client_order_id');
147+
148+
expect(cellFormatter.fromRaw([])).toBe('');
149+
});
150+
151+
it('columns type formatter preserves constraint column order', ()=>{
152+
let typeFormatter = _.find(schemaObj.fields, (f)=>f.id=='columns').type().controlProps.formatter;
153+
154+
/* allOptions are in table column position order (alphabetical here) */
155+
let allOptions = [
156+
{value: 'alpha', label: 'alpha'},
157+
{value: 'beta', label: 'beta'},
158+
{value: 'gamma', label: 'gamma'},
159+
];
160+
161+
/* backendVal comes from the constraint definition in a different order */
162+
let backendVal = [{column: 'gamma'}, {column: 'alpha'}];
163+
164+
let result = typeFormatter.fromRaw(backendVal, allOptions);
165+
166+
/* result must preserve backendVal order, not allOptions order */
167+
expect(result).toEqual([
168+
{value: 'gamma', label: 'gamma'},
169+
{value: 'alpha', label: 'alpha'},
170+
]);
171+
172+
/* empty and null values should be handled gracefully */
173+
expect(typeFormatter.fromRaw([], allOptions)).toEqual([]);
174+
expect(typeFormatter.fromRaw(null, allOptions)).toEqual([]);
175+
});
176+
177+
it('columns type formatter toRaw', ()=>{
178+
let typeFormatter = _.find(schemaObj.fields, (f)=>f.id=='columns').type().controlProps.formatter;
179+
expect(typeFormatter.toRaw([{value: 'user_id'}, {value: 'client_order_id'}])).toEqual([
180+
{column: 'user_id'},
181+
{column: 'client_order_id'},
182+
]);
183+
expect(typeFormatter.toRaw([])).toEqual([]);
184+
expect(typeFormatter.toRaw(null)).toEqual([]);
185+
});
186+
140187
it('validate', ()=>{
141188
let state = {};
142189
let setError = jest.fn();

0 commit comments

Comments
 (0)