mirror of
https://github.com/Fabio286/antares.git
synced 2025-06-05 21:59:22 +02:00
Compare commits
13 Commits
v0.7.31-be
...
v0.7.31-be
Author | SHA1 | Date | |
---|---|---|---|
d03c1b90ce | |||
d34e56a517 | |||
0f35814ca0 | |||
96ae09feca | |||
e3b30359bf | |||
f3c3284fd1 | |||
27387f18a1 | |||
8e54f7b801 | |||
70aae2f194 | |||
592d7b3517 | |||
2b743a2c79 | |||
|
e493db5112 | ||
|
d3d7ab38c0 |
32
.github/workflows/create-artifact-windows-appx.yml
vendored
Normal file
32
.github/workflows/create-artifact-windows-appx.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Create artifact [WINDOWS APPX]
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: windows-2022
|
||||||
|
steps:
|
||||||
|
- name: Check out Git repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm i
|
||||||
|
|
||||||
|
- name: "Build"
|
||||||
|
run: npm run build:appx
|
||||||
|
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: windows-build
|
||||||
|
retention-days: 3
|
||||||
|
path: |
|
||||||
|
build
|
||||||
|
!build/*-unpacked
|
||||||
|
!build/.icon-ico
|
33
CHANGELOG.md
33
CHANGELOG.md
@@ -2,6 +2,39 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
### [0.7.31-beta.4](https://github.com/antares-sql/antares/compare/v0.7.31-beta.3...v0.7.31-beta.4) (2025-01-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Linux:** missing window management icons ([d34e56a](https://github.com/antares-sql/antares/commit/d34e56a517784dea16a7a53bc2249072a3b96596))
|
||||||
|
|
||||||
|
### [0.7.31-beta.3](https://github.com/antares-sql/antares/compare/v0.7.31-beta.2...v0.7.31-beta.3) (2025-01-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* implement a better query splitter for SQL queries, fixes [#926](https://github.com/antares-sql/antares/issues/926) ([96ae09f](https://github.com/antares-sql/antares/commit/96ae09fecad0c1fc8926d5dcf64cc779abe5ed49))
|
||||||
|
* **Linux:** update title bar for better Linux experience ([8e54f7b](https://github.com/antares-sql/antares/commit/8e54f7b80135768a33934bc9336239dee38401a5))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **MySQL:** adjust utf8mb3 encoding to resolve compatibility issue, fixes [#646](https://github.com/antares-sql/antares/issues/646) ([27387f1](https://github.com/antares-sql/antares/commit/27387f18a107fc6c09afec5f85134496ce764355))
|
||||||
|
|
||||||
|
### [0.7.31-beta.2](https://github.com/antares-sql/antares/compare/v0.7.31-beta.1...v0.7.31-beta.2) (2025-01-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add developer tools and refresh buttons to console in development mode ([592d7b3](https://github.com/antares-sql/antares/commit/592d7b35170f8437ebc15221c97985e889fccb40))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fail to fill cell to datetime column(Postgre) fixes [#924](https://github.com/antares-sql/antares/issues/924) ([d3d7ab3](https://github.com/antares-sql/antares/commit/d3d7ab38c029fc5ec23767c6c86c49a96e4e329c))
|
||||||
|
* reorder condition when format the update data ([e493db5](https://github.com/antares-sql/antares/commit/e493db5112478ff121e4e77f69c21747c5d2e032))
|
||||||
|
|
||||||
### [0.7.31-beta.1](https://github.com/antares-sql/antares/compare/v0.7.31-beta.0...v0.7.31-beta.1) (2025-01-22)
|
### [0.7.31-beta.1](https://github.com/antares-sql/antares/compare/v0.7.31-beta.0...v0.7.31-beta.1) (2025-01-22)
|
||||||
|
|
||||||
|
|
||||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "antares",
|
"name": "antares",
|
||||||
"version": "0.7.31-beta.1",
|
"version": "0.7.31-beta.4",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "antares",
|
"name": "antares",
|
||||||
"version": "0.7.31-beta.1",
|
"version": "0.7.31-beta.4",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "antares",
|
"name": "antares",
|
||||||
"productName": "Antares",
|
"productName": "Antares",
|
||||||
"version": "0.7.31-beta.1",
|
"version": "0.7.31-beta.4",
|
||||||
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
|
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/antares-sql/antares.git",
|
"repository": "https://github.com/antares-sql/antares.git",
|
||||||
|
@@ -34,6 +34,7 @@ export interface ClientParams {
|
|||||||
| { databasePath: string; readonly: boolean };
|
| { databasePath: string; readonly: boolean };
|
||||||
poolSize?: number;
|
poolSize?: number;
|
||||||
logger?: () => void;
|
logger?: () => void;
|
||||||
|
querySplitter?: (sql: string, clieng?: string) => string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
86
src/common/libs/querySplitter.ts
Normal file
86
src/common/libs/querySplitter.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import { ClientCode } from 'common/interfaces/antares';
|
||||||
|
|
||||||
|
export const querySplitter =(sql: string, dbType: ClientCode): string[] => {
|
||||||
|
const queries: string[] = [];
|
||||||
|
let currentQuery = '';
|
||||||
|
let insideBlock = false;
|
||||||
|
let insideString = false;
|
||||||
|
let stringDelimiter: string | null = null;
|
||||||
|
let insideDollarTag = false;
|
||||||
|
let dollarTagDelimiter: string | null = null;
|
||||||
|
|
||||||
|
// Regex patterns for BEGIN-END blocks, dollar tags in PostgreSQL, and semicolons
|
||||||
|
const beginRegex = /\bBEGIN\b/i;
|
||||||
|
const endRegex = /\bEND\b;/i;
|
||||||
|
const dollarTagRegex = /\$(\w+)?\$/; // Matches $tag$ or $$
|
||||||
|
|
||||||
|
// Split on semicolons, keeping semicolons attached to the lines
|
||||||
|
const lines = sql.split(/(?<=;)/);
|
||||||
|
|
||||||
|
for (let line of lines) {
|
||||||
|
line = line.trim();
|
||||||
|
|
||||||
|
if (!line) continue;
|
||||||
|
|
||||||
|
for (let i = 0; i < line.length; i++) {
|
||||||
|
const char = line[i];
|
||||||
|
|
||||||
|
// Handle string boundaries
|
||||||
|
if ((char === '\'' || char === '"') && (!insideString || char === stringDelimiter)) {
|
||||||
|
if (!insideString) {
|
||||||
|
insideString = true;
|
||||||
|
stringDelimiter = char;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
insideString = false;
|
||||||
|
stringDelimiter = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentQuery += char;
|
||||||
|
|
||||||
|
if (dbType === 'pg') {
|
||||||
|
// Handle dollar-quoted blocks in PostgreSQL
|
||||||
|
if (!insideString && line.slice(i).match(dollarTagRegex)) {
|
||||||
|
const match = line.slice(i).match(dollarTagRegex);
|
||||||
|
if (match) {
|
||||||
|
const tag = match[0];
|
||||||
|
if (!insideDollarTag) {
|
||||||
|
insideDollarTag = true;
|
||||||
|
dollarTagDelimiter = tag;
|
||||||
|
currentQuery += tag;
|
||||||
|
i += tag.length - 1;
|
||||||
|
}
|
||||||
|
else if (dollarTagDelimiter === tag) {
|
||||||
|
insideDollarTag = false;
|
||||||
|
dollarTagDelimiter = null;
|
||||||
|
currentQuery += tag;
|
||||||
|
i += tag.length - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check BEGIN-END blocks
|
||||||
|
if (!insideString && !insideDollarTag) {
|
||||||
|
if (beginRegex.test(line))
|
||||||
|
insideBlock = true;
|
||||||
|
|
||||||
|
if (insideBlock && endRegex.test(line))
|
||||||
|
insideBlock = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the query if we encounter a semicolon outside a BEGIN-END block, outside a string, and outside dollar tags
|
||||||
|
if (!insideBlock && !insideString && !insideDollarTag && /;\s*$/.test(line)) {
|
||||||
|
queries.push(currentQuery.trim());
|
||||||
|
currentQuery = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add any remaining query
|
||||||
|
if (currentQuery.trim())
|
||||||
|
queries.push(currentQuery.trim());
|
||||||
|
|
||||||
|
return queries;
|
||||||
|
};
|
@@ -2,27 +2,9 @@ import * as antares from 'common/interfaces/antares';
|
|||||||
import mysql from 'mysql2/promise';
|
import mysql from 'mysql2/promise';
|
||||||
import * as pg from 'pg';
|
import * as pg from 'pg';
|
||||||
import SSH2Promise = require('@fabio286/ssh2-promise');
|
import SSH2Promise = require('@fabio286/ssh2-promise');
|
||||||
|
import { querySplitter } from 'common/libs/querySplitter';
|
||||||
|
|
||||||
export type LoggerLevel = 'query' | 'error'
|
import { ipcLogger, LoggerLevel } from '../misc/ipcLogger';
|
||||||
|
|
||||||
const ipcLogger = ({ content, cUid, level }: {content: string; cUid: string; level: LoggerLevel}) => {
|
|
||||||
if (level === 'error') {
|
|
||||||
if (process.type !== undefined) {
|
|
||||||
const mainWindow = require('electron').webContents.fromId(1);
|
|
||||||
mainWindow.send('non-blocking-exception', { cUid, message: content, date: new Date() });
|
|
||||||
}
|
|
||||||
if (process.env.NODE_ENV === 'development' && process.type === 'browser') console.log(content);
|
|
||||||
}
|
|
||||||
else if (level === 'query') {
|
|
||||||
// Remove comments, newlines and multiple spaces
|
|
||||||
const escapedSql = content.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '').replace(/\s\s+/g, ' ');
|
|
||||||
if (process.type !== undefined) {
|
|
||||||
const mainWindow = require('electron').webContents.fromId(1);
|
|
||||||
mainWindow.send('query-log', { cUid, sql: escapedSql, date: new Date() });
|
|
||||||
}
|
|
||||||
if (process.env.NODE_ENV === 'development' && process.type === 'browser') console.log(escapedSql);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* As Simple As Possible Query Builder Core
|
* As Simple As Possible Query Builder Core
|
||||||
@@ -34,6 +16,7 @@ export abstract class BaseClient {
|
|||||||
protected _poolSize: number;
|
protected _poolSize: number;
|
||||||
protected _ssh?: SSH2Promise;
|
protected _ssh?: SSH2Promise;
|
||||||
protected _logger: (args: {content: string; cUid: string; level: LoggerLevel}) => void;
|
protected _logger: (args: {content: string; cUid: string; level: LoggerLevel}) => void;
|
||||||
|
protected _querySplitter: (sql: string, client: antares.ClientCode) => string[];
|
||||||
protected _queryDefaults: antares.QueryBuilderObject;
|
protected _queryDefaults: antares.QueryBuilderObject;
|
||||||
protected _query: antares.QueryBuilderObject;
|
protected _query: antares.QueryBuilderObject;
|
||||||
|
|
||||||
@@ -43,6 +26,7 @@ export abstract class BaseClient {
|
|||||||
this._params = args.params;
|
this._params = args.params;
|
||||||
this._poolSize = args.poolSize || undefined;
|
this._poolSize = args.poolSize || undefined;
|
||||||
this._logger = args.logger || ipcLogger;
|
this._logger = args.logger || ipcLogger;
|
||||||
|
this._querySplitter = args.querySplitter || querySplitter;
|
||||||
|
|
||||||
this._queryDefaults = {
|
this._queryDefaults = {
|
||||||
schema: '',
|
schema: '',
|
||||||
|
@@ -245,10 +245,10 @@ export class FirebirdSQLClient extends BaseClient {
|
|||||||
name: db.name,
|
name: db.name,
|
||||||
size: schemaSize,
|
size: schemaSize,
|
||||||
tables: remappedTables,
|
tables: remappedTables,
|
||||||
functions: [],
|
functions: [] as null[],
|
||||||
procedures: remappedProcedures,
|
procedures: remappedProcedures,
|
||||||
triggers: remappedTriggers,
|
triggers: remappedTriggers,
|
||||||
schedulers: []
|
schedulers: [] as null[]
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -337,7 +337,7 @@ export class FirebirdSQLClient extends BaseClient {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
name: field.FIELD_NAME.trim(),
|
name: field.FIELD_NAME.trim(),
|
||||||
key: null,
|
key: null as null,
|
||||||
type: fieldType,
|
type: fieldType,
|
||||||
schema: schema,
|
schema: schema,
|
||||||
table: table,
|
table: table,
|
||||||
@@ -346,14 +346,14 @@ export class FirebirdSQLClient extends BaseClient {
|
|||||||
datePrecision: field.FIELD_NAME.trim() === 'TIMESTAMP' ? 4 : null,
|
datePrecision: field.FIELD_NAME.trim() === 'TIMESTAMP' ? 4 : null,
|
||||||
charLength: ![...NUMBER, ...FLOAT].includes(fieldType) ? field.FIELD_LENGTH : null,
|
charLength: ![...NUMBER, ...FLOAT].includes(fieldType) ? field.FIELD_LENGTH : null,
|
||||||
nullable: !field.NOT_NULL,
|
nullable: !field.NOT_NULL,
|
||||||
unsigned: null,
|
unsigned: null as null,
|
||||||
zerofill: null,
|
zerofill: null as null,
|
||||||
order: field.FIELD_POSITION+1,
|
order: field.FIELD_POSITION+1,
|
||||||
default: defaultValue,
|
default: defaultValue,
|
||||||
charset: field.CHARSET,
|
charset: field.CHARSET,
|
||||||
collation: null,
|
collation: null as null,
|
||||||
autoIncrement: false,
|
autoIncrement: false,
|
||||||
onUpdate: null,
|
onUpdate: null as null,
|
||||||
comment: field.DESCRIPTION?.trim()
|
comment: field.DESCRIPTION?.trim()
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -457,7 +457,7 @@ export class FirebirdSQLClient extends BaseClient {
|
|||||||
table: table,
|
table: table,
|
||||||
field: field.FKCOLUMN_NAME.trim(),
|
field: field.FKCOLUMN_NAME.trim(),
|
||||||
position: field.KEY_SEQ,
|
position: field.KEY_SEQ,
|
||||||
constraintPosition: null,
|
constraintPosition: null as null,
|
||||||
constraintName: field.FK_NAME.trim(),
|
constraintName: field.FK_NAME.trim(),
|
||||||
refSchema: schema,
|
refSchema: schema,
|
||||||
refTable: field.PKTABLE_NAME.trim(),
|
refTable: field.PKTABLE_NAME.trim(),
|
||||||
@@ -1041,9 +1041,7 @@ export class FirebirdSQLClient extends BaseClient {
|
|||||||
const resultsArr = [];
|
const resultsArr = [];
|
||||||
let paramsArr = [];
|
let paramsArr = [];
|
||||||
const queries = args.split
|
const queries = args.split
|
||||||
? sql.split(/((?:[^;'"]*(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')[^;'"]*)+)|;/gm)
|
? this._querySplitter(sql, 'firebird')
|
||||||
.filter(Boolean)
|
|
||||||
.map(q => q.trim())
|
|
||||||
: [sql];
|
: [sql];
|
||||||
|
|
||||||
let connection: firebird.Database | firebird.Transaction;
|
let connection: firebird.Database | firebird.Transaction;
|
||||||
|
@@ -4,7 +4,9 @@ import dataTypes from 'common/data-types/mysql';
|
|||||||
import * as antares from 'common/interfaces/antares';
|
import * as antares from 'common/interfaces/antares';
|
||||||
import * as mysql from 'mysql2/promise';
|
import * as mysql from 'mysql2/promise';
|
||||||
|
|
||||||
|
import * as EncodingToCharset from '../../../../node_modules/mysql2/lib/constants/encoding_charset.js';
|
||||||
import { BaseClient } from './BaseClient';
|
import { BaseClient } from './BaseClient';
|
||||||
|
EncodingToCharset.utf8mb3 = 192; // To fix https://github.com/sidorares/node-mysql2/issues/1398 until not included in mysql2
|
||||||
|
|
||||||
export class MySQLClient extends BaseClient {
|
export class MySQLClient extends BaseClient {
|
||||||
private _schema?: string;
|
private _schema?: string;
|
||||||
@@ -1753,9 +1755,7 @@ export class MySQLClient extends BaseClient {
|
|||||||
const resultsArr: antares.QueryResult[] = [];
|
const resultsArr: antares.QueryResult[] = [];
|
||||||
let paramsArr = [];
|
let paramsArr = [];
|
||||||
const queries = args.split
|
const queries = args.split
|
||||||
? sql.split(/((?:[^;'"]*(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')[^;'"]*)+)|;/gm)
|
? this._querySplitter(sql, 'mysql')
|
||||||
.filter(Boolean)
|
|
||||||
.map(q => q.trim())
|
|
||||||
: [sql];
|
: [sql];
|
||||||
|
|
||||||
const connection = await this.getConnection(args);
|
const connection = await this.getConnection(args);
|
||||||
|
@@ -466,7 +466,7 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
procedures: remappedProcedures,
|
procedures: remappedProcedures,
|
||||||
triggers: remappedTriggers,
|
triggers: remappedTriggers,
|
||||||
triggerFunctions: remappedTriggerFunctions,
|
triggerFunctions: remappedTriggerFunctions,
|
||||||
schedulers: []
|
schedulers: [] as null[]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -532,7 +532,7 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
name: field.column_name,
|
name: field.column_name,
|
||||||
key: null,
|
key: null as null,
|
||||||
type: type.toUpperCase(),
|
type: type.toUpperCase(),
|
||||||
isArray,
|
isArray,
|
||||||
schema: field.table_schema,
|
schema: field.table_schema,
|
||||||
@@ -542,14 +542,14 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
datePrecision: field.datetime_precision,
|
datePrecision: field.datetime_precision,
|
||||||
charLength: field.character_maximum_length,
|
charLength: field.character_maximum_length,
|
||||||
nullable: field.is_nullable.includes('YES'),
|
nullable: field.is_nullable.includes('YES'),
|
||||||
unsigned: null,
|
unsigned: null as null,
|
||||||
zerofill: null,
|
zerofill: null as null,
|
||||||
order: field.ordinal_position,
|
order: field.ordinal_position,
|
||||||
default: field.column_default,
|
default: field.column_default,
|
||||||
charset: field.character_set_name,
|
charset: field.character_set_name,
|
||||||
collation: field.collation_name,
|
collation: field.collation_name,
|
||||||
autoIncrement: false,
|
autoIncrement: false,
|
||||||
onUpdate: null,
|
onUpdate: null as null,
|
||||||
comment: field.column_comment
|
comment: field.column_comment
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -1252,9 +1252,9 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
return results.rows.map(async row => {
|
return results.rows.map(async row => {
|
||||||
if (!row.pg_get_functiondef) {
|
if (!row.pg_get_functiondef) {
|
||||||
return {
|
return {
|
||||||
definer: null,
|
definer: null as null,
|
||||||
sql: '',
|
sql: '',
|
||||||
parameters: [],
|
parameters: [] as null[],
|
||||||
name: routine,
|
name: routine,
|
||||||
comment: '',
|
comment: '',
|
||||||
security: 'DEFINER',
|
security: 'DEFINER',
|
||||||
@@ -1303,8 +1303,8 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
name: routine,
|
name: routine,
|
||||||
comment: '',
|
comment: '',
|
||||||
security: row.pg_get_functiondef.includes('SECURITY DEFINER') ? 'DEFINER' : 'INVOKER',
|
security: row.pg_get_functiondef.includes('SECURITY DEFINER') ? 'DEFINER' : 'INVOKER',
|
||||||
deterministic: null,
|
deterministic: null as null,
|
||||||
dataAccess: null,
|
dataAccess: null as null,
|
||||||
language: row.pg_get_functiondef.match(/(?<=LANGUAGE )(.*)(?<=[\S+\n\r\s])/gm)[0]
|
language: row.pg_get_functiondef.match(/(?<=LANGUAGE )(.*)(?<=[\S+\n\r\s])/gm)[0]
|
||||||
};
|
};
|
||||||
})[0];
|
})[0];
|
||||||
@@ -1368,9 +1368,9 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
return results.rows.map(async row => {
|
return results.rows.map(async row => {
|
||||||
if (!row.pg_get_functiondef) {
|
if (!row.pg_get_functiondef) {
|
||||||
return {
|
return {
|
||||||
definer: null,
|
definer: null as null,
|
||||||
sql: '',
|
sql: '',
|
||||||
parameters: [],
|
parameters: [] as null[],
|
||||||
name: func,
|
name: func,
|
||||||
comment: '',
|
comment: '',
|
||||||
security: 'DEFINER',
|
security: 'DEFINER',
|
||||||
@@ -1418,8 +1418,8 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
name: func,
|
name: func,
|
||||||
comment: '',
|
comment: '',
|
||||||
security: row.pg_get_functiondef.includes('SECURITY DEFINER') ? 'DEFINER' : 'INVOKER',
|
security: row.pg_get_functiondef.includes('SECURITY DEFINER') ? 'DEFINER' : 'INVOKER',
|
||||||
deterministic: null,
|
deterministic: null as null,
|
||||||
dataAccess: null,
|
dataAccess: null as null,
|
||||||
language: row.pg_get_functiondef.match(/(?<=LANGUAGE )(.*)(?<=[\S+\n\r\s])/gm)[0],
|
language: row.pg_get_functiondef.match(/(?<=LANGUAGE )(.*)(?<=[\S+\n\r\s])/gm)[0],
|
||||||
returns: row.pg_get_functiondef.match(/(?<=RETURNS )(.*)(?<=[\S+\n\r\s])/gm)[0].replace('SETOF ', '').toUpperCase()
|
returns: row.pg_get_functiondef.match(/(?<=RETURNS )(.*)(?<=[\S+\n\r\s])/gm)[0].replace('SETOF ', '').toUpperCase()
|
||||||
};
|
};
|
||||||
@@ -1665,9 +1665,7 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
const resultsArr: antares.QueryResult[] = [];
|
const resultsArr: antares.QueryResult[] = [];
|
||||||
let paramsArr = [];
|
let paramsArr = [];
|
||||||
const queries = args.split
|
const queries = args.split
|
||||||
? sql.split(/(?!\B'[^']*);(?![^']*'\B)/gm)
|
? this._querySplitter(sql, 'pg')
|
||||||
.filter(Boolean)
|
|
||||||
.map(q => q.trim())
|
|
||||||
: [sql];
|
: [sql];
|
||||||
|
|
||||||
let connection: pg.Client | pg.PoolClient;
|
let connection: pg.Client | pg.PoolClient;
|
||||||
|
@@ -124,10 +124,10 @@ export class SQLiteClient extends BaseClient {
|
|||||||
name: db.name,
|
name: db.name,
|
||||||
size: schemaSize,
|
size: schemaSize,
|
||||||
tables: remappedTables,
|
tables: remappedTables,
|
||||||
functions: [],
|
functions: [] as null[],
|
||||||
procedures: [],
|
procedures: [] as null[],
|
||||||
triggers: remappedTriggers,
|
triggers: remappedTriggers,
|
||||||
schedulers: []
|
schedulers: [] as null[]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -166,22 +166,22 @@ export class SQLiteClient extends BaseClient {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
name: field.name,
|
name: field.name,
|
||||||
key: null,
|
key: null as null,
|
||||||
type: type.trim(),
|
type: type.trim(),
|
||||||
schema: schema,
|
schema: schema,
|
||||||
table: table,
|
table: table,
|
||||||
numLength: [...NUMBER, ...FLOAT].includes(type) ? length : null,
|
numLength: [...NUMBER, ...FLOAT].includes(type) ? length : null,
|
||||||
datePrecision: null,
|
datePrecision: null as null,
|
||||||
charLength: ![...NUMBER, ...FLOAT].includes(type) ? length : null,
|
charLength: ![...NUMBER, ...FLOAT].includes(type) ? length : null,
|
||||||
nullable: !field.notnull,
|
nullable: !field.notnull,
|
||||||
unsigned: null,
|
unsigned: null as null,
|
||||||
zerofill: null,
|
zerofill: null as null,
|
||||||
order: typeof field.cid === 'string' ? +field.cid + 1 : field.cid + 1,
|
order: typeof field.cid === 'string' ? +field.cid + 1 : field.cid + 1,
|
||||||
default: field.dflt_value,
|
default: field.dflt_value,
|
||||||
charset: null,
|
charset: null as null,
|
||||||
collation: null,
|
collation: null as null,
|
||||||
autoIncrement: false,
|
autoIncrement: false,
|
||||||
onUpdate: null,
|
onUpdate: null as null,
|
||||||
comment: ''
|
comment: ''
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -267,7 +267,7 @@ export class SQLiteClient extends BaseClient {
|
|||||||
table: table,
|
table: table,
|
||||||
field: field.from,
|
field: field.from,
|
||||||
position: field.id + 1,
|
position: field.id + 1,
|
||||||
constraintPosition: null,
|
constraintPosition: null as null,
|
||||||
constraintName: field.id,
|
constraintName: field.id,
|
||||||
refSchema: schema,
|
refSchema: schema,
|
||||||
refTable: field.table,
|
refTable: field.table,
|
||||||
@@ -629,9 +629,7 @@ export class SQLiteClient extends BaseClient {
|
|||||||
const resultsArr = [];
|
const resultsArr = [];
|
||||||
let paramsArr = [];
|
let paramsArr = [];
|
||||||
const queries = args.split
|
const queries = args.split
|
||||||
? sql.split(/((?:[^;'"]*(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')[^;'"]*)+)|;/gm)
|
? this._querySplitter(sql, 'sqlite')
|
||||||
.filter(Boolean)
|
|
||||||
.map(q => q.trim())
|
|
||||||
: [sql];
|
: [sql];
|
||||||
|
|
||||||
let connection: sqlite.Database;
|
let connection: sqlite.Database;
|
||||||
|
20
src/main/libs/misc/ipcLogger.ts
Normal file
20
src/main/libs/misc/ipcLogger.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
export type LoggerLevel = 'query' | 'error'
|
||||||
|
|
||||||
|
export const ipcLogger = ({ content, cUid, level }: {content: string; cUid: string; level: LoggerLevel}) => {
|
||||||
|
if (level === 'error') {
|
||||||
|
if (process.type !== undefined) {
|
||||||
|
const mainWindow = require('electron').webContents.fromId(1);
|
||||||
|
mainWindow.send('non-blocking-exception', { cUid, message: content, date: new Date() });
|
||||||
|
}
|
||||||
|
if (process.env.NODE_ENV === 'development' && process.type === 'browser') console.log(content);
|
||||||
|
}
|
||||||
|
else if (level === 'query') {
|
||||||
|
// Remove comments, newlines and multiple spaces
|
||||||
|
const escapedSql = content.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '').replace(/\s\s+/g, ' ');
|
||||||
|
if (process.type !== undefined) {
|
||||||
|
const mainWindow = require('electron').webContents.fromId(1);
|
||||||
|
mainWindow.send('query-log', { cUid, sql: escapedSql, date: new Date() });
|
||||||
|
}
|
||||||
|
if (process.env.NODE_ENV === 'development' && process.type === 'browser') console.log(escapedSql);
|
||||||
|
}
|
||||||
|
};
|
@@ -43,7 +43,8 @@ async function createMainWindow () {
|
|||||||
spellcheck: false
|
spellcheck: false
|
||||||
},
|
},
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
titleBarStyle: isLinux ? 'default' :'hidden',
|
frame: !isLinux,
|
||||||
|
titleBarStyle: 'hidden',
|
||||||
titleBarOverlay: isWindows
|
titleBarOverlay: isWindows
|
||||||
? {
|
? {
|
||||||
color: appTheme === 'dark' ? '#3f3f3f' : '#fff',
|
color: appTheme === 'dark' ? '#3f3f3f' : '#fff',
|
||||||
@@ -127,8 +128,8 @@ app.on('ready', async () => {
|
|||||||
if (isWindows)
|
if (isWindows)
|
||||||
mainWindow.show();
|
mainWindow.show();
|
||||||
|
|
||||||
if (isDevelopment && !isWindows)// Because on Windows you can open devtools from title-bar
|
// if (isDevelopment && !isWindows)
|
||||||
mainWindow.webContents.openDevTools();
|
// mainWindow.webContents.openDevTools();
|
||||||
|
|
||||||
process.on('uncaughtException', error => {
|
process.on('uncaughtException', error => {
|
||||||
mainWindow.webContents.send('unhandled-exception', error);
|
mainWindow.webContents.send('unhandled-exception', error);
|
||||||
|
@@ -21,8 +21,24 @@
|
|||||||
<a class="tab-link" @click="selectedTab = 'debug'">{{ t('application.debugConsole') }}</a>
|
<a class="tab-link" @click="selectedTab = 'debug'">{{ t('application.debugConsole') }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div class="d-flex">
|
||||||
|
<div
|
||||||
|
v-if="isDevelopment"
|
||||||
|
class="c-hand mr-2"
|
||||||
|
@click="openDevTools()"
|
||||||
|
>
|
||||||
|
<BaseIcon icon-name="mdiBugPlayOutline" :size="22" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="isDevelopment"
|
||||||
|
class="c-hand mr-2"
|
||||||
|
@click="reload()"
|
||||||
|
>
|
||||||
|
<BaseIcon icon-name="mdiRefresh" :size="22" />
|
||||||
|
</div>
|
||||||
<button class="btn btn-clear mr-1" @click="resizeConsole(0)" />
|
<button class="btn btn-clear mr-1" @click="resizeConsole(0)" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="selectedTab === 'query'"
|
v-show="selectedTab === 'query'"
|
||||||
ref="queryConsoleBody"
|
ref="queryConsoleBody"
|
||||||
@@ -71,6 +87,7 @@
|
|||||||
</BaseContextMenu>
|
</BaseContextMenu>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { getCurrentWindow } from '@electron/remote';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { highlight } from 'sql-highlight';
|
import { highlight } from 'sql-highlight';
|
||||||
@@ -112,6 +129,8 @@ const isHover = ref(false);
|
|||||||
const isContext = ref(false);
|
const isContext = ref(false);
|
||||||
const contextContent: Ref<string> = ref(null);
|
const contextContent: Ref<string> = ref(null);
|
||||||
const contextEvent: Ref<MouseEvent> = ref(null);
|
const contextEvent: Ref<MouseEvent> = ref(null);
|
||||||
|
const w = ref(getCurrentWindow());
|
||||||
|
const isDevelopment = ref(process.env.NODE_ENV === 'development');
|
||||||
|
|
||||||
const resize = (e: MouseEvent) => {
|
const resize = (e: MouseEvent) => {
|
||||||
const el = queryConsole.value;
|
const el = queryConsole.value;
|
||||||
@@ -142,6 +161,14 @@ const copyLog = () => {
|
|||||||
isContext.value = false;
|
isContext.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openDevTools = () => {
|
||||||
|
w.value.webContents.openDevTools();
|
||||||
|
};
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
w.value.reload();
|
||||||
|
};
|
||||||
|
|
||||||
watch(workspaceQueryLogs, async () => {
|
watch(workspaceQueryLogs, async () => {
|
||||||
if (!isHover.value) {
|
if (!isHover.value) {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-if="!isLinux"
|
|
||||||
id="titlebar"
|
id="titlebar"
|
||||||
@dblclick="toggleFullScreen"
|
@dblclick="toggleFullScreen"
|
||||||
>
|
>
|
||||||
@@ -21,16 +20,27 @@
|
|||||||
class="titlebar-element"
|
class="titlebar-element"
|
||||||
@click="openDevTools"
|
@click="openDevTools"
|
||||||
>
|
>
|
||||||
<BaseIcon icon-name="mdiBugPlayOutline" :size="24" />
|
<BaseIcon icon-name="mdiBugPlayOutline" :size="18" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="isDevelopment"
|
v-if="isDevelopment"
|
||||||
class="titlebar-element"
|
class="titlebar-element"
|
||||||
@click="reload"
|
@click="reload"
|
||||||
>
|
>
|
||||||
<BaseIcon icon-name="mdiRefresh" :size="24" />
|
<BaseIcon icon-name="mdiRefresh" :size="18" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isWindows" :style="'width: 140px;'" />
|
<div v-if="isWindows" :style="'width: 140px;'" />
|
||||||
|
<div v-if="isLinux" class="d-flex">
|
||||||
|
<div class="titlebar-element" @click="minimize">
|
||||||
|
<BaseIcon icon-name="mdiWindowMinimize" :size="18" />
|
||||||
|
</div>
|
||||||
|
<div class="titlebar-element" @click="toggleFullScreen">
|
||||||
|
<BaseIcon :icon-name="isMaximized ? 'mdiWindowRestore' : 'mdiWindowMaximize'" :size="18" />
|
||||||
|
</div>
|
||||||
|
<div class="titlebar-element" @click="closeApp">
|
||||||
|
<BaseIcon icon-name="mdiClose" :size="18" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -74,6 +84,18 @@ const windowTitle = computed(() => {
|
|||||||
return [connectionName, ...breadcrumbs].join(' • ');
|
return [connectionName, ...breadcrumbs].join(' • ');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const openDevTools = () => {
|
||||||
|
w.value.webContents.openDevTools();
|
||||||
|
};
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
w.value.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
const minimize = () => {
|
||||||
|
w.value.minimize();
|
||||||
|
};
|
||||||
|
|
||||||
const toggleFullScreen = () => {
|
const toggleFullScreen = () => {
|
||||||
if (isMaximized.value)
|
if (isMaximized.value)
|
||||||
w.value.unmaximize();
|
w.value.unmaximize();
|
||||||
@@ -81,12 +103,8 @@ const toggleFullScreen = () => {
|
|||||||
w.value.maximize();
|
w.value.maximize();
|
||||||
};
|
};
|
||||||
|
|
||||||
const openDevTools = () => {
|
const closeApp = () => {
|
||||||
w.value.webContents.openDevTools();
|
ipcRenderer.send('close-app');
|
||||||
};
|
|
||||||
|
|
||||||
const reload = () => {
|
|
||||||
w.value.reload();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onResize = () => {
|
const onResize = () => {
|
||||||
|
@@ -696,15 +696,15 @@ const fillCell = (event: { name: string; group: string; type: string }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fakeValue = (fakerCustom as any)[event.group][event.name]();
|
fakeValue = (fakerCustom as any)[event.group][event.name]();
|
||||||
if (['string', 'number'].includes(typeof fakeValue)) {
|
const isDateType = [...DATE, ...DATETIME].includes(selectedCell.value.type);
|
||||||
|
if (isDateType)
|
||||||
|
fakeValue = moment(fakeValue).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
|
||||||
|
else if (['string', 'number'].includes(typeof fakeValue)) {
|
||||||
if (typeof fakeValue === 'number')
|
if (typeof fakeValue === 'number')
|
||||||
fakeValue = String(fakeValue);
|
fakeValue = String(fakeValue);
|
||||||
|
|
||||||
if (selectedCell.value.length)
|
if (selectedCell.value.length)
|
||||||
fakeValue = fakeValue.substring(0, selectedCell.value.length < 1024 ? Number(selectedCell.value.length) : 1024);
|
fakeValue = fakeValue.substring(0, selectedCell.value.length < 1024 ? Number(selectedCell.value.length) : 1024);
|
||||||
}
|
}
|
||||||
else if ([...DATE, ...DATETIME].includes(selectedCell.value.type))
|
|
||||||
fakeValue = moment(fakeValue).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
|
|
||||||
else if (TIME.includes(selectedCell.value.type))
|
else if (TIME.includes(selectedCell.value.type))
|
||||||
fakeValue = moment(fakeValue).format(`HH:mm:ss${datePrecision}`);
|
fakeValue = moment(fakeValue).format(`HH:mm:ss${datePrecision}`);
|
||||||
|
|
||||||
|
@@ -29,14 +29,8 @@ $explorebar-width: 14rem;
|
|||||||
$footer-height: 1.5rem;
|
$footer-height: 1.5rem;
|
||||||
|
|
||||||
@function get-excluding-size() {
|
@function get-excluding-size() {
|
||||||
@if $platform == linux {
|
|
||||||
@return $footer-height;
|
|
||||||
}
|
|
||||||
|
|
||||||
@else {
|
|
||||||
@return $footer-height + $titlebar-height;
|
@return $footer-height + $titlebar-height;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* stylelint-disable-next-line function-no-unknown */
|
/* stylelint-disable-next-line function-no-unknown */
|
||||||
$excluding-size: get-excluding-size();
|
$excluding-size: get-excluding-size();
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
background-color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
1
src/renderer/untyped.d.ts
vendored
1
src/renderer/untyped.d.ts
vendored
@@ -3,6 +3,7 @@
|
|||||||
declare module '@/App.vue';
|
declare module '@/App.vue';
|
||||||
declare module 'v-mask';
|
declare module 'v-mask';
|
||||||
declare module 'json2php';
|
declare module 'json2php';
|
||||||
|
declare module '*/encoding_charset.js';
|
||||||
declare module 'vuedraggable' {// <- to export as default
|
declare module 'vuedraggable' {// <- to export as default
|
||||||
const draggableComponent: import('vue').DefineComponent<{
|
const draggableComponent: import('vue').DefineComponent<{
|
||||||
list: {
|
list: {
|
||||||
|
Reference in New Issue
Block a user