Skip to content

Commit

Permalink
HCK-9607: browser support (#16)
Browse files Browse the repository at this point in the history
* chore: declared `lodash` as external resource

* feat: allowed FE features in browser

* fix: reversed suggested change for regexp by sonar

* fix: eliminated the `readConfig` dependency, taking the configs directly from the payload

* chore: added `postinstall` hook

* fix: passed missing arguments

* fix: adapted object keys after using the already parsed configs
  • Loading branch information
chulanovskyi-bs authored Jan 24, 2025
1 parent 8fea967 commit 23d7dbd
Show file tree
Hide file tree
Showing 17 changed files with 621 additions and 403 deletions.
5 changes: 5 additions & 0 deletions api/fe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const { generateScript } = require('../forward_engineering/api');

module.exports = {
generateScript,
};
9 changes: 9 additions & 0 deletions esbuild.package.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const fs = require('fs');
const path = require('path');
const esbuild = require('esbuild');
const { clean } = require('esbuild-plugin-clean');
const { copy } = require('esbuild-plugin-copy');
const { copyFolderFiles, addReleaseFlag } = require('@hackolade/hck-esbuild-plugins-pack');
const { EXCLUDED_EXTENSIONS, EXCLUDED_FILES, DEFAULT_RELEASE_FOLDER_PATH } = require('./buildConstants');

Expand All @@ -11,6 +12,7 @@ const RELEASE_FOLDER_PATH = path.join(DEFAULT_RELEASE_FOLDER_PATH, `${packageDat
esbuild
.build({
entryPoints: [
path.resolve(__dirname, 'api', 'fe.js'),
path.resolve(__dirname, 'forward_engineering', 'api.js'),
path.resolve(__dirname, 'reverse_engineering', 'api.js'),
],
Expand All @@ -21,10 +23,17 @@ esbuild
outdir: RELEASE_FOLDER_PATH,
minify: true,
logLevel: 'info',
external: ['lodash'],
plugins: [
clean({
patterns: [DEFAULT_RELEASE_FOLDER_PATH],
}),
copy({
assets: {
from: [path.join('node_modules', 'lodash', '**', '*')],
to: [path.join('node_modules', 'lodash')],
},
}),
copyFolderFiles({
fromPath: __dirname,
targetFolderPath: RELEASE_FOLDER_PATH,
Expand Down
318 changes: 29 additions & 289 deletions forward_engineering/api.js
Original file line number Diff line number Diff line change
@@ -1,303 +1,43 @@
const helper = require('../helper/helper.js');
const schemaHelper = require('../helper/schemaHelper.js');
const { getFieldsSchema } = require('./helpers/getFieldsSchema');
const { getMappingScript } = require('./helpers/getMappingScript');
const { getTypeSchema } = require('./helpers/getTypeSchema');
const { getCurlScript } = require('./helpers/getCurlScript');
const { getKibanaScript } = require('./helpers/getKibanaScript');

module.exports = {
generateScript(data, logger, cb) {
const { jsonSchema, modelData, entityData, isUpdateScript } = data;
const containerData = data.containerData || {};
const {
jsonSchema,
modelData,
entityData,
isUpdateScript,
pluginConfiguration,
internalDefinitions,
modelDefinitions,
externalDefinitions,
containerData = {},
} = data;

let result = '';
let fieldsSchema = this.getFieldsSchema({

const fieldsSchema = getFieldsSchema({
jsonSchema: JSON.parse(jsonSchema),
internalDefinitions: JSON.parse(data.internalDefinitions),
modelDefinitions: JSON.parse(data.modelDefinitions),
externalDefinitions: JSON.parse(data.externalDefinitions),
internalDefinitions: JSON.parse(internalDefinitions),
modelDefinitions: JSON.parse(modelDefinitions),
externalDefinitions: JSON.parse(externalDefinitions),
fieldLevelConfig: pluginConfiguration.fieldLevelConfig,
});
let typeSchema = this.getTypeSchema(entityData, fieldsSchema);
let mappingScript = this.getMappingScript(containerData, typeSchema);

const typeSchema = getTypeSchema(entityData, fieldsSchema);

const mappingScript = getMappingScript(containerData, typeSchema, pluginConfiguration.containerLevelConfig);

if (isUpdateScript) {
result = this.getCurlScript(mappingScript, modelData, containerData);
result = getCurlScript(mappingScript, modelData, containerData);
} else {
result += this.getKibanaScript(mappingScript, containerData);
result += getKibanaScript(mappingScript, containerData);
}

cb(null, result);
},

getCurlScript(mapping, modelData, indexData) {
const host = modelData.host || 'localhost';
const port = modelData.port || 9200;
const indexName = indexData.name || '';
const majorVersion = +(modelData.dbVersion || '').split('.').shift();
const includeTypeName = majorVersion >= 7 ? '&include_type_name=true' : '';

return `curl -XPUT '${host}:${port}/${indexName.toLowerCase()}?pretty${includeTypeName}' -H 'Content-Type: application/json' -d '\n${JSON.stringify(mapping, null, 4)}\n'`;
},

getKibanaScript(mapping, indexData) {
const indexName = indexData.name || '';

return `PUT /${indexName.toLowerCase()}\n${JSON.stringify(mapping, null, 4)}`;
},

getFieldsSchema(data) {
const { jsonSchema } = data;
let schema = {};

if (!(jsonSchema.properties && jsonSchema.properties._source && jsonSchema.properties._source.properties)) {
return schema;
}

schema = this.getSchemaByItem(jsonSchema.properties._source.properties, data);

return schema;
},

getSchemaByItem(properties, data) {
let schema = {};

for (let fieldName in properties) {
let field = properties[fieldName];

schema[fieldName] = this.getField(field, data);
}

return schema;
},

getField(field, data) {
let schema = {};
const fieldProperties = helper.getFieldProperties(field.type, field, {});
let type = this.getFieldType(field);

if (type !== 'object' && type !== 'array') {
schema.type = type;
}

if (type === 'object') {
schema.properties = {};
}

this.setProperties(schema, fieldProperties, data);

if (type === 'alias') {
return { ...schema, ...this.getAliasSchema(field, data) };
} else if (type === 'join') {
return { ...schema, ...this.getJoinSchema(field) };
} else if (
[
'completion',
'sparse_vector',
'dense_vector',
'geo_shape',
'geo_point',
'rank_feature',
'rank_features',
].includes(type)
) {
return schema;
} else if (field.properties) {
schema.properties = this.getSchemaByItem(field.properties, data);
} else if (field.items) {
let arrData = field.items;

if (Array.isArray(field.items)) {
arrData = field.items[0];
}

schema = { ...schema, ...this.getField(arrData, data) };
}

return schema;
},

getFieldType(field) {
switch (field.type) {
case 'geo-shape':
return 'geo_shape';
case 'geo-point':
return 'geo_point';
case 'number':
return field.mode || 'long';
case 'string':
return field.mode || 'text';
case 'range':
return field.mode || 'integer_range';
case 'null':
return 'long';
default:
return field.type;
}
},

setProperties(schema, properties, data) {
for (let propName in properties) {
if (propName === 'stringfields') {
try {
schema['fields'] = JSON.parse(properties[propName]);
} catch (e) {}
} else if (this.isFieldList(properties[propName])) {
const names = schemaHelper.getNamesByIds(
properties[propName].map(item => item.keyId),
[data.jsonSchema, data.internalDefinitions, data.modelDefinitions, data.externalDefinitions],
);
if (names.length) {
schema[propName] = names.length === 1 ? names[0] : names;
}
} else {
schema[propName] = properties[propName];
}
}

return schema;
},

getTypeSchema(typeData, fieldsSchema) {
let script = {};

if (typeData.dynamic) {
script.dynamic = typeData.dynamic;
}

script.properties = fieldsSchema;

return {
[(typeData.collectionName || '').toLowerCase()]: script,
};
},

getMappingScript(indexData, typeSchema) {
let mappingScript = {};
let settings = this.getSettings(indexData);
let aliases = this.getAliases(indexData);

if (settings) {
mappingScript.settings = settings;
}

if (aliases) {
mappingScript.aliases = aliases;
}

mappingScript.mappings = typeSchema;

return mappingScript;
},

getSettings(indexData) {
let settings;
let properties = helper.getContainerLevelProperties();

properties.forEach(propertyName => {
if (indexData[propertyName]) {
if (!settings) {
settings = {};
}

settings[propertyName] = indexData[propertyName];
}
});

return settings;
},

getAliases(indexData) {
let aliases;

if (!indexData.aliases) {
return aliases;
}

indexData.aliases.forEach(alias => {
if (alias.name) {
if (!aliases) {
aliases = {};
}

aliases[alias.name] = {};

if (alias.filter) {
let filterData = '';
try {
filterData = JSON.parse(alias.filter);
} catch (e) {}

aliases[alias.name].filter = {
term: filterData,
};
}

if (alias.routing) {
aliases[alias.name].routing = alias.routing;
}
}
});

return aliases;
},

isFieldList(property) {
if (!Array.isArray(property)) {
return false;
}

if (!property[0]) {
return false;
}

if (property[0].keyId) {
return true;
}

return false;
},

getJoinSchema(field) {
if (!Array.isArray(field.relations)) {
return {};
}

const relations = field.relations.reduce((result, item) => {
if (!item.parent) {
return result;
}

if (!Array.isArray(item.children)) {
return result;
}

if (item.children.length === 1) {
return {
...result,
[item.parent]: item.children?.[0]?.name
};
}

return {
...result,
[item.parent]: item.children.map(item => item.name || '')
};
}, {});

return { relations };
},

getAliasSchema(field, data) {
if (!Array.isArray(field.path)) {
return {};
}

if (field.path.length === 0) {
return {};
}

const pathName = schemaHelper.getPathName(field.path[0].keyId, [
data.jsonSchema,
data.internalDefinitions,
data.modelDefinitions,
data.externalDefinitions,
]);

return { path: pathName };
},
};
13 changes: 13 additions & 0 deletions forward_engineering/helpers/getCurlScript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const getCurlScript = (mapping, modelData, indexData) => {
const host = modelData.host || 'localhost';
const port = modelData.port || 9200;
const indexName = indexData.name || '';
const majorVersion = +(modelData.dbVersion || '').split('.').shift();
const includeTypeName = majorVersion >= 7 ? '&include_type_name=true' : '';

return `curl -XPUT '${host}:${port}/${indexName.toLowerCase()}?pretty${includeTypeName}' -H 'Content-Type: application/json' -d '\n${JSON.stringify(mapping, null, 4)}\n'`;
};

module.exports = {
getCurlScript,
};
Loading

0 comments on commit 23d7dbd

Please sign in to comment.