Merge pull request #472 from antares-sql/firebirdsql-support

Firebird SQL support
This commit is contained in:
Fabio Di Stasio 2022-11-17 16:19:59 +01:00 committed by GitHub
commit 038cf68253
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1671 additions and 107 deletions

View File

@ -5,6 +5,7 @@
"MySQL",
"PostgreSQL",
"SQLite",
"Firebird SQL",
"Windows",
"translation",
"Linux",

View File

@ -12,7 +12,7 @@
Antares is an SQL client based on [Electron.js](https://github.com/electron/electron) and [Vue.js](https://github.com/vuejs/vue) that aims to become a useful tool, especially for developers.
Our target is to support as many databases as possible, and all major operating systems, including the ARM versions.
**At the moment this application is in development state, many features will come in future updates**, and supports only MySQL/MariaDB, PostgreSQL and SQLite.
**At the moment this application is in development state, many features will come in future updates**, and supports only MySQL/MariaDB, PostgreSQL, SQLite and Firebird SQL.
However, there are all the features necessary to have a pleasant database management experience, so give it a chance and send us your feedback, we would really appreciate it.
We are actively working on it, hoping to provide new cool features, improvements and fixes as soon as possible.
@ -84,8 +84,8 @@ This is a roadmap with major features will come in near future.
- [x] MySQL/MariaDB
- [x] PostgreSQL
- [x] SQLite
- [ ] MSSQL
- [ ] OracleDB
- [x] Firebird SQL
- [ ] SQL Server
- [ ] More...
### Operating Systems

32
package-lock.json generated
View File

@ -26,6 +26,7 @@
"marked": "~4.0.19",
"moment": "~2.29.4",
"mysql2": "~2.3.2",
"node-firebird": "~1.1.3",
"pg": "~8.7.1",
"pg-connection-string": "~2.5.0",
"pg-query-stream": "~4.2.3",
@ -4132,6 +4133,14 @@
"prebuild-install": "^7.1.0"
}
},
"node_modules/big-integer": {
"version": "1.6.51",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
"integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
"engines": {
"node": ">=0.6"
}
},
"node_modules/big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@ -11274,6 +11283,15 @@
}
}
},
"node_modules/node-firebird": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/node-firebird/-/node-firebird-1.1.3.tgz",
"integrity": "sha512-3VhiP8XMqlKQo8H8nPOmrqYFseEj0uUdoacZ5xutRAOFzLWR9ImXBfVLUdg4AiH34YCshgiU8Lc37AAX3Vc6YQ==",
"dependencies": {
"big-integer": "^1.6.48",
"long": "^4.0.0"
}
},
"node_modules/node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@ -19893,6 +19911,11 @@
"prebuild-install": "^7.1.0"
}
},
"big-integer": {
"version": "1.6.51",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
"integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg=="
},
"big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@ -25338,6 +25361,15 @@
"whatwg-url": "^5.0.0"
}
},
"node-firebird": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/node-firebird/-/node-firebird-1.1.3.tgz",
"integrity": "sha512-3VhiP8XMqlKQo8H8nPOmrqYFseEj0uUdoacZ5xutRAOFzLWR9ImXBfVLUdg4AiH34YCshgiU8Lc37AAX3Vc6YQ==",
"requires": {
"big-integer": "^1.6.48",
"long": "^4.0.0"
}
},
"node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",

View File

@ -135,6 +135,7 @@
"marked": "~4.0.19",
"moment": "~2.29.4",
"mysql2": "~2.3.2",
"node-firebird": "~1.1.3",
"pg": "~8.7.1",
"pg-connection-string": "~2.5.0",
"pg-query-stream": "~4.2.3",

View File

@ -1,10 +1,14 @@
import { Customizations } from '../interfaces/customizations';
// Everything OFF
export const defaults: Customizations = {
// Defaults
defaultPort: null,
defaultUser: null,
defaultDatabase: null,
dataTypes: [],
indexTypes: [],
foreignActions: [],
// Core
database: false,
collations: false,
@ -45,9 +49,9 @@ export const defaults: Customizations = {
exportByChunks: false,
schemaImport: false,
tableSettings: false,
tableOptions: false,
tableArray: false,
tableRealCount: false,
tableDuplicate: false,
viewSettings: false,
triggerSettings: false,
triggerFunctionSettings: false,
@ -73,6 +77,7 @@ export const defaults: Customizations = {
procedureDataAccess: false,
procedureSql: null,
procedureContext: false,
procedureContextValues: [],
procedureLanguage: false,
functionDeterministic: false,
functionDataAccess: false,

View File

@ -0,0 +1,63 @@
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
import firebirdTypes from '../data-types/firebird';
export const customizations: Customizations = {
...defaults,
// Defaults
defaultPort: 3050,
defaultUser: 'SYSDBA',
defaultDatabase: null,
dataTypes: firebirdTypes,
indexTypes: [
'PRIMARY',
// 'CHECK',
'UNIQUE'
],
foreignActions: [
'RESTRICT',
'NO ACTION',
'CASCADE',
'SET NULL',
'SET DEFAULT'
],
// Core
database: true,
collations: false,
engines: false,
connectionSchema: false,
sslConnection: false,
sshConnection: false,
fileConnection: false,
cancelQueries: false,
// Tools
processesList: false,
usersManagement: false,
variables: false,
// Structure
schemas: false,
tables: true,
views: true,
triggers: true,
routines: true,
functions: false,
// Settings
elementsWrapper: '"',
stringsWrapper: '\'',
tableAdd: true,
tableSettings: true,
tableRealCount: true,
viewAdd: true,
viewSettings: true,
triggerAdd: true,
triggerMultipleEvents: true,
triggerSql: 'BEGIN\r\n\r\nEND',
routineAdd: true,
procedureContext: true,
procedureContextValues: ['IN', 'OUT'],
procedureSql: 'BEGIN\r\n\r\nEND',
parametersLength: true,
indexes: true,
foreigns: true,
nullable: true
};

View File

@ -1,16 +1,19 @@
import * as mysql from 'common/customizations/mysql';
import * as postgresql from 'common/customizations/postgresql';
import * as sqlite from 'common/customizations/sqlite';
import * as firebird from 'common/customizations/firebird';
import { Customizations } from 'common/interfaces/customizations';
export default {
maria: mysql.customizations,
mysql: mysql.customizations,
pg: postgresql.customizations,
sqlite: sqlite.customizations
sqlite: sqlite.customizations,
firebird: firebird.customizations
} as {
maria: Customizations;
mysql: Customizations;
pg: Customizations;
sqlite: Customizations;
firebird: Customizations;
};

View File

@ -1,5 +1,6 @@
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
import mysqlTypes from '../data-types/mysql';
export const customizations: Customizations = {
...defaults,
@ -7,6 +8,19 @@ export const customizations: Customizations = {
defaultPort: 3306,
defaultUser: 'root',
defaultDatabase: null,
dataTypes: mysqlTypes,
indexTypes: [
'PRIMARY',
'INDEX',
'UNIQUE',
'FULLTEXT'
],
foreignActions: [
'RESTRICT',
'CASCADE',
'SET NULL',
'NO ACTION'
],
// Core
connectionSchema: true,
collations: true,
@ -29,6 +43,7 @@ export const customizations: Customizations = {
stringsWrapper: '"',
tableAdd: true,
tableTruncateDisableFKCheck: true,
tableDuplicate: true,
viewAdd: true,
triggerAdd: true,
routineAdd: true,
@ -51,7 +66,6 @@ export const customizations: Customizations = {
unsigned: true,
nullable: true,
zerofill: true,
tableOptions: true,
autoIncrement: true,
comment: true,
collation: true,
@ -64,6 +78,7 @@ export const customizations: Customizations = {
procedureDataAccess: true,
procedureSql: 'BEGIN\r\n\r\nEND',
procedureContext: true,
procedureContextValues: ['IN', 'OUT', 'INOUT'],
triggerSql: 'BEGIN\r\n\r\nEND',
functionDeterministic: true,
functionDataAccess: true,

View File

@ -1,5 +1,6 @@
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
import postgresqlTypes from '../data-types/postgresql';
export const customizations: Customizations = {
...defaults,
@ -7,6 +8,18 @@ export const customizations: Customizations = {
defaultPort: 5432,
defaultUser: 'postgres',
defaultDatabase: 'postgres',
dataTypes: postgresqlTypes,
indexTypes: [
'PRIMARY',
'INDEX',
'UNIQUE'
],
foreignActions: [
'RESTRICT',
'CASCADE',
'SET NULL',
'NO ACTION'
],
// Core
database: true,
sslConnection: true,
@ -26,6 +39,7 @@ export const customizations: Customizations = {
elementsWrapper: '"',
stringsWrapper: '\'',
tableAdd: true,
tableDuplicate: true,
viewAdd: true,
triggerAdd: true,
triggerFunctionAdd: true,
@ -47,6 +61,7 @@ export const customizations: Customizations = {
tableArray: true,
procedureSql: '$procedure$\r\n\r\n$procedure$',
procedureContext: true,
procedureContextValues: ['IN', 'OUT', 'INOUT'],
procedureLanguage: true,
functionSql: '$function$\r\n\r\n$function$',
triggerFunctionSql: '$function$\r\nBEGIN\r\n\r\nEND\r\n$function$',

View File

@ -1,8 +1,21 @@
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
import sqliteTypes from '../data-types/sqlite';
export const customizations: Customizations = {
...defaults,
dataTypes: sqliteTypes,
indexTypes: [
'PRIMARY',
'INDEX',
'UNIQUE'
],
foreignActions: [
'RESTRICT',
'CASCADE',
'SET NULL',
'NO ACTION'
],
// Core
fileConnection: true,
// Structure
@ -14,6 +27,7 @@ export const customizations: Customizations = {
elementsWrapper: '"',
stringsWrapper: '\'',
tableAdd: true,
tableDuplicate: true,
viewAdd: true,
triggerAdd: true,
schemaEdit: false,

View File

@ -0,0 +1,136 @@
import { TypesGroup } from 'common/interfaces/antares';
export default [
{
group: 'integer',
types: [
{
name: 'SMALLINT',
length: false,
collation: false,
unsigned: true,
zerofill: true
},
{
name: 'INTEGER',
length: false,
collation: false,
unsigned: true,
zerofill: true
},
{
name: 'BIGINT',
length: false,
collation: false,
unsigned: true,
zerofill: true
}
]
},
{
group: 'float',
types: [
{
name: 'DECIMAL',
length: true,
scale: true,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'NUMERIC',
length: true,
scale: true,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'FLOAT',
length: false,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'DOUBLE PRECISION',
length: false,
collation: false,
unsigned: false,
zerofill: false
}
]
},
{
group: 'string',
types: [
{
name: 'CHAR',
length: true,
collation: true,
unsigned: false,
zerofill: false
},
{
name: 'VARCHAR',
length: true,
collation: true,
unsigned: false,
zerofill: false
},
{
name: 'BLOB-TEXT',
length: false,
collation: true,
unsigned: false,
zerofill: false
}
]
},
{
group: 'binary',
types: [
{
name: 'BLOB',
length: false,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'CHAR-BINARY',
length: false,
collation: false,
unsigned: false,
zerofill: false
}
]
},
{
group: 'time',
types: [
{
name: 'DATE',
length: false,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'TIME',
length: true,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'TIMESTAMP',
length: false,
collation: false,
unsigned: false,
zerofill: false
}
]
}
] as TypesGroup[];

View File

@ -10,7 +10,8 @@ export const LONG_TEXT = [
'MEDIUMTEXT',
'LONGTEXT',
'JSON',
'VARBINARY'
'VARBINARY',
'BLOB-TEXT'
];
export const ARRAY = [
@ -35,7 +36,8 @@ export const NUMBER = [
'SERIAL',
'BIGSERIAL',
'OID',
'XID'
'XID',
'INT64'
];
export const FLOAT = [
@ -84,7 +86,8 @@ export const BLOB = [
'MEDIUMBLOB',
'LONGBLOB',
'LONG_BLOB',
'BYTEA'
'BYTEA',
'CHAR-BINARY'
];
export const BIT = [

View File

@ -1,6 +0,0 @@
export default [
'PRIMARY',
'INDEX',
'UNIQUE',
'FULLTEXT'
];

View File

@ -1,5 +0,0 @@
export default [
'PRIMARY',
'INDEX',
'UNIQUE'
];

View File

@ -1,5 +0,0 @@
export default [
'PRIMARY',
'INDEX',
'UNIQUE'
];

View File

@ -8,9 +8,10 @@ import SSHConfig from 'ssh2-promise/lib/sshConfig';
import { MySQLClient } from '../../main/libs/clients/MySQLClient';
import { PostgreSQLClient } from '../../main/libs/clients/PostgreSQLClient';
import { SQLiteClient } from '../../main/libs/clients/SQLiteClient';
import { FirebirdSQLClient } from 'src/main/libs/clients/FirebirdSQLClient';
export type Client = MySQLClient | PostgreSQLClient | SQLiteClient
export type ClientCode = 'mysql' | 'maria' | 'pg' | 'sqlite'
export type Client = MySQLClient | PostgreSQLClient | SQLiteClient | FirebirdSQLClient
export type ClientCode = 'mysql' | 'maria' | 'pg' | 'sqlite' | 'firebird'
export type Exporter = MysqlExporter | PostgreSQLExporter
export type Importer = MySQLImporter | PostgreSQLImporter

View File

@ -1,8 +1,13 @@
import { TypesGroup } from './antares';
export interface Customizations {
// Defaults
defaultPort?: number;
defaultUser?: string;
defaultDatabase?: string;
dataTypes?: TypesGroup[];
indexTypes?: string[];
foreignActions?: string[];
// Core
database?: boolean;
collations?: boolean;
@ -30,7 +35,7 @@ export interface Customizations {
stringsWrapper: string;
tableAdd?: boolean;
tableSettings?: boolean;
tableOptions?: boolean;
tableDuplicate?: boolean;
tableArray?: boolean;
tableRealCount?: boolean;
tableTruncateDisableFKCheck?: boolean;
@ -71,6 +76,7 @@ export interface Customizations {
procedureDataAccess?: boolean;
procedureSql?: string;
procedureContext?: boolean;
procedureContextValues?: string[];
procedureLanguage?: boolean;
functionDeterministic?: boolean;
functionDataAccess?: boolean;

View File

@ -61,7 +61,11 @@ export default (connections: {[key: string]: antares.Client}) => {
});
await connection.connect();
await connection.select('1+1').run();
if (conn.client === 'firebird')
connection.raw('SELECT rdb$get_context(\'SYSTEM\', \'DB_NAME\') FROM rdb$database');
else
await connection.select('1+1').run();
connection.destroy();
return { status: 'success' };

View File

@ -97,7 +97,7 @@ export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-engines', async (event, uid) => {
try {
const result = await connections[uid].getEngines();
const result: unknown = await connections[uid].getEngines();
return { status: 'success', response: result };
}

View File

@ -105,6 +105,7 @@ export default (connections: {[key: string]: antares.Client}) => {
break;
case 'pg':
case 'sqlite':
case 'firebird':
escapedParam = `'${params.content.replaceAll('\'', '\'\'')}'`;
break;
}
@ -124,6 +125,7 @@ export default (connections: {[key: string]: antares.Client}) => {
escapedParam = `0x${fileBlob.toString('hex')}`;
break;
case 'pg':
case 'firebird':
fileBlob = fs.readFileSync(params.content);
escapedParam = `decode('${fileBlob.toString('hex')}', 'hex')`;
break;
@ -141,6 +143,7 @@ export default (connections: {[key: string]: antares.Client}) => {
escapedParam = '\'\'';
break;
case 'pg':
case 'firebird':
escapedParam = 'decode(\'\', \'hex\')';
break;
case 'sqlite':
@ -158,6 +161,7 @@ export default (connections: {[key: string]: antares.Client}) => {
case 'mysql':
case 'maria':
case 'pg':
case 'firebird':
escapedParam = params.content;
break;
case 'sqlite':
@ -223,10 +227,11 @@ export default (connections: {[key: string]: antares.Client}) => {
}).join(',');
try {
const result = await connections[params.uid]
const result: unknown = await connections[params.uid]
.schema(params.schema)
.delete(params.table)
.where({ [params.primary]: `IN (${idString})` })
.limit(params.rows.length)
.run();
return { status: 'success', response: result };
@ -285,6 +290,7 @@ export default (connections: {[key: string]: antares.Client}) => {
break;
case 'pg':
case 'sqlite':
case 'firebird':
escapedParam = `'${params.row[key].value.replaceAll('\'', '\'\'')}'`;
break;
}
@ -382,7 +388,20 @@ export default (connections: {[key: string]: antares.Client}) => {
if (description)
query.select(`LEFT(${description}, 20) AS foreign_description`);
const results = await query.run();
const results = await query.run<{[key: string]: string}>();
const parsedResults: {[key: string]: string}[] = [];
for (const row of results.rows) {
const remappedRow: {[key: string]: string} = {};
for (const key in row)
remappedRow[key.toLowerCase()] = row[key];// Thanks Firebird -.-
parsedResults.push(remappedRow);
}
results.rows = parsedResults;
return { status: 'success', response: results };
}

View File

@ -16,7 +16,7 @@ const queryLogger = ({ sql, cUid }: {sql: string; cUid: string}) => {
/**
* As Simple As Possible Query Builder Core
*/
export class AntaresCore {
export abstract class AntaresCore {
_client: antares.ClientCode;
protected _cUid: string
protected _params: mysql.ConnectionOptions | pg.ClientConfig | { databasePath: string; readonly: boolean};

View File

@ -2,6 +2,7 @@ import * as antares from 'common/interfaces/antares';
import { MySQLClient } from './clients/MySQLClient';
import { PostgreSQLClient } from './clients/PostgreSQLClient';
import { SQLiteClient } from './clients/SQLiteClient';
import { FirebirdSQLClient } from './clients/FirebirdSQLClient';
export class ClientsFactory {
static getClient (args: antares.ClientParams) {
@ -13,6 +14,8 @@ export class ClientsFactory {
return new PostgreSQLClient(args);
case 'sqlite':
return new SQLiteClient(args);
case 'firebird':
return new FirebirdSQLClient(args);
default:
throw new Error(`Unknown database client: ${args.client}`);
}

File diff suppressed because it is too large Load Diff

View File

@ -540,11 +540,7 @@ export class PostgreSQLClient extends AntaresCore {
return {
name: row.constraint_name,
column: row.column_name,
indexType: null as null,
type: row.constraint_type,
cardinality: null as null,
comment: '',
indexComment: ''
type: row.constraint_type
};
});
}

View File

@ -217,11 +217,7 @@ export class SQLiteClient extends AntaresCore {
remappedIndexes.push({
name: 'PRIMARY',
column: key.name,
indexType: null as never,
type: 'PRIMARY',
cardinality: null as never,
comment: '',
indexComment: ''
type: 'PRIMARY'
});
}

View File

@ -123,8 +123,8 @@ else {
if (isWindows)
mainWindow.show();
if (isDevelopment)
mainWindow.webContents.openDevTools();
// if (isDevelopment)
// mainWindow.webContents.openDevTools();
process.on('uncaughtException', error => {
mainWindow.webContents.send('unhandled-exception', error);

View File

@ -240,7 +240,9 @@ watch(() => tablesInQuery.value.length, () => {
});
fields.value = localFields;
setCustomCompleter();
setTimeout(() => {
setCustomCompleter();
}, 100);
});
watch(editorTheme, () => {

View File

@ -415,7 +415,8 @@ const clients = [
{ name: 'MySQL', slug: 'mysql' },
{ name: 'MariaDB', slug: 'maria' },
{ name: 'PostgreSQL', slug: 'pg' },
{ name: 'SQLite', slug: 'sqlite' }
{ name: 'SQLite', slug: 'sqlite' },
{ name: 'Firebird SQL (experimental)', slug: 'firebird' }
];
const connection = ref({

View File

@ -428,7 +428,8 @@ const clients = [
{ name: 'MySQL', slug: 'mysql' },
{ name: 'MariaDB', slug: 'maria' },
{ name: 'PostgreSQL', slug: 'pg' },
{ name: 'SQLite', slug: 'sqlite' }
{ name: 'SQLite', slug: 'sqlite' },
{ name: 'Firebird SQL (experimental)', slug: 'firebird' }
];
const firstInput: Ref<HTMLInputElement> = ref(null);

View File

@ -258,6 +258,9 @@ const runRoutine = (params?: string[]) => {
case 'pg':
sql = `CALL ${localElement.value.name}(${params.join(',')})`;
break;
case 'firebird':
sql = `EXECUTE PROCEDURE "${localElement.value.name}"(${params.join(',')})`;
break;
// case 'mssql':
// sql = `EXEC ${localElement.value.name} ${params.join(',')}`;
// break;

View File

@ -18,7 +18,7 @@
<span class="d-flex"><i class="mdi mdi-18px mdi-tune-vertical-variant text-light pr-1" /> {{ t('word.settings') }}</span>
</div>
<div
v-if="selectedTable && selectedTable.type === 'table'"
v-if="selectedTable && selectedTable.type === 'table' && customizations.tableDuplicate"
class="context-element"
@click="duplicateTable"
>

View File

@ -291,7 +291,7 @@ watch(consoleHeight, () => {
});
originalRoutine.value = {
sql: customizations.value.functionSql,
sql: customizations.value.procedureSql,
language: customizations.value.languages ? customizations.value.languages[0] : null,
name: '',
definer: '',

View File

@ -275,7 +275,13 @@ const saveContentListener = () => {
};
watch(() => props.isSelected, (val) => {
if (val) changeBreadcrumbs({ schema: props.schema });
if (val) {
changeBreadcrumbs({ schema: props.schema });
setTimeout(() => {
resizeQueryEditor();
}, 50);
}
});
watch(isChanged, (val) => {

View File

@ -351,6 +351,9 @@ const runRoutine = (params?: string[]) => {
case 'pg':
sql = `CALL ${originalRoutine.value.name}(${params.join(',')})`;
break;
case 'firebird':
sql = `EXECUTE PROCEDURE "${originalRoutine.value.name}"(${params.join(',')})`;
break;
case 'mssql':
sql = `EXEC ${originalRoutine.value.name} ${params.join(',')}`;
break;

View File

@ -118,29 +118,17 @@
{{ t('word.context') }}
</label>
<div class="column">
<label class="form-radio">
<label
v-for="condext in customizations.procedureContextValues"
:key="condext"
class="form-radio"
>
<input
v-model="selectedParamObj.context"
type="radio"
name="context"
value="IN"
> <i class="form-icon" /> IN
</label>
<label class="form-radio">
<input
v-model="selectedParamObj.context"
type="radio"
value="OUT"
name="context"
> <i class="form-icon" /> OUT
</label>
<label class="form-radio">
<input
v-model="selectedParamObj.context"
type="radio"
value="INOUT"
name="context"
> <i class="form-icon" /> INOUT
:value="condext"
> <i class="form-icon" /> {{ condext }}
</label>
</div>
</div>

View File

@ -300,7 +300,7 @@ const getFieldsData = async () => {
field.defaultType = 'noval';
else if (field.default === 'NULL')
field.defaultType = 'null';
else if (isNaN(+field.default) && field.default.charAt(0) !== '\'')
else if (typeof field.default === 'string' && isNaN(+field.default) && field.default.charAt(0) !== '\'')
field.defaultType = 'expression';
else {
field.defaultType = 'custom';
@ -323,11 +323,13 @@ const getFieldsData = async () => {
const { status, response } = await Tables.getTableIndexes(params);
if (status === 'success') {
const indexesObj = response.reduce((acc: {[key: string]: TableIndex[]}, curr: TableIndex) => {
acc[curr.name] = acc[curr.name] || [];
acc[curr.name].push(curr);
return acc;
}, {});
const indexesObj = response
.filter((index: TableIndex) => index.type !== 'FOREIGN KEY')
.reduce((acc: {[key: string]: TableIndex[]}, curr: TableIndex) => {
acc[curr.name] = acc[curr.name] || [];
acc[curr.name].push(curr);
return acc;
}, {});
originalIndexes.value = Object.keys(indexesObj).map(index => {
return {
@ -529,9 +531,10 @@ const clearChanges = () => {
};
const addField = () => {
const uid = uidGen();
localFields.value.push({
_antares_id: uidGen(),
name: `${t('word.field', 1)}_${++newFieldsCounter.value}`,
_antares_id: uid,
name: `${t('word.field', 1)}_${uid.substring(0, 4)}`,
key: '',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: (workspace.value.dataTypes[0] as any).types[0].name,

View File

@ -113,7 +113,7 @@
</div>
</div>
<div class="form-group">
<label class="form-label col-3 pt-0">
<label class="form-label col-3">
{{ t('message.referenceTable') }}
</label>
<div class="column">
@ -219,13 +219,8 @@ const foreignProxy = ref([]);
const selectedForeignID = ref('');
const modalInnerHeight = ref(400);
const refFields = ref({} as {[key: string]: TableField[]});
const foreignActions = [
'RESTRICT',
'CASCADE',
'SET NULL',
'NO ACTION'
];
const foreignActions = computed(() => props.workspace.customizations.foreignActions);
const selectedForeignObj = computed(() => foreignProxy.value.find(foreign => foreign._antares_id === selectedForeignID.value));
const isChanged = computed(() => JSON.stringify(props.localKeyUsage) !== JSON.stringify(foreignProxy.value));
@ -254,16 +249,17 @@ const getModalInnerHeight = () => {
};
const addForeign = () => {
const uid = uidGen();
foreignProxy.value = [...foreignProxy.value, {
_antares_id: uidGen(),
constraintName: `FK_${uidGen()}`,
_antares_id: uid,
constraintName: `FK_${uid.substring(0, 4)}`,
refSchema: props.schema,
table: props.table,
refTable: '',
field: '',
refField: '',
onUpdate: foreignActions[0],
onDelete: foreignActions[0]
onUpdate: foreignActions.value[0],
onDelete: foreignActions.value[0]
}];
if (foreignProxy.value.length === 1)
@ -271,6 +267,7 @@ const addForeign = () => {
setTimeout(() => {
indexesPanel.value.scrollTop = indexesPanel.value.scrollHeight + 60;
selectedForeignID.value = uid;
}, 20);
};

View File

@ -92,7 +92,7 @@
<BaseSelect
v-model="selectedIndexObj.type"
:options="indexTypes"
:option-disabled="(opt: any) => opt === 'PRIMARY'"
:option-disabled="(opt: any) => opt === 'PRIMARY' && hasPrimary"
class="form-select"
/>
</div>
@ -160,6 +160,7 @@ const modalInnerHeight = ref(400);
const selectedIndexObj = computed(() => indexesProxy.value.find(index => index._antares_id === selectedIndexID.value));
const isChanged = computed(() => JSON.stringify(props.localIndexes) !== JSON.stringify(indexesProxy.value));
const hasPrimary = computed(() => indexesProxy.value.some(index => ['PRIMARY', 'PRIMARY KEY'].includes(index.type)));
const confirmIndexesChange = () => {
indexesProxy.value = indexesProxy.value.filter(index => index.fields.length);
@ -179,15 +180,12 @@ const getModalInnerHeight = () => {
};
const addIndex = () => {
const uid = uidGen();
indexesProxy.value = [...indexesProxy.value, {
_antares_id: uidGen(),
name: 'NEW_INDEX',
_antares_id: uid,
name: `INDEX_${uid.substring(0, 4)}`,
fields: [],
type: 'INDEX',
comment: '',
indexType: 'BTREE',
indexComment: '',
cardinality: 0
type: props.workspace.customizations.primaryAsIndex ? props.indexTypes[0] : props.indexTypes[1]
}];
if (indexesProxy.value.length === 1)
@ -195,6 +193,7 @@ const addIndex = () => {
setTimeout(() => {
indexesPanel.value.scrollTop = indexesPanel.value.scrollHeight + 60;
selectedIndexID.value = uid;
}, 20);
};

View File

@ -501,8 +501,8 @@ const editOFF = () => {
localRow.value.enumValues = '';
if (fieldType.value.length) {
if (['integer', 'float', 'binary', 'spatial'].includes(fieldType.value.group)) localRow.value.numLength = 11;
if (['string'].includes(fieldType.value.group)) localRow.value.charLength = 15;
if (['integer', 'float', 'binary', 'spatial'].includes(fieldType.value.group)) localRow.value.numLength = 10;
if (['string'].includes(fieldType.value.group)) localRow.value.charLength = 20;
if (['time'].includes(fieldType.value.group)) localRow.value.datePrecision = 0;
if (['other'].includes(fieldType.value.group)) localRow.value.enumValues = '\'valA\',\'valB\'';
}

View File

@ -270,6 +270,8 @@ const keyName = (key: string) => {
return 'UNIQUE';
case 'mul':
return 'INDEX';
case 'fk':
return 'REFERENCES';
default:
return 'UNKNOWN ' + key;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -26,6 +26,8 @@
"macaddr8": $string-color,
"uuid": $string-color,
"regproc": $string-color,
"blob-text": $string-color,
"int": $number-color,
"tinyint": $number-color,
"smallint": $number-color,
@ -44,6 +46,7 @@
"double_precision": $number-color,
"oid": $number-color,
"xid": $number-color,
"money": $number-color,
"number": $number-color,
"datetime": $date-color,
@ -54,9 +57,12 @@
"timestamp": $date-color,
"timestamp_without_time_zone": $date-color,
"timestamp_with_time_zone": $date-color,
"bit": $bit-color,
"bit_varying": $bit-color,
"binary": $blob-color,
"char-binary": $blob-color,
"varbinary": $blob-color,
"blob": $blob-color,
"tinyblob": $blob-color,
@ -65,10 +71,12 @@
"longblob": $blob-color,
"long_blob": $blob-color,
"bytea": $blob-color,
"enum": $enum-color,
"set": $enum-color,
"bool": $enum-color,
"boolean": $enum-color,
"interval": $array-color,
"array": $array-color,
"anyarray": $array-color,
@ -85,6 +93,7 @@
"geomcollection": $array-color,
"geometrycollection": $array-color,
"aclitem": $array-color,
"unknown": $unknown-color,
)
);

View File

@ -25,6 +25,10 @@
background-image: url("../images/svg/sqlite.svg");
}
&.dbi-firebird {
background-image: url("../images/svg/firebird.svg");
}
&.dbi-oracledb {
background-image: url("../images/svg/oracledb.svg");
}

View File

@ -21,6 +21,10 @@
color: limegreen;
}
&.key-fk {
color: chocolate;
}
&.key-FULLTEXT {
color: mediumvioletred;
}

View File

@ -176,8 +176,6 @@ export const useWorkspacesStore = defineStore('workspaces', {
: workspace);
}
else {
let dataTypes: TypesGroup[] = [];
let indexTypes: string[] = [];
let clientCustomizations: Customizations;
const { updateLastConnection } = connectionsStore;
@ -186,21 +184,20 @@ export const useWorkspacesStore = defineStore('workspaces', {
switch (connection.client) {
case 'mysql':
case 'maria':
dataTypes = require('common/data-types/mysql').default;
indexTypes = require('common/index-types/mysql').default;
clientCustomizations = customizations.mysql;
break;
case 'pg':
dataTypes = require('common/data-types/postgresql').default;
indexTypes = require('common/index-types/postgresql').default;
clientCustomizations = customizations.pg;
break;
case 'sqlite':
dataTypes = require('common/data-types/sqlite').default;
indexTypes = require('common/index-types/sqlite').default;
clientCustomizations = customizations.sqlite;
break;
case 'firebird':
clientCustomizations = customizations.firebird;
break;
}
const dataTypes = clientCustomizations.dataTypes;
const indexTypes = clientCustomizations.indexTypes;
const { status, response: version } = await Schema.getVersion(connection.uid);