Skip to content

Commit 23e802a

Browse files
ivan-m-devLinsted
andauthored
HCK-16175: add support of EXTERNAL tables for FE (#77)
* HCK-16175: add support of EXTERNAL tables for FE * HCK-16175: fix Sonar issue --------- Co-authored-by: Linsted <ivan.malenko18@gmail.com>
1 parent d2f5c2f commit 23e802a

5 files changed

Lines changed: 368 additions & 17 deletions

File tree

forward_engineering/configs/templates.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ module.exports = {
1414
createTableAs:
1515
'CREATE ${temporary}TABLE "${schemaName}"."${name}" ${backup}${tableAttribute} AS ${query};\n${comment}${columnDescriptions}',
1616

17+
createExternalTable:
18+
'CREATE EXTERNAL TABLE "${schemaName}"."${name}" (${columnDefinitions})${partitionedBy}${rowFormat}${storedAs}${location}${tableProperties};${comment}${columnDescriptions}',
19+
20+
createExternalTableAs:
21+
'CREATE EXTERNAL TABLE "${schemaName}"."${name}"${partitionedBy}${rowFormat}${storedAs}${location}${tableProperties} AS\n${query};${comment}${columnDescriptions}',
22+
1723
createView:
1824
'CREATE${orReplace} VIEW "${schemaName}"."${name}"(\n' +
1925
'\t${column_list}\n' +

forward_engineering/ddlProvider.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ module.exports = (baseProvider, options, app) => {
2121
setOrReplace,
2222
getCompositeName,
2323
toString,
24+
parseTextArea,
25+
parseProps,
26+
getRowFormat,
27+
getStoredAs,
2428
} = require('./helpers/general')(app);
2529
const {
2630
decorateType,
@@ -34,6 +38,49 @@ module.exports = (baseProvider, options, app) => {
3438
} = require('./helpers/columnDefinitionHelper')(app);
3539
const { generateConstraint } = require('./helpers/constraintHelper')(app);
3640

41+
const buildExternalTable = ({ tableData, schemaName, asSelect, isActivated, comment, columnDescriptions }) => {
42+
const partitionedBy = tableData.partitionedBy
43+
? `\nPARTITIONED BY (${parseTextArea(tableData.partitionedBy)})`
44+
: '';
45+
46+
const rowFormat = getRowFormat(tableData);
47+
const storedAs = getStoredAs(tableData);
48+
49+
const location = tableData.externalLocation ? `\nLOCATION ${toString(tableData.externalLocation)}` : '';
50+
const tblProperties = tableData.tableProperties
51+
? `\nTABLE PROPERTIES (${parseProps(tableData.tableProperties)})`
52+
: '';
53+
const columnDefinitions = getColumnsDefinitions(tableData.columns, isActivated);
54+
55+
if (asSelect) {
56+
return assignTemplates(templates.createExternalTableAs, {
57+
name: tableData.name,
58+
schemaName,
59+
partitionedBy,
60+
rowFormat,
61+
storedAs,
62+
location,
63+
tableProperties: tblProperties,
64+
query: asSelect,
65+
comment: tableData.comment ? comment : '',
66+
columnDescriptions,
67+
});
68+
}
69+
70+
return assignTemplates(templates.createExternalTable, {
71+
name: tableData.name,
72+
schemaName,
73+
columnDefinitions: columnDefinitions === '' ? '' : '\n\t' + columnDefinitions,
74+
partitionedBy,
75+
rowFormat,
76+
storedAs,
77+
location,
78+
tableProperties: tblProperties,
79+
comment: tableData.comment ? comment : '',
80+
columnDescriptions,
81+
});
82+
};
83+
3784
return {
3885
createSchema({
3986
name,
@@ -107,6 +154,17 @@ module.exports = (baseProvider, options, app) => {
107154
tableData.columnDefinitions,
108155
);
109156

157+
if (tableData.externalTable) {
158+
return buildExternalTable({
159+
tableData,
160+
schemaName,
161+
asSelect,
162+
isActivated,
163+
comment,
164+
columnDescriptions,
165+
});
166+
}
167+
110168
if (asSelect) {
111169
return assignTemplates(templates.createTableAs, {
112170
name: tableData.name,
@@ -338,6 +396,17 @@ module.exports = (baseProvider, options, app) => {
338396
? ''
339397
: generateConstraint(sortKey, templates.compoundSortKey, jsonSchema.isActivated, { sortStyle }),
340398
query: '',
399+
externalTable: firstTab.externalTable,
400+
partitionedBy: firstTab.partitionedBy,
401+
rowFormatType: firstTab.rowFormatType,
402+
rowFormatDelimited: firstTab.rowFormatDelimited,
403+
rowFormatSerde: firstTab.rowFormatSerde,
404+
serdeProperties: firstTab.serdeProperties,
405+
storedAs: firstTab.storedAs,
406+
inputFormatClass: firstTab.inputFormatClass,
407+
outputFormatClass: firstTab.outputFormatClass,
408+
externalLocation: firstTab.externalLocation,
409+
tableProperties: firstTab.tableProperties,
341410
};
342411
},
343412

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
const DROP_STATEMENTS = ['DROP SCHEMA', 'DROP TABLE', 'DROP FUNCTION', 'DROP PROCEDURE', 'DROP COLUMN', 'DROP VIEW'];
22

3+
const ROW_FORMAT_TYPES = Object.freeze({
4+
DELIMITED: 'DELIMITED',
5+
SERDE: 'SERDE',
6+
});
7+
8+
const STORED_AS_TYPES = Object.freeze({
9+
INPUT_OUTPUT_FORMAT: 'INPUTFORMAT / OUTPUTFORMAT',
10+
});
11+
312
module.exports = {
413
DROP_STATEMENTS,
14+
ROW_FORMAT_TYPES,
15+
STORED_AS_TYPES,
516
};

forward_engineering/helpers/general.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const _ = require('lodash');
22
const { commentIfDeactivated } = require('./commentDeactivatedHelper');
3+
const { ROW_FORMAT_TYPES, STORED_AS_TYPES } = require('./constants');
34

45
module.exports = app => {
56
const { checkAllKeysActivated, clean, tab } = app.require('@hackolade/ddl-fe-utils').general;
@@ -178,6 +179,64 @@ module.exports = app => {
178179
}
179180
};
180181

182+
const parseTextArea = text =>
183+
text
184+
? text
185+
.split('\n')
186+
.map(l => l.trim())
187+
.filter(Boolean)
188+
.join(', ')
189+
: '';
190+
191+
const parseProps = text => {
192+
if (!text) return '';
193+
194+
return text
195+
.split('\n')
196+
.map(line => line.trim())
197+
.filter(line => line.includes('='))
198+
.map(line => {
199+
const [propertyKey, ...valueParts] = line.split('=');
200+
const propertyValue = valueParts.join('=').trim();
201+
202+
return `'${escape(propertyKey.trim())}'='${escape(propertyValue)}'`;
203+
})
204+
.join(', ');
205+
};
206+
207+
const getRowFormat = tableData => {
208+
if (tableData.rowFormatType === ROW_FORMAT_TYPES.DELIMITED && tableData.rowFormatDelimited) {
209+
return `\nROW FORMAT DELIMITED ${tableData.rowFormatDelimited}`;
210+
}
211+
212+
if (tableData.rowFormatType === ROW_FORMAT_TYPES.SERDE && tableData.rowFormatSerde) {
213+
let format = `\nROW FORMAT SERDE ${toString(tableData.rowFormatSerde)}`;
214+
const serdeProps = parseProps(tableData.serdeProperties);
215+
216+
if (serdeProps) {
217+
format += `\nWITH SERDEPROPERTIES (${serdeProps})`;
218+
}
219+
return format;
220+
}
221+
222+
return '';
223+
};
224+
225+
const getStoredAs = tableData => {
226+
if (tableData.storedAs === STORED_AS_TYPES.INPUT_OUTPUT_FORMAT) {
227+
if (tableData.inputFormatClass && tableData.outputFormatClass) {
228+
return `\nSTORED AS INPUTFORMAT ${toString(tableData.inputFormatClass)}\nOUTPUTFORMAT ${toString(tableData.outputFormatClass)}`;
229+
}
230+
return '';
231+
}
232+
233+
if (tableData.storedAs) {
234+
return `\nSTORED AS ${tableData.storedAs}`;
235+
}
236+
237+
return '';
238+
};
239+
181240
return {
182241
toString,
183242
toNumber,
@@ -195,5 +254,9 @@ module.exports = app => {
195254
filterProcedure,
196255
setOrReplace,
197256
getCompositeName,
257+
parseTextArea,
258+
parseProps,
259+
getRowFormat,
260+
getStoredAs,
198261
};
199262
};

0 commit comments

Comments
 (0)