diff --git a/package.json b/package.json index 276d63d0..5606bd99 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "electron-log": "^4.3.0", "electron-store": "^7.0.0", "electron-updater": "^4.3.5", + "faker": "^5.3.1", "keytar": "^7.3.0", "lodash": "^4.17.20", "moment": "^2.29.1", diff --git a/src/common/FakerMethods.js b/src/common/FakerMethods.js new file mode 100644 index 00000000..efa02bd2 --- /dev/null +++ b/src/common/FakerMethods.js @@ -0,0 +1,217 @@ +export default class { + static get _methods () { + return [ + { name: 'zipCode', group: 'address', types: ['string'] }, + { name: 'zipCodeByState', group: 'address', types: ['string'] }, + { name: 'city', group: 'address', types: ['string'] }, + { name: 'cityPrefix', group: 'address', types: ['string'] }, + { name: 'citySuffix', group: 'address', types: ['string'] }, + { name: 'streetName', group: 'address', types: ['string'] }, + { name: 'streetAddress', group: 'address', types: ['string'] }, + { name: 'streetSuffix', group: 'address', types: ['string'] }, + { name: 'streetPrefix', group: 'address', types: ['string'] }, + { name: 'secondaryAddress', group: 'address', types: ['string'] }, + { name: 'county', group: 'address', types: ['string'] }, + { name: 'country', group: 'address', types: ['string'] }, + { name: 'countryCode', group: 'address', types: ['string'] }, + { name: 'state', group: 'address', types: ['string'] }, + { name: 'stateAbbr', group: 'address', types: ['string'] }, + { name: 'latitude', group: 'address', types: ['string'] }, + { name: 'longitude', group: 'address', types: ['string'] }, + { name: 'direction', group: 'address', types: ['string'] }, + { name: 'cardinalDirection', group: 'address', types: ['string'] }, + { name: 'ordinalDirection', group: 'address', types: ['string'] }, + // { name: 'nearbyGPSCoordinate', group: 'address', types: ['string'] }, + { name: 'timeZone', group: 'address', types: ['string'] }, + + { name: 'color', group: 'commerce', types: ['string'] }, + { name: 'department', group: 'commerce', types: ['string'] }, + { name: 'productName', group: 'commerce', types: ['string'] }, + { name: 'price', group: 'commerce', types: ['string', 'float'] }, + { name: 'productAdjective', group: 'commerce', types: ['string'] }, + { name: 'productMaterial', group: 'commerce', types: ['string'] }, + { name: 'product', group: 'commerce', types: ['string'] }, + { name: 'productDescription', group: 'commerce', types: ['string'] }, + + { name: 'suffixes', group: 'company', types: ['string'] }, + { name: 'companyName', group: 'company', types: ['string'] }, + { name: 'companySuffix', group: 'company', types: ['string'] }, + { name: 'catchPhrase', group: 'company', types: ['string'] }, + { name: 'bs', group: 'company', types: ['string'] }, + { name: 'catchPhraseAdjective', group: 'company', types: ['string'] }, + { name: 'catchPhraseDescriptor', group: 'company', types: ['string'] }, + { name: 'catchPhraseNoun', group: 'company', types: ['string'] }, + { name: 'bsAdjective', group: 'company', types: ['string'] }, + { name: 'bsBuzz', group: 'company', types: ['string'] }, + { name: 'bsNoun', group: 'company', types: ['string'] }, + + { name: 'column', group: 'database', types: ['string'] }, + { name: 'type', group: 'database', types: ['string'] }, + { name: 'collation', group: 'database', types: ['string'] }, + { name: 'engine', group: 'database', types: ['string'] }, + + { name: 'past', group: 'date', types: ['string', 'datetime'] }, + { name: 'future', group: 'date', types: ['string', 'datetime'] }, + // { name: 'between', group: 'date', types: ['string'] }, + { name: 'recent', group: 'date', types: ['string', 'datetime'] }, + { name: 'soon', group: 'date', types: ['string', 'datetime'] }, + { name: 'month', group: 'date', types: ['string'] }, + { name: 'weekday', group: 'date', types: ['string'] }, + + { name: 'account', group: 'finance', types: ['string', 'number'] }, + { name: 'accountName', group: 'finance', types: ['string'] }, + { name: 'routingNumber', group: 'finance', types: ['string', 'number'] }, + { name: 'mask', group: 'finance', types: ['string', 'number'] }, + { name: 'amount', group: 'finance', types: ['string', 'float'] }, + { name: 'transactionType', group: 'finance', types: ['string'] }, + { name: 'currencyCode', group: 'finance', types: ['string'] }, + { name: 'currencyName', group: 'finance', types: ['string'] }, + { name: 'currencySymbol', group: 'finance', types: ['string'] }, + { name: 'bitcoinAddress', group: 'finance', types: ['string'] }, + { name: 'litecoinAddress', group: 'finance', types: ['string'] }, + { name: 'creditCardNumber', group: 'finance', types: ['string'] }, + { name: 'creditCardCVV', group: 'finance', types: ['string', 'number'] }, + { name: 'ethereumAddress', group: 'finance', types: ['string'] }, + { name: 'iban', group: 'finance', types: ['string'] }, + { name: 'bic', group: 'finance', types: ['string'] }, + { name: 'transactionDescription', group: 'finance', types: ['string'] }, + + { name: 'branch', group: 'git', types: ['string'] }, + { name: 'commitEntry', group: 'git', types: ['string'] }, + { name: 'commitMessage', group: 'git', types: ['string'] }, + { name: 'commitSha', group: 'git', types: ['string'] }, + { name: 'shortSha', group: 'git', types: ['string'] }, + + { name: 'abbreviation', group: 'hacker', types: ['string'] }, + { name: 'adjective', group: 'hacker', types: ['string'] }, + { name: 'noun', group: 'hacker', types: ['string'] }, + { name: 'verb', group: 'hacker', types: ['string'] }, + { name: 'ingverb', group: 'hacker', types: ['string'] }, + { name: 'phrase', group: 'hacker', types: ['string'] }, + + // { name: 'avatar', group: 'internet', types: ['string'] }, + { name: 'email', group: 'internet', types: ['string'] }, + { name: 'exampleEmail', group: 'internet', types: ['string'] }, + { name: 'userName', group: 'internet', types: ['string'] }, + { name: 'protocol', group: 'internet', types: ['string'] }, + { name: 'url', group: 'internet', types: ['string'] }, + { name: 'domainName', group: 'internet', types: ['string'] }, + { name: 'domainSuffix', group: 'internet', types: ['string'] }, + { name: 'domainWord', group: 'internet', types: ['string'] }, + { name: 'ip', group: 'internet', types: ['string'] }, + { name: 'ipv6', group: 'internet', types: ['string'] }, + { name: 'userAgent', group: 'internet', types: ['string'] }, + { name: 'color', group: 'internet', types: ['string'] }, + { name: 'mac', group: 'internet', types: ['string'] }, + { name: 'password', group: 'internet', types: ['string'] }, + + { name: 'word', group: 'lorem', types: ['string'] }, + { name: 'words', group: 'lorem', types: ['string'] }, + { name: 'sentence', group: 'lorem', types: ['string'] }, + { name: 'slug', group: 'lorem', types: ['string'] }, + { name: 'sentences', group: 'lorem', types: ['string'] }, + { name: 'paragraph', group: 'lorem', types: ['string'] }, + { name: 'paragraphs', group: 'lorem', types: ['string'] }, + { name: 'text', group: 'lorem', types: ['string'] }, + { name: 'lines', group: 'lorem', types: ['string'] }, + + { name: 'genre', group: 'music', types: ['string'] }, + + { name: 'firstName', group: 'name', types: ['string'] }, + { name: 'lastName', group: 'name', types: ['string'] }, + { name: 'middleName', group: 'name', types: ['string'] }, + { name: 'findName', group: 'name', types: ['string'] }, + { name: 'jobTitle', group: 'name', types: ['string'] }, + { name: 'gender', group: 'name', types: ['string'] }, + { name: 'prefix', group: 'name', types: ['string'] }, + { name: 'suffix', group: 'name', types: ['string'] }, + { name: 'title', group: 'name', types: ['string'] }, + { name: 'jobDescriptor', group: 'name', types: ['string'] }, + { name: 'jobArea', group: 'name', types: ['string'] }, + { name: 'jobType', group: 'name', types: ['string'] }, + + { name: 'phoneNumber', group: 'phone', types: ['string'] }, + { name: 'phoneNumberFormat', group: 'phone', types: ['string'] }, + { name: 'phoneFormats', group: 'phone', types: ['string'] }, + + { name: 'number', group: 'random', types: ['string', 'number'] }, + { name: 'float', group: 'random', types: ['string', 'float'] }, + { name: 'arrayElement', group: 'random', types: ['string'] }, + { name: 'arrayElements', group: 'random', types: ['string'] }, + { name: 'objectElement', group: 'random', types: ['string'] }, + { name: 'uuid', group: 'random', types: ['string'] }, + { name: 'boolean', group: 'random', types: ['string'] }, + { name: 'word', group: 'random', types: ['string'] }, + { name: 'words', group: 'random', types: ['string'] }, + // { name: 'image', group: 'random', types: ['string'] }, + { name: 'locale', group: 'random', types: ['string'] }, + { name: 'alpha', group: 'random', types: ['string'] }, + { name: 'alphaNumeric', group: 'random', types: ['string'] }, + { name: 'hexaDecimal', group: 'random', types: ['string'] }, + + { name: 'fileName', group: 'system', types: ['string'] }, + { name: 'commonFileName', group: 'system', types: ['string'] }, + { name: 'mimeType', group: 'system', types: ['string'] }, + { name: 'commonFileType', group: 'system', types: ['string'] }, + { name: 'commonFileExt', group: 'system', types: ['string'] }, + { name: 'fileType', group: 'system', types: ['string'] }, + { name: 'fileExt', group: 'system', types: ['string'] }, + { name: 'directoryPath', group: 'system', types: ['string'] }, + { name: 'filePath', group: 'system', types: ['string'] }, + { name: 'semver', group: 'system', types: ['string'] }, + + { name: 'recent', group: 'time', types: ['string', 'time'] }, + + { name: 'vehicle', group: 'vehicle', types: ['string'] }, + { name: 'manufacturer', group: 'vehicle', types: ['string'] }, + { name: 'model', group: 'vehicle', types: ['string'] }, + { name: 'type', group: 'vehicle', types: ['string'] }, + { name: 'fuel', group: 'vehicle', types: ['string'] }, + { name: 'vin', group: 'vehicle', types: ['string'] }, + { name: 'color', group: 'vehicle', types: ['string'] } + ]; + } + + static getGroups () { + const groupsObj = this._methods.reduce((acc, curr) => { + if (curr.group in acc) + curr.types.forEach(type => acc[curr.group].add(type)); + else + acc[curr.group] = new Set(curr.types); + + return acc; + }, {}); + + const groupsArr = []; + + for (const key in groupsObj) + groupsArr.push({ name: key, types: [...groupsObj[key]] }); + + return groupsArr.sort((a, b) => { + if (a.name < b.name) + return -1; + + if (b.name > a.name) + return 1; + + return 0; + }); ; + } + + static getGroupsByType (type) { + if (!type) return []; + return this.getGroups().filter(group => group.types.includes(type)); + } + + static getMethods ({ type, group }) { + return this._methods.filter(method => method.group === group && method.types.includes(type)).sort((a, b) => { + if (a.name < b.name) + return -1; + + if (b.name > a.name) + return 1; + + return 0; + }); + } +} diff --git a/src/main/ipc-handlers/tables.js b/src/main/ipc-handlers/tables.js index a0373f9e..0be8acc5 100644 --- a/src/main/ipc-handlers/tables.js +++ b/src/main/ipc-handlers/tables.js @@ -1,6 +1,8 @@ import { ipcMain } from 'electron'; +import faker from 'faker'; +import moment from 'moment'; import { sqlEscaper } from 'common/libs/sqlEscaper'; -import { TEXT, LONG_TEXT, NUMBER, FLOAT, BLOB, BIT } from 'common/fieldTypes'; +import { TEXT, LONG_TEXT, NUMBER, FLOAT, BLOB, BIT, DATE, DATETIME } from 'common/fieldTypes'; import fs from 'fs'; export default (connections) => { @@ -204,6 +206,65 @@ export default (connections) => { } }); + ipcMain.handle('insert-table-fake-rows', async (event, params) => { + try { + const rows = []; + + for (let i = 0; i < +params.repeat; i++) { + const insertObj = {}; + + for (const key in params.row) { + const type = params.fields[key]; + let escapedParam; + + if (!('group' in params.row[key]) || params.row[key].group === 'manual') { // Manual value + if (params.row[key].value === null) + escapedParam = 'NULL'; + else if ([...NUMBER, ...FLOAT].includes(type)) + escapedParam = params.row[key].value; + else if ([...TEXT, ...LONG_TEXT].includes(type)) + escapedParam = `"${sqlEscaper(params.row[key].value)}"`; + else if (BLOB.includes(type)) { + if (params.row[key].value) { + const fileBlob = fs.readFileSync(params.row[key].value); + escapedParam = `0x${fileBlob.toString('hex')}`; + } + else + escapedParam = '""'; + } + else + escapedParam = `"${sqlEscaper(params.row[key].value)}"`; + + insertObj[key] = escapedParam; + } + else { // Faker value + let fakeValue = faker[params.row[key].group][params.row[key].method](); + + if ([...TEXT, ...LONG_TEXT].includes(type)) + fakeValue = `"${sqlEscaper(fakeValue)}"`; + else if ([...DATE, ...DATETIME].includes(type)) + fakeValue = `"${moment(fakeValue).format('YYYY-MM-DD HH:mm:ss.SSSSSS')}"`; + + insertObj[key] = fakeValue; + } + } + + rows.push(insertObj); + } + + await connections[params.uid] + .schema(params.schema) + .into(params.table) + .insert(rows) + .run(); + + return { status: 'success' }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); + ipcMain.handle('get-foreign-list', async (event, { uid, schema, table, column, description }) => { try { const query = connections[uid] diff --git a/src/renderer/components/FakerSelect.vue b/src/renderer/components/FakerSelect.vue new file mode 100644 index 00000000..fe041e93 --- /dev/null +++ b/src/renderer/components/FakerSelect.vue @@ -0,0 +1,205 @@ + + + diff --git a/src/renderer/components/ModalFakerRows.vue b/src/renderer/components/ModalFakerRows.vue new file mode 100644 index 00000000..1406bf2f --- /dev/null +++ b/src/renderer/components/ModalFakerRows.vue @@ -0,0 +1,278 @@ + + + + + diff --git a/src/renderer/components/ModalNewTableRow.vue b/src/renderer/components/ModalNewTableRow.vue index dbccea96..709c6441 100644 --- a/src/renderer/components/ModalNewTableRow.vue +++ b/src/renderer/components/ModalNewTableRow.vue @@ -50,6 +50,16 @@ :tabindex="key+1" @change="filesChange($event,field.name)" > + {{ $t('word.add') }} -