mirror of
https://github.com/beekeeper-studio/beekeeper-studio.git
synced 2026-03-13 10:12:54 +08:00
Initial BigQuery Client Support
Initial BigQuery Client Support Upstream update ConnectionInterface.vue Multiple changes, cleanup and vscode - Cleanup code for upstream PR - Finally a working vscode launch with proper sourceMap for Renderer Add listViews and logs cleanup Vscode Launch config Adding BigQuery Client Update Bigqueryform.vue fix build issues Bigquery, bugfixes and changes
This commit is contained in:
45
.vscode/launch.json
vendored
Normal file
45
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Electron: Main",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd":"${workspaceFolder}/apps/studio",
|
||||
"runtimeExecutable": "${workspaceFolder}/apps/studio/node_modules/.bin/electron",
|
||||
"preLaunchTask": "electron-debug",
|
||||
"args": [
|
||||
"--remote-debugging-port=9223",
|
||||
"./dist_electron",
|
||||
"--enable-logging"
|
||||
],
|
||||
"sourceMapPathOverrides": {
|
||||
"webpack:///./src/*": "${webRoot}/apps/studio/src/*"
|
||||
},
|
||||
"sourceMaps": true,
|
||||
},
|
||||
|
||||
{
|
||||
"name": "Electron: Renderer",
|
||||
"type": "chrome",
|
||||
"request": "attach",
|
||||
"port": 9223,
|
||||
"urlFilter": "http://localhost:*",
|
||||
"timeout": 50000,
|
||||
"webRoot": "${workspaceFolder}",
|
||||
"sourceMapPathOverrides": {
|
||||
"webpack:///./src/*": "${webRoot}/apps/studio/src/*"
|
||||
},
|
||||
"sourceMaps": true,
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Electron: All",
|
||||
"configurations": [
|
||||
"Electron: Main",
|
||||
"Electron: Renderer"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
32
.vscode/tasks.json
vendored
Normal file
32
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "electron-debug",
|
||||
"type": "process",
|
||||
"echoCommand": true,
|
||||
"options": {
|
||||
"cwd": "apps/studio"
|
||||
},
|
||||
"command": "./node_modules/.bin/vue-cli-service",
|
||||
"isBackground": true,
|
||||
"args": [
|
||||
"electron:serve",
|
||||
"--remote-debugging-port=9223",
|
||||
"--debug",
|
||||
],
|
||||
"problemMatcher": {
|
||||
"owner": "custom",
|
||||
"pattern": {
|
||||
"regexp": ""
|
||||
},
|
||||
"background": {
|
||||
"beginsPattern": "Starting development server\\.\\.\\.",
|
||||
"endsPattern": "Not launching electron as debug argument was passed\\."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -48,6 +48,9 @@
|
||||
.sqlite-form {
|
||||
margin-bottom: $gutter-h;
|
||||
}
|
||||
.bigquery-form {
|
||||
margin-bottom: $gutter-h;
|
||||
}
|
||||
.text-connect {
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,12 @@ app.on('activate', async (_event, hasVisibleWindows) => {
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on('ready', async () => {
|
||||
if (isDevelopment && !process.env.IS_TEST) {
|
||||
// Need to explicitly disable CORS when running in dev mode because
|
||||
// we can't connect to bigquery-emulator on localhost.
|
||||
// See: https://github.com/electron/electron/issues/23664
|
||||
console.log("Dev mode detected, disabling CORS")
|
||||
app.commandLine.appendSwitch('disable-web-security');
|
||||
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors')
|
||||
// Install Vue Devtools
|
||||
try {
|
||||
console.log("installing vue devtools")
|
||||
|
||||
@@ -22,7 +22,8 @@ export const ConnectionTypes = [
|
||||
{ name: 'Amazon Redshift', value: 'redshift' },
|
||||
{ name: 'CockroachDB', value: 'cockroachdb' },
|
||||
{ name: 'Oracle', value: 'other' },
|
||||
{ name: 'Cassandra', value: 'other' }
|
||||
{ name: 'Cassandra', value: 'other' },
|
||||
{ name: 'BigQuery', value: 'bigquery' },
|
||||
]
|
||||
|
||||
export const keymapTypes = [
|
||||
@@ -40,6 +41,12 @@ export interface RedshiftOptions {
|
||||
tokenDurationSeconds?: number;
|
||||
}
|
||||
|
||||
export interface BigQueryOptions {
|
||||
iamAuthenticationEnabled?: boolean
|
||||
keyFilename?: string;
|
||||
projectId?: string;
|
||||
}
|
||||
|
||||
export interface ConnectionOptions {
|
||||
cluster?: string
|
||||
}
|
||||
@@ -99,6 +106,8 @@ export class DbConnectionBase extends ApplicationEntity {
|
||||
return 1433
|
||||
} else if (this.connectionType === 'cockroachdb') {
|
||||
return 26257
|
||||
} else if (this._connectionType === 'bigquery') {
|
||||
return 443
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -185,6 +194,9 @@ export class DbConnectionBase extends ApplicationEntity {
|
||||
@Column({ type: 'simple-json', nullable: false })
|
||||
redshiftOptions: RedshiftOptions = {}
|
||||
|
||||
@Column({ type: 'simple-json', nullable: false })
|
||||
bigQueryOptions: BigQueryOptions = {}
|
||||
|
||||
// this is only for SQL Server.
|
||||
@Column({ type: 'boolean', nullable: false })
|
||||
trustServerCertificate = false
|
||||
|
||||
@@ -30,6 +30,7 @@ export class UsedConnection extends DbConnectionBase implements ISimpleConnectio
|
||||
this.options = other.options
|
||||
this.trustServerCertificate = other.trustServerCertificate
|
||||
this.redshiftOptions = other.redshiftOptions
|
||||
this.bigQueryOptions = other.bigQueryOptions
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { RedshiftOptions } from "../appdb/models/saved_connection"
|
||||
import { BigQueryOptions } from "../appdb/models/saved_connection"
|
||||
|
||||
export type ConnectionType = 'sqlite' | 'sqlserver' | 'redshift' | 'cockroachdb' | 'mysql' | 'postgresql' | 'mariadb' | 'cassandra'
|
||||
export type ConnectionType = 'sqlite' | 'sqlserver' | 'redshift' | 'cockroachdb' | 'mysql' | 'postgresql' | 'mariadb' | 'cassandra' | 'bigquery'
|
||||
export type SshMode = null | 'agent' | 'userpass' | 'keyfile'
|
||||
|
||||
export interface ISimpleConnection {
|
||||
@@ -31,6 +32,7 @@ export interface ISimpleConnection {
|
||||
trustServerCertificate?: boolean
|
||||
options?: any
|
||||
redshiftOptions?: RedshiftOptions
|
||||
bigQueryOptions?: BigQueryOptions
|
||||
}
|
||||
|
||||
export interface IConnection extends ISimpleConnection {
|
||||
|
||||
@@ -109,6 +109,11 @@
|
||||
:config="config"
|
||||
:testing="testing"
|
||||
/>
|
||||
<big-query-form
|
||||
v-if="config.connectionType === 'bigquery'"
|
||||
:config="config"
|
||||
:testing="testing"
|
||||
/>
|
||||
<other-database-notice v-if="config.connectionType === 'other'" />
|
||||
|
||||
<!-- TEST AND CONNECT -->
|
||||
@@ -161,239 +166,240 @@
|
||||
class="pitch"
|
||||
v-if="!config.connectionType"
|
||||
>
|
||||
🧚 Hey! If you love the app, consider buying the full version of Beekeeper Studio to support us (and get more features too!). <a
|
||||
🧚 Hey! If you love the app, consider buying the full version of Beekeeper Studio to support us (and get more
|
||||
features too!). <a
|
||||
href="https://docs.beekeeperstudio.io/docs/upgrading-from-the-community-edition"
|
||||
class=""
|
||||
>Learn more ></a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<small class="app-version"><a href="https://www.beekeeperstudio.io/releases/latest">Beekeeper Studio {{ version }}</a></small>
|
||||
<small class="app-version"><a href="https://www.beekeeperstudio.io/releases/latest">Beekeeper Studio {{ version
|
||||
}}</a></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import os from 'os'
|
||||
import {SavedConnection} from '../common/appdb/models/saved_connection'
|
||||
import ConnectionSidebar from './sidebar/ConnectionSidebar.vue'
|
||||
import MysqlForm from './connection/MysqlForm.vue'
|
||||
import PostgresForm from './connection/PostgresForm.vue'
|
||||
import RedshiftForm from './connection/RedshiftForm.vue'
|
||||
import Sidebar from './common/Sidebar.vue'
|
||||
import SqliteForm from './connection/SqliteForm.vue'
|
||||
import SqlServerForm from './connection/SqlServerForm.vue'
|
||||
import SaveConnectionForm from './connection/SaveConnectionForm.vue'
|
||||
import Split from 'split.js'
|
||||
import ImportButton from './connection/ImportButton.vue'
|
||||
import _ from 'lodash'
|
||||
import platformInfo from '@/common/platform_info'
|
||||
import ErrorAlert from './common/ErrorAlert.vue'
|
||||
import rawLog from 'electron-log'
|
||||
import { mapState } from 'vuex'
|
||||
import { dialectFor } from '@shared/lib/dialects/models'
|
||||
import { findClient } from '@/lib/db/clients'
|
||||
import OtherDatabaseNotice from './connection/OtherDatabaseNotice.vue'
|
||||
import Vue from 'vue'
|
||||
import os from 'os'
|
||||
import { SavedConnection } from '../common/appdb/models/saved_connection'
|
||||
import ConnectionSidebar from './sidebar/ConnectionSidebar.vue'
|
||||
import MysqlForm from './connection/MysqlForm.vue'
|
||||
import PostgresForm from './connection/PostgresForm.vue'
|
||||
import RedshiftForm from './connection/RedshiftForm.vue'
|
||||
import Sidebar from './common/Sidebar.vue'
|
||||
import SqliteForm from './connection/SqliteForm.vue'
|
||||
import SqlServerForm from './connection/SqlServerForm.vue'
|
||||
import SaveConnectionForm from './connection/SaveConnectionForm.vue'
|
||||
import BigQueryForm from './connection/BigQueryForm.vue'
|
||||
import Split from 'split.js'
|
||||
import ImportButton from './connection/ImportButton.vue'
|
||||
import _ from 'lodash'
|
||||
import platformInfo from '@/common/platform_info'
|
||||
import ErrorAlert from './common/ErrorAlert.vue'
|
||||
import rawLog from 'electron-log'
|
||||
import { mapState } from 'vuex'
|
||||
import { dialectFor } from '@shared/lib/dialects/models'
|
||||
import { findClient } from '@/lib/db/clients'
|
||||
import OtherDatabaseNotice from './connection/OtherDatabaseNotice.vue'
|
||||
import Vue from 'vue'
|
||||
|
||||
const log = rawLog.scope('ConnectionInterface')
|
||||
// import ImportUrlForm from './connection/ImportUrlForm';
|
||||
|
||||
const log = rawLog.scope('ConnectionInterface')
|
||||
// import ImportUrlForm from './connection/ImportUrlForm';
|
||||
export default Vue.extend({
|
||||
components: { ConnectionSidebar, MysqlForm, PostgresForm, RedshiftForm, Sidebar, SqliteForm, SqlServerForm, SaveConnectionForm, ImportButton, ErrorAlert, OtherDatabaseNotice, BigQueryForm, },
|
||||
|
||||
export default Vue.extend({
|
||||
components: { ConnectionSidebar, MysqlForm, PostgresForm, RedshiftForm, Sidebar, SqliteForm, SqlServerForm, SaveConnectionForm, ImportButton, ErrorAlert, OtherDatabaseNotice, },
|
||||
|
||||
data() {
|
||||
return {
|
||||
config: new SavedConnection(),
|
||||
errors: null,
|
||||
connectionError: null,
|
||||
errorHelp: null,
|
||||
testing: false,
|
||||
split: null,
|
||||
url: null,
|
||||
importError: null,
|
||||
sidebarShown: true,
|
||||
version: platformInfo.appVersion
|
||||
data() {
|
||||
return {
|
||||
config: new SavedConnection(),
|
||||
errors: null,
|
||||
connectionError: null,
|
||||
errorHelp: null,
|
||||
testing: false,
|
||||
split: null,
|
||||
url: null,
|
||||
importError: null,
|
||||
sidebarShown: true,
|
||||
version: platformInfo.appVersion
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['workspaceId']),
|
||||
...mapState('data/connections', { 'connections': 'items' }),
|
||||
connectionTypes() {
|
||||
return this.$config.defaults.connectionTypes
|
||||
},
|
||||
pageTitle() {
|
||||
if (_.isNull(this.config) || _.isUndefined(this.config.id)) {
|
||||
return "New Connection"
|
||||
} else {
|
||||
return this.config.name
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['workspaceId']),
|
||||
...mapState('data/connections', {'connections': 'items'}),
|
||||
connectionTypes() {
|
||||
return this.$config.defaults.connectionTypes
|
||||
},
|
||||
pageTitle() {
|
||||
if(_.isNull(this.config) || _.isUndefined(this.config.id)) {
|
||||
return "New Connection"
|
||||
} else {
|
||||
return this.config.name
|
||||
}
|
||||
},
|
||||
dialect() {
|
||||
return dialectFor(this.config.connectionType)
|
||||
dialect() {
|
||||
return dialectFor(this.config.connectionType)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
workspaceId() {
|
||||
this.config = new SavedConnection()
|
||||
},
|
||||
config: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.connectionError = null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
workspaceId() {
|
||||
this.config = new SavedConnection()
|
||||
},
|
||||
config: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.connectionError = null
|
||||
}
|
||||
},
|
||||
'config.connectionType'(newConnectionType) {
|
||||
if(!findClient(newConnectionType)?.supportsSocketPath) {
|
||||
this.config.socketPathEnabled = false
|
||||
}
|
||||
},
|
||||
connectionError() {
|
||||
console.log("error watch", this.connectionError, this.dialect)
|
||||
if (this.connectionError &&
|
||||
this.dialect == 'sqlserver' &&
|
||||
this.connectionError.message &&
|
||||
this.connectionError.message.includes('self signed certificate')
|
||||
) {
|
||||
this.errorHelp = `You might need to check 'Trust Server Certificate'`
|
||||
} else {
|
||||
'config.connectionType'(newConnectionType) {
|
||||
if (!findClient(newConnectionType)?.supportsSocketPath) {
|
||||
this.config.socketPathEnabled = false
|
||||
}
|
||||
},
|
||||
connectionError() {
|
||||
console.log("error watch", this.connectionError, this.dialect)
|
||||
if (this.connectionError &&
|
||||
this.dialect == 'sqlserver' &&
|
||||
this.connectionError.message &&
|
||||
this.connectionError.message.includes('self signed certificate')
|
||||
) {
|
||||
this.errorHelp = `You might need to check 'Trust Server Certificate'`
|
||||
} else {
|
||||
this.errorHelp = null
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (!this.$store.getters.workspace) {
|
||||
await this.$store.commit('workspace', this.$store.state.localWorkspace)
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (!this.$store.getters.workspace) {
|
||||
await this.$store.commit('workspace', this.$store.state.localWorkspace)
|
||||
}
|
||||
await this.$store.dispatch('loadUsedConfigs')
|
||||
await this.$store.dispatch('pinnedConnections/loadPins')
|
||||
await this.$store.dispatch('pinnedConnections/reorder', this.$store.state.pinnedConnections.pins)
|
||||
this.config.sshUsername = os.userInfo().username
|
||||
this.$nextTick(() => {
|
||||
const components = [
|
||||
this.$refs.sidebar.$refs.sidebar,
|
||||
this.$refs.content
|
||||
]
|
||||
this.split = Split(components, {
|
||||
elementStyle: (_dimension, size) => ({
|
||||
'flex-basis': `calc(${size}%)`,
|
||||
}),
|
||||
sizes: [300, 500],
|
||||
gutterize: 8,
|
||||
minSize: [300, 300],
|
||||
expandToMin: true,
|
||||
} as Split.Options)
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.split) {
|
||||
this.split.destroy()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
maybeLoadSqlite(e) {
|
||||
// cast to an array
|
||||
const files = [...e.dataTransfer.files || []]
|
||||
if (!files || !files.length) return
|
||||
if (!this.config) return;
|
||||
// we only load the first
|
||||
const file = files[0]
|
||||
const allGood = this.config.parse(file.path)
|
||||
if (!allGood) {
|
||||
this.$noty.error(`Unable to open '${file.name}'. It is not a valid SQLite file.`);
|
||||
return
|
||||
} else {
|
||||
this.submit()
|
||||
}
|
||||
await this.$store.dispatch('loadUsedConfigs')
|
||||
await this.$store.dispatch('pinnedConnections/loadPins')
|
||||
await this.$store.dispatch('pinnedConnections/reorder', this.$store.state.pinnedConnections.pins)
|
||||
this.config.sshUsername = os.userInfo().username
|
||||
this.$nextTick(() => {
|
||||
const components = [
|
||||
this.$refs.sidebar.$refs.sidebar,
|
||||
this.$refs.content
|
||||
]
|
||||
this.split = Split(components, {
|
||||
elementStyle: (_dimension, size) => ({
|
||||
'flex-basis': `calc(${size}%)`,
|
||||
}),
|
||||
sizes: [300,500],
|
||||
gutterize: 8,
|
||||
minSize: [300, 300],
|
||||
expandToMin: true,
|
||||
} as Split.Options)
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
if(this.split) {
|
||||
this.split.destroy()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
maybeLoadSqlite(e) {
|
||||
// cast to an array
|
||||
const files = [...e.dataTransfer.files || []]
|
||||
if (!files || !files.length) return
|
||||
if (!this.config) return;
|
||||
// we only load the first
|
||||
const file = files[0]
|
||||
const allGood = this.config.parse(file.path)
|
||||
if (!allGood) {
|
||||
this.$noty.error(`Unable to open '${file.name}'. It is not a valid SQLite file.`);
|
||||
return
|
||||
} else {
|
||||
this.submit()
|
||||
}
|
||||
|
||||
},
|
||||
create() {
|
||||
},
|
||||
create() {
|
||||
this.config = new SavedConnection()
|
||||
},
|
||||
edit(config) {
|
||||
this.config = config
|
||||
this.errors = null
|
||||
this.connectionError = null
|
||||
},
|
||||
async remove(config) {
|
||||
if (this.config === config) {
|
||||
this.config = new SavedConnection()
|
||||
},
|
||||
edit(config) {
|
||||
this.config = config
|
||||
}
|
||||
await this.$store.dispatch('pinnedConnections/remove', config)
|
||||
await this.$store.dispatch('data/connections/remove', config)
|
||||
this.$noty.success(`${config.name} deleted`)
|
||||
},
|
||||
async duplicate(config) {
|
||||
// Duplicates ES 6 class of the connection, without any reference to the old one.
|
||||
const duplicateConfig = await this.$store.dispatch('data/connections/clone', config)
|
||||
duplicateConfig.name = 'Copy of ' + duplicateConfig.name
|
||||
|
||||
try {
|
||||
const id = await this.$store.dispatch('data/connections/save', duplicateConfig)
|
||||
this.$noty.success(`The connection was successfully duplicated!`)
|
||||
this.config = this.connections.find((c) => c.id === id) || this.config
|
||||
} catch (ex) {
|
||||
this.$noty.error(`Could not duplicate Connection: ${ex.message}`)
|
||||
}
|
||||
|
||||
},
|
||||
async submit() {
|
||||
this.connectionError = null
|
||||
try {
|
||||
await this.$store.dispatch('connect', this.config)
|
||||
} catch (ex) {
|
||||
this.connectionError = ex
|
||||
this.$noty.error("Error establishing a connection")
|
||||
log.error(ex)
|
||||
}
|
||||
},
|
||||
async handleConnect(config) {
|
||||
this.config = config
|
||||
await this.submit()
|
||||
},
|
||||
async testConnection() {
|
||||
|
||||
try {
|
||||
this.testing = true
|
||||
this.connectionError = null
|
||||
await this.$store.dispatch('test', this.config)
|
||||
this.$noty.success("Connection looks good!")
|
||||
return true
|
||||
} catch (ex) {
|
||||
this.connectionError = ex
|
||||
this.$noty.error("Error establishing a connection")
|
||||
} finally {
|
||||
this.testing = false
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
try {
|
||||
this.errors = null
|
||||
this.connectionError = null
|
||||
},
|
||||
async remove(config) {
|
||||
if (this.config === config) {
|
||||
this.config = new SavedConnection()
|
||||
}
|
||||
await this.$store.dispatch('pinnedConnections/remove', config)
|
||||
await this.$store.dispatch('data/connections/remove', config)
|
||||
this.$noty.success(`${config.name} deleted`)
|
||||
},
|
||||
async duplicate(config) {
|
||||
// Duplicates ES 6 class of the connection, without any reference to the old one.
|
||||
const duplicateConfig = await this.$store.dispatch('data/connections/clone', config)
|
||||
duplicateConfig.name = 'Copy of ' + duplicateConfig.name
|
||||
|
||||
try {
|
||||
const id = await this.$store.dispatch('data/connections/save', duplicateConfig)
|
||||
this.$noty.success(`The connection was successfully duplicated!`)
|
||||
this.config = this.connections.find((c) => c.id === id) || this.config
|
||||
} catch (ex) {
|
||||
this.$noty.error(`Could not duplicate Connection: ${ex.message}`)
|
||||
}
|
||||
|
||||
},
|
||||
async submit() {
|
||||
this.connectionError = null
|
||||
try {
|
||||
await this.$store.dispatch('connect', this.config)
|
||||
} catch(ex) {
|
||||
this.connectionError = ex
|
||||
this.$noty.error("Error establishing a connection")
|
||||
log.error(ex)
|
||||
}
|
||||
},
|
||||
async handleConnect(config) {
|
||||
this.config = config
|
||||
await this.submit()
|
||||
},
|
||||
async testConnection(){
|
||||
|
||||
try {
|
||||
this.testing = true
|
||||
this.connectionError = null
|
||||
await this.$store.dispatch('test', this.config)
|
||||
this.$noty.success("Connection looks good!")
|
||||
return true
|
||||
} catch(ex) {
|
||||
this.connectionError = ex
|
||||
this.$noty.error("Error establishing a connection")
|
||||
} finally {
|
||||
this.testing = false
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
try {
|
||||
this.errors = null
|
||||
this.connectionError = null
|
||||
if (!this.config.name) {
|
||||
throw new Error("Name is required")
|
||||
}
|
||||
await this.$store.dispatch('data/connections/save', this.config)
|
||||
this.$noty.success("Connection Saved")
|
||||
} catch (ex) {
|
||||
console.error(ex)
|
||||
this.errors = [ex.message]
|
||||
this.$noty.error("Could not save connection information")
|
||||
}
|
||||
},
|
||||
handleErrorMessage(message){
|
||||
if (message){
|
||||
this.errors = [message]
|
||||
this.$noty.error("Could not parse connection URL.")
|
||||
}else{
|
||||
this.errors = null
|
||||
if (!this.config.name) {
|
||||
throw new Error("Name is required")
|
||||
}
|
||||
await this.$store.dispatch('data/connections/save', this.config)
|
||||
this.$noty.success("Connection Saved")
|
||||
} catch (ex) {
|
||||
console.error(ex)
|
||||
this.errors = [ex.message]
|
||||
this.$noty.error("Could not save connection information")
|
||||
}
|
||||
},
|
||||
})
|
||||
handleErrorMessage(message) {
|
||||
if (message) {
|
||||
this.errors = [message]
|
||||
this.$noty.error("Could not parse connection URL.")
|
||||
} else {
|
||||
this.errors = null
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
<style></style>
|
||||
|
||||
69
apps/studio/src/components/connection/BigQueryForm.vue
Normal file
69
apps/studio/src/components/connection/BigQueryForm.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="with-connection-type">
|
||||
<div class="form-group">
|
||||
<label for="Project Id">ProjectId</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
v-model="config.bigQueryOptions.projectId"
|
||||
>
|
||||
</div>
|
||||
<div class="advanced-connection-settings">
|
||||
<h4
|
||||
class="advanced-heading flex"
|
||||
:class="{ enabled: iamAuthenticationEnabled }"
|
||||
>
|
||||
<span class="expand">IAM Authentication</span>
|
||||
<x-switch
|
||||
@click.prevent="toggleIAMAuthentication"
|
||||
:toggled="iamAuthenticationEnabled"
|
||||
/>
|
||||
</h4>
|
||||
<div
|
||||
class="advanced-body"
|
||||
v-show="iamAuthenticationEnabled"
|
||||
>
|
||||
<div class="row gutter">
|
||||
<div class="alert alert-info">
|
||||
<i class="material-icons-outlined">info</i>
|
||||
<div>
|
||||
Create a service account key. <a
|
||||
href="https://cloud.google.com/iam/docs/keys-create-delete#creating"
|
||||
>Read
|
||||
More</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="KeyFilename">
|
||||
Key file
|
||||
</label>
|
||||
<file-picker v-model="config.bigQueryOptions.keyFilename" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<common-server-inputs :config="config" />
|
||||
<common-advanced :config="config" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import FilePicker from '@/components/common/form/FilePicker'
|
||||
import CommonAdvanced from './CommonAdvanced'
|
||||
import CommonServerInputs from './CommonServerInputs'
|
||||
|
||||
export default {
|
||||
components: { CommonAdvanced, CommonServerInputs, FilePicker },
|
||||
data() {
|
||||
return {
|
||||
iamAuthenticationEnabled: this.config.bigQueryOptions?.iamAuthenticationEnabled || false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleIAMAuthentication() {
|
||||
this.config.bigQueryOptions.iamAuthenticationEnabled = this.iamAuthenticationEnabled = !this.iamAuthenticationEnabled
|
||||
}
|
||||
},
|
||||
props: ['config'],
|
||||
}
|
||||
</script>
|
||||
@@ -36,7 +36,8 @@ export default {
|
||||
sslRejectUnauthorized: config.sslRejectUnauthorized,
|
||||
trustServerCertificate: config.trustServerCertificate,
|
||||
options: config.options,
|
||||
redshiftOptions: config.redshiftOptions
|
||||
redshiftOptions: config.redshiftOptions,
|
||||
bigQueryOptions: config.bigQueryOptions,
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import createLogger from '../logger';
|
||||
import { SSHConnection } from '@/vendor/node-ssh-forward/index';
|
||||
import { SupportedFeatures, FilterOptions, TableOrView, Routine, TableColumn, SchemaFilterOptions, DatabaseFilterOptions, TableChanges, TableUpdateResult, OrderBy, TableFilter, TableResult, StreamResults, CancelableQuery, ExtendedTableColumn, PrimaryKeyColumn, TableProperties, TableIndex, TableTrigger, TableInsert, TablePartition } from './models';
|
||||
import { AlterPartitionsSpec, AlterTableSpec, IndexAlterations, RelationAlterations } from '@shared/lib/dialects/models';
|
||||
import type { RedshiftOptions } from '@/common/appdb/models/saved_connection';
|
||||
import type { RedshiftOptions, BigQueryOptions } from '@/common/appdb/models/saved_connection';
|
||||
|
||||
const logger = createLogger('db');
|
||||
|
||||
@@ -128,6 +128,7 @@ export interface IDbConnectionServerConfig {
|
||||
trustServerCertificate?: boolean
|
||||
options?: any
|
||||
redshiftOptions?: RedshiftOptions
|
||||
bigQueryOptions?: BigQueryOptions
|
||||
}
|
||||
|
||||
export interface IDbSshTunnel {
|
||||
@@ -513,7 +514,7 @@ function getViewCreateScript(server: IDbConnectionServer, database: IDbConnectio
|
||||
function getMaterializedViewCreateScript(server: IDbConnectionServer, database: IDbConnectionDatabase, view: string /* , schema */) {
|
||||
checkIsConnected(server , database);
|
||||
|
||||
if(typeof database.connection?.getMaterializedViewCreateScript !== 'function') {
|
||||
if (typeof database.connection?.getMaterializedViewCreateScript !== 'function') {
|
||||
return null;
|
||||
} else {
|
||||
return database.connection?.getMaterializedViewCreateScript(view);
|
||||
|
||||
290
apps/studio/src/lib/db/clients/bigquery.js
Normal file
290
apps/studio/src/lib/db/clients/bigquery.js
Normal file
@@ -0,0 +1,290 @@
|
||||
import { errors } from '../../errors';
|
||||
import * as bq from '@google-cloud/bigquery';
|
||||
import { DatabaseClient, IDbConnectionServerConfig, DatabaseElement } from '../client'
|
||||
import { FilterOptions, OrderBy, TableFilter, TableUpdateResult, TableResult, Routine, TableChanges, TableInsert, TableUpdate, TableDelete, DatabaseFilterOptions, SchemaFilterOptions, NgQueryResult, StreamResults, ExtendedTableColumn, PrimaryKeyColumn, TableIndex, IndexedColumn, } from "../models";
|
||||
|
||||
|
||||
import rawLog from 'electron-log'
|
||||
import { createCancelablePromise } from '@/common/utils';
|
||||
import { BigQueryOptions } from '@/common/appdb/models/saved_connection';
|
||||
import { table, time } from 'console';
|
||||
import { data } from 'jquery';
|
||||
import { buildDeleteQueries, buildInsertQueries, buildUpdateQueries, buildInsertQuery, genericSelectTop, buildSelectTopQuery, escapeString, joinQueries, escapeLiteral, applyChangesSql } from './utils';
|
||||
const log = rawLog.scope('bigquery')
|
||||
const logger = () => log
|
||||
|
||||
/**
|
||||
* To keep compatibility with the other clients we treat dataset as database.
|
||||
*/
|
||||
export default async function (server, database) {
|
||||
let client = null
|
||||
logger().debug(`bigquery client creating `, server, ` database:`, database, ` config:`, server.config)
|
||||
const dbConfig = configDatabase(server, database)
|
||||
client = new bq.BigQuery(dbConfig)
|
||||
logger().debug('bigquery client created ', client)
|
||||
|
||||
// light solution to test connection with with a simple query
|
||||
const results = await executeQuery(client, { query: 'SELECT CURRENT_TIMESTAMP()' });
|
||||
logger().debug("bigquery client connected")
|
||||
|
||||
return {
|
||||
supportedFeatures: () => ({ customRoutines: false, comments: false, properties: true, partitions: false, editPartitions: false }),
|
||||
disconnect: () => disconnect(client),
|
||||
listTables: (db) => listTables(client, db),
|
||||
listViews: (filter) => listViews(client, database.database, filter),
|
||||
listMaterializedViews: () => Promise.resolve([]),
|
||||
listRoutines: () => Promise.resolve([]),
|
||||
listTableColumns: (db, table) => listTableColumns(client, db, table),
|
||||
getTableLength: (table) => getTableLength(client, database.database, table),
|
||||
selectTop: (table, offset, limit, orderBy, filters, schema, selects) => selectTop(client, database.database, table, offset, limit, orderBy, filters, selects),
|
||||
getTableKeys: (db, table) => Promise.resolve([]),
|
||||
getPrimaryKeys: (db, table) => Promise.resolve([]),
|
||||
query: (queryText) => query(client, queryText),
|
||||
executeQuery: (queryText) => executeQuery(client, queryText),
|
||||
listDatabases: () => listDatasets(client),
|
||||
getTableProperties: (table) => getTableProperties(client, database.database, table),
|
||||
versionString: () => getVersionString(),
|
||||
// db creation
|
||||
// TODO: determine if bigquery has different charsets
|
||||
listCharsets: () => [],
|
||||
getDefaultCharset: () => null,
|
||||
listCollations: (charset) => [],
|
||||
createDatabase: (databaseName) => createDatabase(client, databaseName),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function configDatabase(server, database) {
|
||||
|
||||
const host = server.config.host
|
||||
const port = server.config.port
|
||||
|
||||
// For BigQuery Only -- IAM authentication and credential exchange
|
||||
const bigQueryOptions = server.config.bigQueryOptions
|
||||
const config = {}
|
||||
|
||||
config.projectId = bigQueryOptions.projectId || server.config.projectId
|
||||
if (server.config.client === 'bigquery' && bigQueryOptions?.iamAuthenticationEnabled) {
|
||||
config.keyFilename = bigQueryOptions.keyFilename
|
||||
}
|
||||
// For testing purposes
|
||||
if (host !== "" && port !== "") {
|
||||
config.apiEndpoint = "http://" + host + ":" + port
|
||||
logger().debug(`configDatabase host: ${host} port: ${port} setting apiEndpoint: ${config.apiEndpoint}`)
|
||||
} // use default otherwise
|
||||
|
||||
logger().debug("configDatabase config: ", config)
|
||||
return config
|
||||
}
|
||||
|
||||
|
||||
function query(client, queryText) {
|
||||
logger().debug('bigQuery query: ' + queryText)
|
||||
let job = null
|
||||
let canceling = false
|
||||
const cancelable = createCancelablePromise({
|
||||
...errors.CANCELED_BY_USER,
|
||||
sqlectronError: 'CANCELED_BY_USER',
|
||||
})
|
||||
|
||||
return {
|
||||
async execute() {
|
||||
// Get a query job first
|
||||
[job] = await client.createQueryJob({ query: queryText })
|
||||
logger().debug("created job: ", job.id)
|
||||
|
||||
try {
|
||||
logger().debug("wait for executeQuery job.id: ", job.id)
|
||||
const data = await Promise.race([
|
||||
cancelable.wait(),
|
||||
executeQuery(client, queryText, job),
|
||||
])
|
||||
return data
|
||||
} catch (err) {
|
||||
log.error('executeQuery error: ', err)
|
||||
throw err
|
||||
}
|
||||
},
|
||||
async cancel() {
|
||||
if (!job) {
|
||||
throw new Error('Query not ready to be canceled')
|
||||
}
|
||||
canceling = true
|
||||
try {
|
||||
const [jobCancelResponse] = await job.cancel()
|
||||
logger().debug("query jobCancelResponse: ", jobCancelResponse)
|
||||
cancelable.cancel()
|
||||
} catch (err) {
|
||||
canceling = false
|
||||
throw err
|
||||
} finally {
|
||||
canceling = false
|
||||
cancelable.discard()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getVersionString() {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
function parseRowData(data) {
|
||||
// BigQuery can return nested objects with custom types in the results
|
||||
// look for the value string property.
|
||||
// https://github.com/googleapis/nodejs-bigquery/blob/71dbed2140893677f7af254f5a7713a7f50bae92/src/bigquery.ts#L2191
|
||||
return data.map((row) => {
|
||||
const parsedRow = {}
|
||||
Object.keys(row).forEach((key) => {
|
||||
let strValue = row[key]
|
||||
if (strValue != null && (Object.prototype.hasOwnProperty.call(strValue, 'value'))) {
|
||||
strValue = row[key].value
|
||||
}
|
||||
parsedRow[key] = strValue
|
||||
})
|
||||
return parsedRow
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function parseRowQueryResult(data) {
|
||||
// Fallback in case the identifier could not reconize the command
|
||||
const isSelect = Array.isArray(data)
|
||||
const rows = parseRowData(data) || []
|
||||
const fields = Object.keys(rows[0] || {}).map((name) => ({ name, id: name }))
|
||||
logger().debug("parseRowQueryResult data length: ", data.length)
|
||||
|
||||
return {
|
||||
command: isSelect ? 'SELECT' : 'UNKNOWN',
|
||||
rows,
|
||||
fields: fields,
|
||||
rowCount: data && data.length,
|
||||
affectedRows: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function executeQuery(client, queries, job) {
|
||||
// Support passing a single query string and an object with params
|
||||
if (queries instanceof String) {
|
||||
queries = { query: queries }
|
||||
}
|
||||
if (!job) {
|
||||
[job] = await client.createQueryJob(queries)
|
||||
}
|
||||
|
||||
// Wait for the query to finish
|
||||
const results = await job.getQueryResults()
|
||||
return results.map(parseRowQueryResult)
|
||||
}
|
||||
|
||||
|
||||
export async function disconnect(client) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
|
||||
function ensureDbFullName(client, db) {
|
||||
if ((db.includes(`${client.projectId}.`)) || db.includes(`.${db}`)) {
|
||||
return db
|
||||
} else {
|
||||
return `${client.projectId}.${db}`
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function listTablesOrViews(client, db, type) {
|
||||
// Lists all tables or views in the dataset
|
||||
const [tables] = await client.dataset(db).getTables()
|
||||
var data = tables.map((table) => ({ name: table.id, entityType: table.metadata.type, metadata: table.metadata, table: table }))
|
||||
data = data.filter((table) => table.metadata.type === type)
|
||||
logger().debug(`listTablesAndViews for type:${type} data: `, data)
|
||||
return data
|
||||
}
|
||||
|
||||
export async function listTables(client, db) {
|
||||
// Lists all tables in the dataset
|
||||
const data = await listTablesOrViews(client, db, 'TABLE')
|
||||
return data
|
||||
}
|
||||
|
||||
|
||||
export async function listTableColumns(client, db, table) {
|
||||
// Lists all columns in a table
|
||||
const [metadata] = await client.dataset(db).table(table).getMetadata()
|
||||
const data = metadata.schema.fields.map((field) => ({ columnName: field.name, dataType: field.type }))
|
||||
return data
|
||||
}
|
||||
|
||||
|
||||
export async function getTableProperties(client, db, table) {
|
||||
logger().debug("getTableProperties: ", table)
|
||||
|
||||
const [
|
||||
length,
|
||||
indexes,
|
||||
triggers, // BigQuery has no triggers
|
||||
relations // BigQuery has no relations
|
||||
] = await Promise.all([
|
||||
getTableLength(client, db, table),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
])
|
||||
return {
|
||||
length, indexes, relations, triggers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function getTableLength(client, db, table) {
|
||||
// Returns the number of rows in the table
|
||||
const [metadata] = await client.dataset(db).table(table).getMetadata()
|
||||
return Number(metadata.numRows)
|
||||
}
|
||||
|
||||
|
||||
export async function listTableIndexes(client, db, table) {
|
||||
return []
|
||||
}
|
||||
|
||||
|
||||
export async function listDatasets(client) {
|
||||
// Lists all datasets in current GCP project.
|
||||
const [datasets] = await client.getDatasets()
|
||||
const data = datasets.map((dataset) => dataset.id)
|
||||
return data
|
||||
}
|
||||
|
||||
export async function selectTop(client, db, table, offset, limit, orderBy, filters, selects) {
|
||||
const columns = await listTableColumns(client, db, table)
|
||||
const bqTable = db + "." + table
|
||||
const queries = buildSelectTopQuery(bqTable, offset, limit, orderBy, filters, 'total', columns, selects)
|
||||
const queriesResult = await executeQuery(client, queries)
|
||||
const data = queriesResult[0]
|
||||
const rowCount = Number(data.rowCount)
|
||||
const fields = Object.keys(data.rows[0] || {})
|
||||
|
||||
const result = {
|
||||
totalRows: rowCount,
|
||||
result: data.rows,
|
||||
fields: { fields }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
export async function listViews(client, db, filter) {
|
||||
// Lists all views in the dataset
|
||||
const data = await listTablesOrViews(client, db, 'VIEW')
|
||||
return data
|
||||
}
|
||||
|
||||
export async function createDatabase(client, databaseName) {
|
||||
// Create a new dataset/database
|
||||
const options = {}
|
||||
const [dataset] = await client.createDataset(databaseName, options);
|
||||
logger().debug(`Dataset ${dataset.id} created.`);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import postgresql from './postgresql';
|
||||
import sqlserver from './sqlserver';
|
||||
import sqlite from './sqlite';
|
||||
import cassandra from './cassandra';
|
||||
import bigquery from './bigquery.js';
|
||||
|
||||
|
||||
export function findClient(key: string): Client | undefined {
|
||||
@@ -124,6 +125,21 @@ export const CLIENTS: ClientConfig[] = [
|
||||
'cancelQuery',
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'bigquery',
|
||||
name: 'BigQuery',
|
||||
defaultPort: 443,
|
||||
disabledFeatures: [
|
||||
'server:ssl',
|
||||
'server:socketPath',
|
||||
'server:user',
|
||||
'server:password',
|
||||
'server:schema',
|
||||
'server:domain',
|
||||
'server:ssh',
|
||||
'scriptCreateTable',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -135,5 +151,6 @@ export default {
|
||||
cassandra,
|
||||
redshift: postgresql,
|
||||
mariadb: mysql,
|
||||
cockroachdb: postgresql
|
||||
cockroachdb: postgresql,
|
||||
bigquery,
|
||||
};
|
||||
|
||||
13
apps/studio/src/migration/20230426_add_bigquery_options.js
Normal file
13
apps/studio/src/migration/20230426_add_bigquery_options.js
Normal file
@@ -0,0 +1,13 @@
|
||||
export default {
|
||||
name: "20230426-add-bigqqery_options",
|
||||
async run(runner) {
|
||||
const queries = [
|
||||
`ALTER TABLE saved_connection ADD COLUMN bigQueryOptions text not null default '{}'`,
|
||||
`ALTER TABLE used_connection ADD COLUMN bigQueryOptions text not null default '{}'`,
|
||||
];
|
||||
for (let i = 0; i < queries.length; i++) {
|
||||
const query = queries[i];
|
||||
await runner.query(query);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -44,6 +44,14 @@ export default {
|
||||
password: 'Example@1',
|
||||
defaultDatabase: 'sakila'
|
||||
},
|
||||
{
|
||||
name: "[DEV] Docker Bigquery",
|
||||
connectionType: 'bigquery',
|
||||
port: 9050,
|
||||
host: 'localhost',
|
||||
projectId: 'bks',
|
||||
defaultDatabase: 'world',
|
||||
},
|
||||
{
|
||||
name: "Beekeeper's Database",
|
||||
connectionType: "sqlite",
|
||||
|
||||
@@ -31,6 +31,7 @@ import createHiddenSchemas from './20220908_create_hidden_schemas'
|
||||
import redshiftOptions from './20220817_add_redshift_options'
|
||||
import connectionPins from './20230308_create_connection_pins'
|
||||
import fixKeymapType from './20230619_fix_keymap_type'
|
||||
import bigQueryOptions from './20230426_add_bigquery_options'
|
||||
|
||||
const logger = createLogger('migrations')()
|
||||
|
||||
@@ -45,7 +46,7 @@ const realMigrations = [
|
||||
addSc, sslFiles, sslReject, pinned, addSort,
|
||||
createCreds, workspaceScoping, workspace2, addTabs, scWorkspace, systemTheme,
|
||||
serverCerts, socketPath, connectionOptions, keepaliveInterval, redshiftOptions,
|
||||
createHiddenEntities, createHiddenSchemas, connectionPins, fixKeymapType
|
||||
createHiddenEntities, createHiddenSchemas, connectionPins, fixKeymapType, bigQueryOptions
|
||||
]
|
||||
|
||||
// fixtures require the models
|
||||
@@ -84,7 +85,7 @@ export default class {
|
||||
console.log("running migrations")
|
||||
const runner = this.connection.connection.createQueryRunner()
|
||||
await runner.query(setupSQL)
|
||||
for(let i = 0; i < migrations.length; i++){
|
||||
for(let i = 0; i < migrations.length; i++) {
|
||||
const migration = migrations[i]
|
||||
logger.debug(`Checking migration ${migration.name}`)
|
||||
if(migration.env && migration.env !== this.env) {
|
||||
|
||||
@@ -31,8 +31,13 @@
|
||||
"../../shared/src/**/*.ts",
|
||||
"../../shared/src/**/*.tsx",
|
||||
"../../shared/src/**/*.vue",
|
||||
"src/*.js",
|
||||
"src/**/*.js",
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules", "dist", "dist_electron"
|
||||
]
|
||||
],
|
||||
"sourceMapPathOverrides": {
|
||||
"src/*": "${webRoot}/apps/studio/src/*"
|
||||
},
|
||||
}
|
||||
|
||||
@@ -173,6 +173,7 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
configureWebpack: {
|
||||
devtool: 'source-map',
|
||||
plugins: [
|
||||
new webpack.IgnorePlugin(/pg-native/, /pg/),
|
||||
new webpack.IgnorePlugin(/kerberos/, /cassandra-driver/),
|
||||
|
||||
21
dev/docker_bigquery/data.sh
Executable file
21
dev/docker_bigquery/data.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
|
||||
# Install curl
|
||||
# apt update
|
||||
# apt install -y axel procps htop
|
||||
|
||||
# # Change directory to /work
|
||||
# cd /work
|
||||
|
||||
# # Download and install Google cloud sdk
|
||||
# export FILENAME=google-cloud-cli-430.0.0-linux-x86_64.tar.gz
|
||||
# [ ! -f $FILENAME ] && axel -k https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/$FILENAME
|
||||
# tar -xvzf $FILENAME
|
||||
# /work/google-cloud-sdk/install.sh -q
|
||||
# # Add gcloud to PATH
|
||||
# source /work/google-cloud-sdk/path.bash.inc
|
||||
# echo "source /work/google-cloud-sdk/path.bash.inc" >> ~/.bashrc
|
||||
|
||||
# Start BigQuery emulator
|
||||
/bin/bigquery-emulator --log-level=debug --project=bks --data-from-yaml=/data/world.yaml
|
||||
28004
dev/docker_bigquery/world.yaml
Normal file
28004
dev/docker_bigquery/world.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@ volumes:
|
||||
psql13:
|
||||
mariadb:
|
||||
cockroachdb:
|
||||
bigquery:
|
||||
|
||||
services:
|
||||
|
||||
@@ -101,5 +102,12 @@ services:
|
||||
ports:
|
||||
- 26257:26257
|
||||
command: start-single-node --insecure
|
||||
|
||||
|
||||
bigquery:
|
||||
image: ghcr.io/goccy/bigquery-emulator:latest
|
||||
volumes:
|
||||
- ./dev/docker_bigquery:/data
|
||||
- ./dev/docker_bigquery:/docker_init
|
||||
ports:
|
||||
- 9050:9050
|
||||
- 9060:9060
|
||||
entrypoint: sh -c 'chmod +x /docker_init/data.sh; /docker_init/data.sh'
|
||||
|
||||
11
package.json
11
package.json
@@ -24,16 +24,19 @@
|
||||
"all:lint": "yarn workspace beekeeper-studio lint && yarn workspace sqltools lint && npx eslint 'shared/**' --fix"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@google-cloud/bigquery": "^6.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||
"@typescript-eslint/parser": "^4.18.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.2",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"npm-run-all": "^4.1.5"
|
||||
"npm-run-all": "^4.1.5",
|
||||
"vue-cli-plugin-electron-builder": "latest",
|
||||
"log-timestamp": "latest"
|
||||
},
|
||||
"resolutions": {
|
||||
"nan": "2.17.0",
|
||||
"node-abi": "^3.34.0",
|
||||
"cpu-features": "./.yarn/packages/empty-package"
|
||||
"nan": "2.17.0",
|
||||
"node-abi": "^3.34.0",
|
||||
"cpu-features": "./.yarn/packages/empty-package"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
"dist_electron",
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
229
yarn.lock
229
yarn.lock
@@ -1816,6 +1816,61 @@
|
||||
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
|
||||
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
|
||||
|
||||
"@google-cloud/bigquery@^6.2.0":
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@google-cloud/bigquery/-/bigquery-6.2.1.tgz#29907fa6050b457de18c5ee5fd32b7c6207bd9f8"
|
||||
integrity sha512-C/tcM3jQ3RU8pKHHxj702ouIfGZ9GAQ5U+ZpvS/o4B3yWtqmnG3TITL5oRnzDjEKeMTNu5C6z3/nFtix3GKlqA==
|
||||
dependencies:
|
||||
"@google-cloud/common" "^4.0.0"
|
||||
"@google-cloud/paginator" "^4.0.0"
|
||||
"@google-cloud/precise-date" "^3.0.1"
|
||||
"@google-cloud/promisify" "^3.0.0"
|
||||
arrify "^2.0.1"
|
||||
big.js "^6.0.0"
|
||||
duplexify "^4.0.0"
|
||||
extend "^3.0.2"
|
||||
is "^3.3.0"
|
||||
stream-events "^1.0.5"
|
||||
uuid "^9.0.0"
|
||||
|
||||
"@google-cloud/common@^4.0.0":
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@google-cloud/common/-/common-4.0.3.tgz#d4324ac83087385d727593f7e1b6d81ee66442cf"
|
||||
integrity sha512-fUoMo5b8iAKbrYpneIRV3z95AlxVJPrjpevxs4SKoclngWZvTXBSGpNisF5+x5m+oNGve7jfB1e6vNBZBUs7Fw==
|
||||
dependencies:
|
||||
"@google-cloud/projectify" "^3.0.0"
|
||||
"@google-cloud/promisify" "^3.0.0"
|
||||
arrify "^2.0.1"
|
||||
duplexify "^4.1.1"
|
||||
ent "^2.2.0"
|
||||
extend "^3.0.2"
|
||||
google-auth-library "^8.0.2"
|
||||
retry-request "^5.0.0"
|
||||
teeny-request "^8.0.0"
|
||||
|
||||
"@google-cloud/paginator@^4.0.0":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@google-cloud/paginator/-/paginator-4.0.1.tgz#5fb8793d4f84d18c50a6f2fad3dadab8d2c533ef"
|
||||
integrity sha512-6G1ui6bWhNyHjmbYwavdN7mpVPRBtyDg/bfqBTAlwr413On2TnFNfDxc9UhTJctkgoCDgQXEKiRPLPR9USlkbQ==
|
||||
dependencies:
|
||||
arrify "^2.0.0"
|
||||
extend "^3.0.2"
|
||||
|
||||
"@google-cloud/precise-date@^3.0.1":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@google-cloud/precise-date/-/precise-date-3.0.1.tgz#1e6659a14af662442037b8f4d20dbc82bf1a78bd"
|
||||
integrity sha512-crK2rgNFfvLoSgcKJY7ZBOLW91IimVNmPfi1CL+kMTf78pTJYd29XqEVedAeBu4DwCJc0EDIp1MpctLgoPq+Uw==
|
||||
|
||||
"@google-cloud/projectify@^3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@google-cloud/projectify/-/projectify-3.0.0.tgz#302b25f55f674854dce65c2532d98919b118a408"
|
||||
integrity sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA==
|
||||
|
||||
"@google-cloud/promisify@^3.0.0":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@google-cloud/promisify/-/promisify-3.0.1.tgz#8d724fb280f47d1ff99953aee0c1669b25238c2e"
|
||||
integrity sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==
|
||||
|
||||
"@hapi/address@2.x.x":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
|
||||
@@ -3924,6 +3979,11 @@ arrify@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
|
||||
integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==
|
||||
|
||||
arrify@^2.0.0, arrify@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
|
||||
integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
|
||||
|
||||
asar@^3.0.3:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/asar/-/asar-3.2.0.tgz#e6edb5edd6f627ebef04db62f771c61bea9c1221"
|
||||
@@ -4278,7 +4338,7 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1:
|
||||
base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
@@ -4341,6 +4401,16 @@ big.js@^5.2.2:
|
||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
|
||||
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
|
||||
|
||||
big.js@^6.0.0:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-6.2.1.tgz#7205ce763efb17c2e41f26f121c420c6a7c2744f"
|
||||
integrity sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==
|
||||
|
||||
bignumber.js@^9.0.0:
|
||||
version "9.1.1"
|
||||
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6"
|
||||
integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==
|
||||
|
||||
binary-extensions@^1.0.0:
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
|
||||
@@ -6461,7 +6531,7 @@ duplexify@^3.4.2, duplexify@^3.6.0:
|
||||
readable-stream "^2.0.0"
|
||||
stream-shift "^1.0.0"
|
||||
|
||||
duplexify@^4.1.1:
|
||||
duplexify@^4.0.0, duplexify@^4.1.1:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0"
|
||||
integrity sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==
|
||||
@@ -6484,7 +6554,7 @@ ecc-jsbn@~0.1.1:
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
|
||||
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
|
||||
@@ -6685,6 +6755,11 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.5.0:
|
||||
memory-fs "^0.5.0"
|
||||
tapable "^1.0.0"
|
||||
|
||||
ent@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
|
||||
integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==
|
||||
|
||||
entities@2.2.0, entities@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
|
||||
@@ -7315,7 +7390,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
|
||||
assign-symbols "^1.0.0"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
extend@~3.0.2:
|
||||
extend@^3.0.2, extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
@@ -7408,6 +7483,11 @@ fast-levenshtein@~2.0.6:
|
||||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
|
||||
|
||||
fast-text-encoding@^1.0.0:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz#0aa25f7f638222e3396d72bf936afcf1d42d6867"
|
||||
integrity sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==
|
||||
|
||||
fast-xml-parser@3.19.0:
|
||||
version "3.19.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz#cb637ec3f3999f51406dd8ff0e6fc4d83e520d01"
|
||||
@@ -7848,6 +7928,16 @@ gauge@~2.7.3:
|
||||
strip-ansi "^3.0.1"
|
||||
wide-align "^1.1.0"
|
||||
|
||||
gaxios@^5.0.0, gaxios@^5.0.1:
|
||||
version "5.1.3"
|
||||
resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-5.1.3.tgz#f7fa92da0fe197c846441e5ead2573d4979e9013"
|
||||
integrity sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==
|
||||
dependencies:
|
||||
extend "^3.0.2"
|
||||
https-proxy-agent "^5.0.0"
|
||||
is-stream "^2.0.0"
|
||||
node-fetch "^2.6.9"
|
||||
|
||||
gaze@^1.0.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
|
||||
@@ -7855,6 +7945,14 @@ gaze@^1.0.0:
|
||||
dependencies:
|
||||
globule "^1.0.0"
|
||||
|
||||
gcp-metadata@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-5.3.0.tgz#6f45eb473d0cb47d15001476b48b663744d25408"
|
||||
integrity sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==
|
||||
dependencies:
|
||||
gaxios "^5.0.0"
|
||||
json-bigint "^1.0.0"
|
||||
|
||||
generate-function@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f"
|
||||
@@ -8138,6 +8236,28 @@ good-listener@^1.2.2:
|
||||
dependencies:
|
||||
delegate "^3.1.2"
|
||||
|
||||
google-auth-library@^8.0.2:
|
||||
version "8.9.0"
|
||||
resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-8.9.0.tgz#15a271eb2ec35d43b81deb72211bd61b1ef14dd0"
|
||||
integrity sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==
|
||||
dependencies:
|
||||
arrify "^2.0.0"
|
||||
base64-js "^1.3.0"
|
||||
ecdsa-sig-formatter "^1.0.11"
|
||||
fast-text-encoding "^1.0.0"
|
||||
gaxios "^5.0.0"
|
||||
gcp-metadata "^5.3.0"
|
||||
gtoken "^6.1.0"
|
||||
jws "^4.0.0"
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
google-p12-pem@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-4.0.1.tgz#82841798253c65b7dc2a4e5fe9df141db670172a"
|
||||
integrity sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==
|
||||
dependencies:
|
||||
node-forge "^1.3.1"
|
||||
|
||||
got@^9.6.0:
|
||||
version "9.6.0"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
|
||||
@@ -8185,6 +8305,15 @@ growly@^1.3.0:
|
||||
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
|
||||
integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==
|
||||
|
||||
gtoken@^6.1.0:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-6.1.2.tgz#aeb7bdb019ff4c3ba3ac100bbe7b6e74dce0e8bc"
|
||||
integrity sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==
|
||||
dependencies:
|
||||
gaxios "^5.0.1"
|
||||
google-p12-pem "^4.0.0"
|
||||
jws "^4.0.0"
|
||||
|
||||
gzip-size@^5.0.0:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274"
|
||||
@@ -9249,6 +9378,11 @@ is-yarn-global@^0.3.0:
|
||||
resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
|
||||
integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
|
||||
|
||||
is@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/is/-/is-3.3.0.tgz#61cff6dd3c4193db94a3d62582072b44e5645d79"
|
||||
integrity sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==
|
||||
|
||||
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
@@ -9909,6 +10043,13 @@ jsesc@~0.5.0:
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
|
||||
integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==
|
||||
|
||||
json-bigint@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1"
|
||||
integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==
|
||||
dependencies:
|
||||
bignumber.js "^9.0.0"
|
||||
|
||||
json-buffer@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
|
||||
@@ -10423,6 +10564,11 @@ lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.1
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
log-prefix@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/log-prefix/-/log-prefix-0.1.1.tgz#3ec492138c8044c9f9732298492dca87850cac90"
|
||||
integrity sha512-aP1Lst8OCdZKATqzXDN0JBissNVZuiKLyo6hOXDBxaQ1jHDsaxh2J1i5Pp0zMy6ayTKDWfUlLMXyLaQe1PJ48g==
|
||||
|
||||
log-symbols@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
|
||||
@@ -10430,6 +10576,13 @@ log-symbols@^2.2.0:
|
||||
dependencies:
|
||||
chalk "^2.0.1"
|
||||
|
||||
log-timestamp@latest:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/log-timestamp/-/log-timestamp-0.3.0.tgz#2e10f1f0db872674ef3ecf53d6a312840acae45f"
|
||||
integrity sha512-luRz6soxijd1aJh0GkLXFjKABihxthvTfWTzu3XhCgg5EivG2bsTpSd63QFbUgS+/KmFtL+0RfSpeaD2QvOV8Q==
|
||||
dependencies:
|
||||
log-prefix "0.1.1"
|
||||
|
||||
loglevel@^1.6.8:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114"
|
||||
@@ -11172,11 +11325,23 @@ node-cache@^4.1.1:
|
||||
clone "2.x"
|
||||
lodash "^4.17.15"
|
||||
|
||||
node-fetch@^2.6.1, node-fetch@^2.6.9:
|
||||
version "2.6.12"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba"
|
||||
integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-forge@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
|
||||
integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==
|
||||
|
||||
node-forge@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"
|
||||
integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==
|
||||
|
||||
node-gyp@^7.1.0:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae"
|
||||
@@ -13247,6 +13412,14 @@ ret@~0.1.10:
|
||||
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
||||
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
|
||||
|
||||
retry-request@^5.0.0:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/retry-request/-/retry-request-5.0.2.tgz#143d85f90c755af407fcc46b7166a4ba520e44da"
|
||||
integrity sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
extend "^3.0.2"
|
||||
|
||||
retry@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
|
||||
@@ -14178,6 +14351,13 @@ stream-each@^1.1.0:
|
||||
end-of-stream "^1.1.0"
|
||||
stream-shift "^1.0.0"
|
||||
|
||||
stream-events@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5"
|
||||
integrity sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==
|
||||
dependencies:
|
||||
stubs "^3.0.0"
|
||||
|
||||
stream-http@^2.7.2:
|
||||
version "2.8.3"
|
||||
resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc"
|
||||
@@ -14366,6 +14546,11 @@ strip-json-comments@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
||||
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
||||
|
||||
stubs@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b"
|
||||
integrity sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==
|
||||
|
||||
stylehacks@^4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5"
|
||||
@@ -14552,6 +14737,17 @@ tedious@^14.0.0:
|
||||
punycode "^2.1.0"
|
||||
sprintf-js "^1.1.2"
|
||||
|
||||
teeny-request@^8.0.0:
|
||||
version "8.0.3"
|
||||
resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-8.0.3.tgz#5cb9c471ef5e59f2fca8280dc3c5909595e6ca24"
|
||||
integrity sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==
|
||||
dependencies:
|
||||
http-proxy-agent "^5.0.0"
|
||||
https-proxy-agent "^5.0.0"
|
||||
node-fetch "^2.6.1"
|
||||
stream-events "^1.0.5"
|
||||
uuid "^9.0.0"
|
||||
|
||||
temp-file@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/temp-file/-/temp-file-3.4.0.tgz#766ea28911c683996c248ef1a20eea04d51652c7"
|
||||
@@ -14848,6 +15044,11 @@ tr46@^1.0.1:
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
tr46@~0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||
|
||||
trim-newlines@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
|
||||
@@ -15438,6 +15639,11 @@ uuid@^8.3.0, uuid@^8.3.2:
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
uuid@^9.0.0:
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
|
||||
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
|
||||
|
||||
v-hotkey@^0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/v-hotkey/-/v-hotkey-0.8.0.tgz#134d64b30a3eeeb53bcb00eba81fdf74e21a032a"
|
||||
@@ -15506,7 +15712,7 @@ vue-class-component@^7.1.0, vue-class-component@^7.2.3:
|
||||
resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-7.2.6.tgz#8471e037b8e4762f5a464686e19e5afc708502e4"
|
||||
integrity sha512-+eaQXVrAm/LldalI272PpDe3+i4mPis0ORiMYxF6Ae4hyuCh15W8Idet7wPUEs4N4YptgFHGys4UrgNQOMyO6w==
|
||||
|
||||
vue-cli-plugin-electron-builder@~2.1.1:
|
||||
vue-cli-plugin-electron-builder@latest, vue-cli-plugin-electron-builder@~2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-cli-plugin-electron-builder/-/vue-cli-plugin-electron-builder-2.1.1.tgz#de8bed25b32e73e28dd08061dd2a3c6bfff73227"
|
||||
integrity sha512-ZrxFZ2uxgpwyFUE8LtguYqaTzSfZ1osME1uFlIj/Iz7GtLrATqs23n/BkKEpyEf5nYNAylzIM8ykGAfH/0QdmA==
|
||||
@@ -15802,6 +16008,11 @@ wcwidth@^1.0.1:
|
||||
dependencies:
|
||||
defaults "^1.0.3"
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
|
||||
|
||||
webidl-conversions@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||
@@ -15984,6 +16195,14 @@ whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0:
|
||||
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
|
||||
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
|
||||
|
||||
whatwg-url@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
|
||||
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
|
||||
dependencies:
|
||||
tr46 "~0.0.3"
|
||||
webidl-conversions "^3.0.0"
|
||||
|
||||
whatwg-url@^6.4.1:
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8"
|
||||
|
||||
Reference in New Issue
Block a user