mirror of
https://github.com/Fabio286/antares.git
synced 2025-03-09 16:00:17 +01:00
Merge pull request #472 from antares-sql/firebirdsql-support
Firebird SQL support
This commit is contained in:
commit
038cf68253
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -5,6 +5,7 @@
|
||||
"MySQL",
|
||||
"PostgreSQL",
|
||||
"SQLite",
|
||||
"Firebird SQL",
|
||||
"Windows",
|
||||
"translation",
|
||||
"Linux",
|
||||
|
@ -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
32
package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
63
src/common/customizations/firebird.ts
Normal file
63
src/common/customizations/firebird.ts
Normal 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
|
||||
};
|
@ -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;
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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$',
|
||||
|
@ -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,
|
||||
|
136
src/common/data-types/firebird.ts
Normal file
136
src/common/data-types/firebird.ts
Normal 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[];
|
@ -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 = [
|
||||
|
@ -1,6 +0,0 @@
|
||||
export default [
|
||||
'PRIMARY',
|
||||
'INDEX',
|
||||
'UNIQUE',
|
||||
'FULLTEXT'
|
||||
];
|
@ -1,5 +0,0 @@
|
||||
export default [
|
||||
'PRIMARY',
|
||||
'INDEX',
|
||||
'UNIQUE'
|
||||
];
|
@ -1,5 +0,0 @@
|
||||
export default [
|
||||
'PRIMARY',
|
||||
'INDEX',
|
||||
'UNIQUE'
|
||||
];
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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' };
|
||||
|
@ -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 };
|
||||
}
|
||||
|
@ -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 };
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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}`);
|
||||
}
|
||||
|
1247
src/main/libs/clients/FirebirdSQLClient.ts
Normal file
1247
src/main/libs/clients/FirebirdSQLClient.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -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'
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -240,7 +240,9 @@ watch(() => tablesInQuery.value.length, () => {
|
||||
});
|
||||
|
||||
fields.value = localFields;
|
||||
setCustomCompleter();
|
||||
setTimeout(() => {
|
||||
setCustomCompleter();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
watch(editorTheme, () => {
|
||||
|
@ -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({
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
>
|
||||
|
@ -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: '',
|
||||
|
@ -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) => {
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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\'';
|
||||
}
|
||||
|
@ -270,6 +270,8 @@ const keyName = (key: string) => {
|
||||
return 'UNIQUE';
|
||||
case 'mul':
|
||||
return 'INDEX';
|
||||
case 'fk':
|
||||
return 'REFERENCES';
|
||||
default:
|
||||
return 'UNKNOWN ' + key;
|
||||
}
|
||||
|
1
src/renderer/images/svg/firebird.svg
Normal file
1
src/renderer/images/svg/firebird.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 6.5 KiB |
@ -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,
|
||||
)
|
||||
);
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -21,6 +21,10 @@
|
||||
color: limegreen;
|
||||
}
|
||||
|
||||
&.key-fk {
|
||||
color: chocolate;
|
||||
}
|
||||
|
||||
&.key-FULLTEXT {
|
||||
color: mediumvioletred;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user