diff --git a/src/sql/base/common/event.ts b/src/sql/base/common/event.ts index c42488a4e5..89235db8c5 100644 --- a/src/sql/base/common/event.ts +++ b/src/sql/base/common/event.ts @@ -5,6 +5,7 @@ 'use strict'; import { Emitter, Event } from 'vs/base/common/event'; +import { IDisposable } from 'vs/base/common/lifecycle'; /** * Implementation of vs/base/common/event/echo that is clearable @@ -37,3 +38,52 @@ export function echo(event: Event, nextTick = false, buffer: T[] = []): { clear }; } + +/** + * Implementation of vs/base/common/event/debounceEvent that is clearable + */ +export function debounceEvent(event: Event, merger: (last: T, event: T) => T, delay?: number, leading?: boolean): { clear: () => void; event: Event }; +export function debounceEvent(event: Event, merger: (last: O, event: I) => O, delay?: number, leading?: boolean): { clear: () => void; event: Event }; +export function debounceEvent(event: Event, merger: (last: O, event: I) => O, delay: number = 100, leading = false): { clear: () => void; event: Event } { + + let subscription: IDisposable; + let output: O = undefined; + let handle: any = undefined; + let numDebouncedCalls = 0; + + const clear = () => output = undefined; + + const emitter = new Emitter({ + onFirstListenerAdd() { + subscription = event(cur => { + numDebouncedCalls++; + output = merger(output, cur); + + if (leading && !handle) { + emitter.fire(output); + } + + clearTimeout(handle); + handle = setTimeout(() => { + let _output = output; + output = undefined; + handle = undefined; + if (!leading || numDebouncedCalls > 1) { + emitter.fire(_output); + } + + numDebouncedCalls = 0; + }, delay); + }); + }, + onLastListenerRemove() { + subscription.dispose(); + } + }); + + return { + event: emitter.event, + clear + }; +} + diff --git a/src/sql/parts/query/execution/queryRunner.ts b/src/sql/parts/query/execution/queryRunner.ts index b7e063a042..2c6fc45c8e 100644 --- a/src/sql/parts/query/execution/queryRunner.ts +++ b/src/sql/parts/query/execution/queryRunner.ts @@ -12,7 +12,7 @@ import * as WorkbenchUtils from 'sql/workbench/common/sqlWorkbenchUtils'; import { IQueryManagementService } from 'sql/parts/query/common/queryManagement'; import * as Utils from 'sql/parts/connection/common/utils'; import { SaveFormat } from 'sql/parts/grid/common/interfaces'; -import { echo } from 'sql/base/common/event'; +import { echo, debounceEvent } from 'sql/base/common/event'; import Severity from 'vs/base/common/severity'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; @@ -22,9 +22,10 @@ import * as types from 'vs/base/common/types'; import { EventEmitter } from 'sql/base/common/eventEmitter'; import { IDisposable } from 'vs/base/common/lifecycle'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { Emitter, debounceEvent, Event } from 'vs/base/common/event'; +import { Emitter, Event } from 'vs/base/common/event'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ResultSerializer } from 'sql/parts/query/common/resultSerializer'; +import { TPromise } from 'vs/base/common/winjs.base'; export interface IEditSessionReadyEvent { ownerUri: string; @@ -73,25 +74,27 @@ export default class QueryRunner { public get isQueryPlan(): boolean { return this._isQueryPlan; } private _onMessage = new Emitter(); - private _echoedMessages = echo(debounceEvent(this._onMessage.event, (l, e) => { + private _debouncedMessage = debounceEvent(this._onMessage.event, (l, e) => { // on first run if (types.isUndefinedOrNull(l)) { return [e]; } else { return l.concat(e); } - })); + }); + private _echoedMessages = echo(this._debouncedMessage.event); public readonly onMessage = this._echoedMessages.event; private _onResultSet = new Emitter(); - private _echoedResultSet = echo(debounceEvent(this._onResultSet.event, (l, e) => { + private _debouncedResultSet = debounceEvent(this._onResultSet.event, (l, e) => { // on first run if (types.isUndefinedOrNull(l)) { return [e]; } else { return l.concat(e); } - })); + }); + private _echoedResultSet = echo(this._debouncedResultSet.event); public readonly onResultSet = this._echoedResultSet.event; private _onQueryStart = new Emitter(); @@ -171,8 +174,13 @@ export default class QueryRunner { private doRunQuery(input: string, runCurrentStatement: boolean, runOptions?: sqlops.ExecutionPlanOptions): Thenable; private doRunQuery(input: sqlops.ISelectionData, runCurrentStatement: boolean, runOptions?: sqlops.ExecutionPlanOptions): Thenable; private doRunQuery(input, runCurrentStatement: boolean, runOptions?: sqlops.ExecutionPlanOptions): Thenable { + if (this.isExecuting) { + return TPromise.as(undefined); + } this._echoedMessages.clear(); this._echoedResultSet.clear(); + this._debouncedMessage.clear(); + this._debouncedResultSet.clear(); let ownerUri = this.uri; this._batchSets = []; this._hasCompleted = false;