Skip to content

Commit 884336f

Browse files
Feature/hck 4561 bbva sequences definition for postgresql re and (#87)
* container-level-config: add sequences tab * RE: add generating script for sequences * container-level-config: add owner field limit for sequence * RE: remove redundant formatting for sequence options * container-level-config: fix default value for sequence cycle property * RE: fix getting options for sequence statement * RE: fix missed arguments wrapping
1 parent 61a8abc commit 884336f

File tree

4 files changed

+305
-2
lines changed

4 files changed

+305
-2
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/**
2+
* @typedef {'bigint' | 'integer' | 'smallint'} DataType
3+
*
4+
* @typedef {{
5+
* cache?: number;
6+
* cycle: boolean;
7+
* dataType: DataType;
8+
* ifNotExist: boolean;
9+
* increment?: number;
10+
* maxValue?: number;
11+
* minValue?: number;
12+
* ownedByColumn: object[];
13+
* ownedByNone: boolean;
14+
* sequenceName: string;
15+
* start?: number;
16+
* temporary: boolean;
17+
* unlogged: boolean;
18+
* }} Sequence
19+
*
20+
* @typedef {{
21+
* key: keyof Sequence;
22+
* clause: string;
23+
* getOption: ({ sequence: Sequence, config: OptionConfig }) => {}
24+
* }} OptionConfig
25+
*/
26+
27+
module.exports = ({
28+
_,
29+
templates,
30+
assignTemplates,
31+
getNamePrefixedWithSchemaName,
32+
}) => {
33+
/**
34+
* @param {string} schemaName
35+
* @param {Sequence[]} sequences
36+
* @returns {string}
37+
*/
38+
const getSequencesScript = (schemaName, sequences) => {
39+
return _.map(sequences, (sequence) => {
40+
const name = getNamePrefixedWithSchemaName(
41+
sequence.sequenceName,
42+
schemaName
43+
);
44+
const ifNotExists = getIfNotExists(sequence);
45+
const sequenceType = getSequenceType(sequence);
46+
const options = getSequenceOptions(sequence);
47+
return assignTemplates(templates.createSequence, {
48+
name,
49+
ifNotExists,
50+
sequenceType,
51+
options,
52+
});
53+
}).join('\n');
54+
};
55+
56+
/**
57+
* @param {Sequence} sequence
58+
* @returns {string}
59+
*/
60+
const getSequenceOptions = (sequence) => {
61+
/**
62+
* @type {Array<OptionConfig>}
63+
*/
64+
const optionConfigs = [
65+
{ getOption, key: 'dataType', clause: 'AS', },
66+
{ getOption, key: 'increment', clause: 'INCREMENT', },
67+
{ getOption, key: 'start', clause: 'START WITH', },
68+
{ getOption, key: 'minValue', clause: 'MINVALUE', },
69+
{ getOption, key: 'maxValue', clause: 'MAXVALUE', },
70+
{ getOption, key: 'cache', clause: 'CACHE', },
71+
{ getOption: getCycle, key: 'cycle' },
72+
{ getOption: getOwnedBy, key: 'ownedByColumn' },
73+
];
74+
75+
const options = optionConfigs
76+
.map((config) => wrapOption(config.getOption({ sequence, config })))
77+
.filter(Boolean)
78+
.join('');
79+
80+
return options ? wrapOptionsBlock(options) : options;
81+
};
82+
83+
/**
84+
* @param {{ sequence: Sequence; config: OptionConfig }} param0
85+
* @returns {string}
86+
*/
87+
const getOption = ({ sequence, config }) => {
88+
const value = sequence[config.key];
89+
return value || value === 0 ? `${config.clause} ${value}` : '';
90+
};
91+
92+
/**
93+
* @param {string} option
94+
* @returns {string}
95+
*/
96+
const wrapOption = (option) => {
97+
return option ? `\t${option}\n` : '';
98+
};
99+
100+
/**
101+
* @param {string} option
102+
* @returns {string}
103+
*/
104+
const wrapOptionsBlock = (option) => {
105+
return '\n' + option.replace(/\n$/, '');
106+
};
107+
108+
/**
109+
* @param {Sequence} sequence
110+
* @returns {string}
111+
*/
112+
const getIfNotExists = (sequence) => {
113+
return sequence.ifNotExist ? ' IF NOT EXISTS' : '';
114+
};
115+
116+
/**
117+
* @param {Sequence} sequence
118+
* @returns {string}
119+
*/
120+
const getSequenceType = (sequence) => {
121+
if (sequence.temporary) {
122+
return ' TEMPORARY';
123+
}
124+
125+
if (sequence.unlogged) {
126+
return ' UNLOGGED';
127+
}
128+
129+
return '';
130+
};
131+
132+
/**
133+
* @param {{ sequence: Sequence }} param0
134+
* @returns {string}
135+
*/
136+
const getCycle = ({ sequence }) => {
137+
if (sequence.cycle === true) {
138+
return 'CYCLE';
139+
}
140+
141+
if (sequence.cycle === false) {
142+
return 'NO CYCLE';
143+
}
144+
145+
return '';
146+
};
147+
148+
/**
149+
* @param {{ sequence: Sequence }} param0
150+
* @returns {string}
151+
*/
152+
const getOwnedBy = ({ sequence }) => {
153+
if (sequence.ownedByNone) {
154+
return 'OWNED BY NONE';
155+
}
156+
157+
const ownedColumn = sequence.ownedByColumn?.[0];
158+
159+
if (ownedColumn) {
160+
const [tableName, columnName] = ownedColumn.name?.split('.') || [];
161+
const ownedColumnName = getNamePrefixedWithSchemaName(
162+
columnName,
163+
tableName
164+
);
165+
return `OWNED BY ${ownedColumnName}`;
166+
}
167+
168+
return '';
169+
};
170+
171+
return {
172+
getSequencesScript,
173+
};
174+
};

forward_engineering/ddlProvider/ddlProvider.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ module.exports = (baseProvider, options, app) => {
5656
getNamePrefixedWithSchemaName,
5757
});
5858

59+
const { getSequencesScript } = require('./ddlHelpers/sequenceHelper')({
60+
_,
61+
templates,
62+
assignTemplates,
63+
getNamePrefixedWithSchemaName,
64+
});
65+
5966
const { getTableTemporaryValue, getTableOptions } = require('./ddlHelpers/tableHelper')({
6067
_,
6168
checkAllKeysDeactivated,
@@ -119,7 +126,7 @@ module.exports = (baseProvider, options, app) => {
119126
});
120127
},
121128

122-
createSchema({ schemaName, ifNotExist, comments, udfs, procedures }) {
129+
createSchema({ schemaName, ifNotExist, comments, udfs, procedures, sequences }) {
123130
const comment = assignTemplates(templates.comment, {
124131
object: 'SCHEMA',
125132
objectName: wrapInQuotes(schemaName),
@@ -134,8 +141,9 @@ module.exports = (baseProvider, options, app) => {
134141

135142
const createFunctionStatement = getFunctionsScript(schemaName, udfs);
136143
const createProceduresStatement = getProceduresScript(schemaName, procedures);
144+
const createSequencesStatement = getSequencesScript(schemaName, sequences);
137145

138-
return _.chain([schemaStatement, createFunctionStatement, createProceduresStatement])
146+
return _.chain([schemaStatement, createFunctionStatement, createProceduresStatement, createSequencesStatement])
139147
.compact()
140148
.map(_.trim)
141149
.join('\n\n')
@@ -716,6 +724,7 @@ module.exports = (baseProvider, options, app) => {
716724
comments: containerData.description,
717725
udfs: data?.udfs || [],
718726
procedures: data?.procedures || [],
727+
sequences: data?.sequences || [],
719728
dbVersion,
720729
};
721730
},

forward_engineering/ddlProvider/templates.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,9 @@ module.exports = {
110110
'\tON ${tableName}\n' +
111111
'${options}' +
112112
'\tEXECUTE ${functionKey} ${functionName};\n',
113+
114+
createSequence:
115+
'CREATE${sequenceType} SEQUENCE${ifNotExists} ${name}' +
116+
'${options}' +
117+
';\n'
113118
};

properties_pane/container_level/containerLevelConfig.json

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,121 @@ making sure that you maintain a proper JSON format.
133133
],
134134
"containerLevelKeys": []
135135
},
136+
{
137+
"lowerTab": "Sequences",
138+
"structure": [
139+
{
140+
"propertyName": "Sequences",
141+
"propertyType": "group",
142+
"propertyKeyword": "sequences",
143+
"propertyTooltip": "",
144+
"structure": [
145+
{
146+
"propertyName": "Sequence name",
147+
"propertyKeyword": "sequenceName",
148+
"propertyTooltip": "",
149+
"propertyType": "text"
150+
},
151+
{
152+
"propertyName": "If not exists",
153+
"propertyKeyword": "ifNotExist",
154+
"propertyTooltip": "Do not throw an error if a relation with the same name already exists. A notice is issued in this case. Note that there is no guarantee that the existing relation is anything like the sequence that would have been created — it might not even be a sequence.",
155+
"propertyType": "checkbox"
156+
},
157+
{
158+
"propertyName": "Temporary",
159+
"propertyKeyword": "temporary",
160+
"propertyTooltip": "If specified, the sequence object is created only for this session, and is automatically dropped on session exit. Existing permanent sequences with the same name are not visible (in this session) while the temporary sequence exists, unless they are referenced with schema-qualified names.",
161+
"defaultValue": false,
162+
"propertyType": "checkbox"
163+
},
164+
{
165+
"propertyName": "Unlogged",
166+
"propertyKeyword": "unlogged",
167+
"propertyTooltip": "If specified, the sequence is created as an unlogged sequence. Changes to unlogged sequences are not written to the write-ahead log. They are not crash-safe: an unlogged sequence is automatically reset to its initial state after a crash or unclean shutdown. Unlogged sequences are also not replicated to standby servers.",
168+
"defaultValue": false,
169+
"propertyType": "checkbox"
170+
},
171+
{
172+
"propertyName": "Data type",
173+
"propertyKeyword": "dataType",
174+
"propertyTooltip": "The data type determines the default minimum and maximum values of the sequence.",
175+
"propertyType": "select",
176+
"defaultValue": "bigint",
177+
"options": [
178+
"bigint",
179+
"integer",
180+
"smallint"
181+
]
182+
},
183+
{
184+
"propertyName": "Start",
185+
"propertyKeyword": "start",
186+
"propertyType": "numeric",
187+
"valueType": "number",
188+
"propertyTooltip": "Allows the sequence to begin anywhere. The default starting value is minvalue for ascending sequences and maxvalue for descending ones."
189+
},
190+
{
191+
"propertyName": "Increment",
192+
"propertyKeyword": "increment",
193+
"propertyType": "numeric",
194+
"valueType": "number",
195+
"propertyTooltip": "The data type determines the default minimum and maximum values of the sequence."
196+
},
197+
{
198+
"propertyName": "Min value",
199+
"propertyKeyword": "minValue",
200+
"propertyType": "numeric",
201+
"valueType": "number",
202+
"propertyTooltip": "Determines the minimum value a sequence can generate. If this clause is not supplied is specified, then defaults will be used. The default for an ascending sequence is 1. The default for a descending sequence is the minimum value of the data type."
203+
},
204+
{
205+
"propertyName": "Max value",
206+
"propertyKeyword": "maxValue",
207+
"propertyType": "numeric",
208+
"valueType": "number",
209+
"propertyTooltip": "Determines the maximum value for the sequence. If this clause is not supplied is specified, then default values will be used. The default for an ascending sequence is the maximum value of the data type. The default for a descending sequence is -1."
210+
},
211+
{
212+
"propertyName": "Cache",
213+
"propertyKeyword": "cache",
214+
"propertyType": "numeric",
215+
"valueType": "number",
216+
"propertyTooltip": "specifies how many sequence numbers are to be preallocated and stored in memory for faster access. The minimum value is 1 (only one value can be generated at a time, i.e., no cache), and this is also the default",
217+
"minValue": 1
218+
},
219+
{
220+
"propertyName": "Cycle",
221+
"propertyKeyword": "cycle",
222+
"propertyTooltip": "Allows the sequence to wrap around when the maxvalue or minvalue has been reached by an ascending or descending sequence respectively. If the limit is reached, the next number generated will be the minvalue or maxvalue, respectively.",
223+
"defaultValue": false,
224+
"propertyType": "checkbox"
225+
},
226+
{
227+
"propertyName": "Owned by none",
228+
"propertyKeyword": "ownedByNone",
229+
"propertyTooltip": "Specifies that there is no association with a specific table column, such that if that column (or its whole table) is dropped, the sequence will be automatically dropped as well. ",
230+
"defaultValue": true,
231+
"propertyType": "checkbox"
232+
},
233+
{
234+
"propertyName": "Owned by column",
235+
"propertyKeyword": "ownedByColumn",
236+
"propertyType": "fieldList",
237+
"template": "orderedList",
238+
"propertyTooltip": "Causes the sequence to be associated with a specific table column, such that if that column (or its whole table) is dropped, the sequence will be automatically dropped as well. The specified table must have the same owner and be in the same schema as the sequence.",
239+
"templateOptions": {
240+
"maxFields": 1
241+
},
242+
"dependency": {
243+
"key": "ownedByNone",
244+
"value": false
245+
}
246+
}
247+
]
248+
}
249+
]
250+
},
136251
{
137252
"lowerTab": "Functions",
138253
"structure": [

0 commit comments

Comments
 (0)