SQL Operations Studio Public Preview 1 (0.23) release source code

This commit is contained in:
Karl Burtram
2017-11-09 14:30:27 -08:00
parent b88ecb8d93
commit 3cdac41339
8829 changed files with 759707 additions and 286 deletions

View File

@@ -0,0 +1,334 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { Schemas } from 'vs/base/common/network';
import { IDisposable } from 'vs/base/common/lifecycle';
import { isEmptyObject } from 'vs/base/common/types';
import URI from 'vs/base/common/uri';
import Event, { Emitter, debounceEvent } from 'vs/base/common/event';
import Severity from 'vs/base/common/severity';
import { IMarkerService, IMarkerData, IResourceMarker, IMarker, MarkerStatistics } from './markers';
interface MapMap<V> {
[key: string]: { [key: string]: V };
}
namespace MapMap {
export function get<V>(map: MapMap<V>, key1: string, key2: string): V {
if (map[key1]) {
return map[key1][key2];
}
return undefined;
}
export function set<V>(map: MapMap<V>, key1: string, key2: string, value: V): void {
if (!map[key1]) {
map[key1] = Object.create(null);
}
map[key1][key2] = value;
}
export function remove(map: MapMap<any>, key1: string, key2: string): boolean {
if (map[key1] && map[key1][key2]) {
delete map[key1][key2];
if (isEmptyObject(map[key1])) {
delete map[key1];
}
return true;
}
return false;
}
}
class MarkerStats implements MarkerStatistics {
errors: number = 0;
infos: number = 0;
warnings: number = 0;
unknowns: number = 0;
private _data: { [resource: string]: MarkerStatistics } = Object.create(null);
private _service: IMarkerService;
private _subscription: IDisposable;
constructor(service: IMarkerService) {
this._service = service;
this._subscription = service.onMarkerChanged(this._update, this);
}
dispose(): void {
this._subscription.dispose();
this._data = undefined;
}
private _update(resources: URI[]): void {
for (const resource of resources) {
const key = resource.toString();
const oldStats = this._data[key];
if (oldStats) {
this._substract(oldStats);
}
const newStats = this._resourceStats(resource);
this._add(newStats);
this._data[key] = newStats;
}
}
private _resourceStats(resource: URI): MarkerStatistics {
const result: MarkerStatistics = { errors: 0, warnings: 0, infos: 0, unknowns: 0 };
// TODO this is a hack
if (resource.scheme === Schemas.inMemory || resource.scheme === Schemas.walkThrough || resource.scheme === Schemas.walkThroughSnippet) {
return result;
}
for (const { severity } of this._service.read({ resource })) {
if (severity === Severity.Error) {
result.errors += 1;
} else if (severity === Severity.Warning) {
result.warnings += 1;
} else if (severity === Severity.Info) {
result.infos += 1;
} else {
result.unknowns += 1;
}
}
return result;
}
private _substract(op: MarkerStatistics) {
this.errors -= op.errors;
this.warnings -= op.warnings;
this.infos -= op.infos;
this.unknowns -= op.unknowns;
}
private _add(op: MarkerStatistics) {
this.errors += op.errors;
this.warnings += op.warnings;
this.infos += op.infos;
this.unknowns += op.unknowns;
}
}
export class MarkerService implements IMarkerService {
_serviceBrand: any;
private _onMarkerChanged = new Emitter<URI[]>();
private _onMarkerChangedEvent: Event<URI[]> = debounceEvent(this._onMarkerChanged.event, MarkerService._debouncer, 0);
private _byResource: MapMap<IMarker[]> = Object.create(null);
private _byOwner: MapMap<IMarker[]> = Object.create(null);
private _stats: MarkerStats;
constructor() {
this._stats = new MarkerStats(this);
}
dispose(): void {
this._stats.dispose();
}
get onMarkerChanged(): Event<URI[]> {
return this._onMarkerChangedEvent;
}
getStatistics(): MarkerStatistics {
return this._stats;
}
remove(owner: string, resources: URI[]): void {
if (!isFalsyOrEmpty(resources)) {
for (const resource of resources) {
this.changeOne(owner, resource, undefined);
}
}
}
changeOne(owner: string, resource: URI, markerData: IMarkerData[]): void {
if (isFalsyOrEmpty(markerData)) {
// remove marker for this (owner,resource)-tuple
const a = MapMap.remove(this._byResource, resource.toString(), owner);
const b = MapMap.remove(this._byOwner, owner, resource.toString());
if (a !== b) {
throw new Error('invalid marker service state');
}
if (a && b) {
this._onMarkerChanged.fire([resource]);
}
} else {
// insert marker for this (owner,resource)-tuple
const markers: IMarker[] = [];
for (const data of markerData) {
const marker = MarkerService._toMarker(owner, resource, data);
if (marker) {
markers.push(marker);
}
}
MapMap.set(this._byResource, resource.toString(), owner, markers);
MapMap.set(this._byOwner, owner, resource.toString(), markers);
this._onMarkerChanged.fire([resource]);
}
}
private static _toMarker(owner: string, resource: URI, data: IMarkerData): IMarker {
let { code, severity, message, source, startLineNumber, startColumn, endLineNumber, endColumn } = data;
if (!message) {
return undefined;
}
// santize data
code = code || null;
startLineNumber = startLineNumber > 0 ? startLineNumber : 1;
startColumn = startColumn > 0 ? startColumn : 1;
endLineNumber = endLineNumber >= startLineNumber ? endLineNumber : startLineNumber;
endColumn = endColumn > 0 ? endColumn : startColumn;
return {
resource,
owner,
code,
severity,
message,
source,
startLineNumber,
startColumn,
endLineNumber,
endColumn
};
}
changeAll(owner: string, data: IResourceMarker[]): void {
const changes: URI[] = [];
const map = this._byOwner[owner];
// remove old marker
if (map) {
delete this._byOwner[owner];
for (const resource in map) {
// remeber what we remove
const [first] = MapMap.get(this._byResource, resource, owner);
if (first) {
changes.push(first.resource);
}
// actual remove
MapMap.remove(this._byResource, resource, owner);
}
}
// add new markers
if (!isFalsyOrEmpty(data)) {
// group by resource
const groups: { [resource: string]: IMarker[] } = Object.create(null);
for (const { resource, marker: markerData } of data) {
const marker = MarkerService._toMarker(owner, resource, markerData);
if (!marker) {
// filter bad markers
continue;
}
const array = groups[resource.toString()];
if (!array) {
groups[resource.toString()] = [marker];
changes.push(resource);
} else {
array.push(marker);
}
}
// insert all
for (const resource in groups) {
MapMap.set(this._byResource, resource, owner, groups[resource]);
MapMap.set(this._byOwner, owner, resource, groups[resource]);
}
}
if (changes.length > 0) {
this._onMarkerChanged.fire(changes);
}
}
read(filter: { owner?: string; resource?: URI; take?: number; } = Object.create(null)): IMarker[] {
let { owner, resource, take } = filter;
if (!take || take < 0) {
take = -1;
}
if (owner && resource) {
// exactly one owner AND resource
const result = MapMap.get(this._byResource, resource.toString(), owner);
if (!result) {
return [];
} else {
return result.slice(0, take > 0 ? take : undefined);
}
} else if (!owner && !resource) {
// all
const result: IMarker[] = [];
for (const key1 in this._byResource) {
for (const key2 in this._byResource[key1]) {
for (const data of this._byResource[key1][key2]) {
const newLen = result.push(data);
if (take > 0 && newLen === take) {
return result;
}
}
}
}
return result;
} else {
// of one resource OR owner
const map: { [key: string]: IMarker[] } = owner
? this._byOwner[owner]
: this._byResource[resource.toString()];
if (!map) {
return [];
}
const result: IMarker[] = [];
for (const key in map) {
for (const data of map[key]) {
const newLen = result.push(data);
if (take > 0 && newLen === take) {
return result;
}
}
}
return result;
}
}
// --- event debounce logic
private static _dedupeMap: { [uri: string]: boolean };
private static _debouncer(last: URI[], event: URI[]): URI[] {
if (!last) {
MarkerService._dedupeMap = Object.create(null);
last = [];
}
for (const uri of event) {
if (MarkerService._dedupeMap[uri.toString()] === void 0) {
MarkerService._dedupeMap[uri.toString()] = true;
last.push(uri);
}
}
return last;
}
}

View File

@@ -0,0 +1,116 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import Severity from 'vs/base/common/severity';
import Event from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export interface IMarkerService {
_serviceBrand: any;
getStatistics(): MarkerStatistics;
changeOne(owner: string, resource: URI, markers: IMarkerData[]): void;
changeAll(owner: string, data: IResourceMarker[]): void;
remove(owner: string, resources: URI[]): void;
read(filter?: { owner?: string; resource?: URI; take?: number; }): IMarker[];
onMarkerChanged: Event<URI[]>;
}
/**
* A structure defining a problem/warning/etc.
*/
export interface IMarkerData {
code?: string;
severity: Severity;
message: string;
source?: string;
startLineNumber: number;
startColumn: number;
endLineNumber: number;
endColumn: number;
}
export interface IResourceMarker {
resource: URI;
marker: IMarkerData;
}
export interface IMarker {
owner: string;
resource: URI;
severity: Severity;
code?: string;
message: string;
source?: string;
startLineNumber: number;
startColumn: number;
endLineNumber: number;
endColumn: number;
}
export interface MarkerStatistics {
errors: number;
warnings: number;
infos: number;
unknowns: number;
}
export namespace IMarkerData {
const emptyString = '';
export function makeKey(markerData: IMarkerData): string {
let result: string[] = [emptyString];
if (markerData.source) {
result.push(markerData.source.replace('¦', '\¦'));
} else {
result.push(emptyString);
}
if (markerData.code) {
result.push(markerData.code.replace('¦', '\¦'));
} else {
result.push(emptyString);
}
if (markerData.severity !== void 0 && markerData.severity !== null) {
result.push(Severity.toString(markerData.severity));
} else {
result.push(emptyString);
}
if (markerData.message) {
result.push(markerData.message.replace('¦', '\¦'));
} else {
result.push(emptyString);
}
if (markerData.startLineNumber !== void 0 && markerData.startLineNumber !== null) {
result.push(markerData.startLineNumber.toString());
} else {
result.push(emptyString);
}
if (markerData.startColumn !== void 0 && markerData.startColumn !== null) {
result.push(markerData.startColumn.toString());
} else {
result.push(emptyString);
}
if (markerData.endLineNumber !== void 0 && markerData.endLineNumber !== null) {
result.push(markerData.endLineNumber.toString());
} else {
result.push(emptyString);
}
if (markerData.endColumn !== void 0 && markerData.endColumn !== null) {
result.push(markerData.endColumn.toString());
} else {
result.push(emptyString);
}
result.push(emptyString);
return result.join('¦');
}
}
export const IMarkerService = createDecorator<IMarkerService>('markerService');

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,199 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import assert = require('assert');
import URI from 'vs/base/common/uri';
import markerService = require('vs/platform/markers/common/markerService');
import { IMarkerData } from 'vs/platform/markers/common/markers';
function randomMarkerData(): IMarkerData {
return {
severity: 1,
message: Math.random().toString(16),
startLineNumber: 1,
startColumn: 1,
endLineNumber: 1,
endColumn: 1
};
}
suite('Marker Service', () => {
test('query', () => {
let service = new markerService.MarkerService();
service.changeAll('far', [{
resource: URI.parse('file:///c/test/file.cs'),
marker: randomMarkerData()
}]);
assert.equal(service.read().length, 1);
assert.equal(service.read({ owner: 'far' }).length, 1);
assert.equal(service.read({ resource: URI.parse('file:///c/test/file.cs') }).length, 1);
assert.equal(service.read({ owner: 'far', resource: URI.parse('file:///c/test/file.cs') }).length, 1);
service.changeAll('boo', [{
resource: URI.parse('file:///c/test/file.cs'),
marker: randomMarkerData()
}]);
assert.equal(service.read().length, 2);
assert.equal(service.read({ owner: 'far' }).length, 1);
assert.equal(service.read({ owner: 'boo' }).length, 1);
});
test('changeOne override', () => {
let service = new markerService.MarkerService();
service.changeOne('far', URI.parse('/path/only.cs'), [randomMarkerData()]);
assert.equal(service.read().length, 1);
assert.equal(service.read({ owner: 'far' }).length, 1);
service.changeOne('boo', URI.parse('/path/only.cs'), [randomMarkerData()]);
assert.equal(service.read().length, 2);
assert.equal(service.read({ owner: 'far' }).length, 1);
assert.equal(service.read({ owner: 'boo' }).length, 1);
service.changeOne('far', URI.parse('/path/only.cs'), [randomMarkerData(), randomMarkerData()]);
assert.equal(service.read({ owner: 'far' }).length, 2);
assert.equal(service.read({ owner: 'boo' }).length, 1);
});
test('changeOne/All clears', () => {
let service = new markerService.MarkerService();
service.changeOne('far', URI.parse('/path/only.cs'), [randomMarkerData()]);
service.changeOne('boo', URI.parse('/path/only.cs'), [randomMarkerData()]);
assert.equal(service.read({ owner: 'far' }).length, 1);
assert.equal(service.read({ owner: 'boo' }).length, 1);
assert.equal(service.read().length, 2);
service.changeOne('far', URI.parse('/path/only.cs'), []);
assert.equal(service.read({ owner: 'far' }).length, 0);
assert.equal(service.read({ owner: 'boo' }).length, 1);
assert.equal(service.read().length, 1);
service.changeAll('boo', []);
assert.equal(service.read({ owner: 'far' }).length, 0);
assert.equal(service.read({ owner: 'boo' }).length, 0);
assert.equal(service.read().length, 0);
});
test('changeAll sends event for cleared', () => {
let service = new markerService.MarkerService();
service.changeAll('far', [{
resource: URI.parse('file:///d/path'),
marker: randomMarkerData()
}, {
resource: URI.parse('file:///d/path'),
marker: randomMarkerData()
}]);
assert.equal(service.read({ owner: 'far' }).length, 2);
service.onMarkerChanged(changedResources => {
assert.equal(changedResources.length, 1);
changedResources.forEach(u => assert.equal(u.toString(), 'file:///d/path'));
assert.equal(service.read({ owner: 'far' }).length, 0);
});
service.changeAll('far', []);
});
test('changeAll merges', () => {
let service = new markerService.MarkerService();
service.changeAll('far', [{
resource: URI.parse('file:///c/test/file.cs'),
marker: randomMarkerData()
}, {
resource: URI.parse('file:///c/test/file.cs'),
marker: randomMarkerData()
}]);
assert.equal(service.read({ owner: 'far' }).length, 2);
});
test('changeAll must not break integrety, issue #12635', () => {
let service = new markerService.MarkerService();
service.changeAll('far', [{
resource: URI.parse('scheme:path1'),
marker: randomMarkerData()
}, {
resource: URI.parse('scheme:path2'),
marker: randomMarkerData()
}]);
service.changeAll('boo', [{
resource: URI.parse('scheme:path1'),
marker: randomMarkerData()
}]);
service.changeAll('far', [{
resource: URI.parse('scheme:path1'),
marker: randomMarkerData()
}, {
resource: URI.parse('scheme:path2'),
marker: randomMarkerData()
}]);
assert.equal(service.read({ owner: 'far' }).length, 2);
assert.equal(service.read({ resource: URI.parse('scheme:path1') }).length, 2);
});
test('invalid marker data', () => {
let data = randomMarkerData();
let service = new markerService.MarkerService();
data.message = undefined;
service.changeOne('far', URI.parse('some:uri/path'), [data]);
assert.equal(service.read({ owner: 'far' }).length, 0);
data.message = null;
service.changeOne('far', URI.parse('some:uri/path'), [data]);
assert.equal(service.read({ owner: 'far' }).length, 0);
data.message = 'null';
service.changeOne('far', URI.parse('some:uri/path'), [data]);
assert.equal(service.read({ owner: 'far' }).length, 1);
});
test('MapMap#remove returns bad values, https://github.com/Microsoft/vscode/issues/13548', () => {
let service = new markerService.MarkerService();
service.changeOne('o', URI.parse('some:uri/1'), [randomMarkerData()]);
service.changeOne('o', URI.parse('some:uri/2'), []);
});
test('Error code of zero in markers get removed, #31275', function () {
let data = <IMarkerData>{
code: '0',
startLineNumber: 1,
startColumn: 2,
endLineNumber: 1,
endColumn: 5,
message: 'test',
severity: 0,
source: 'me'
};
let service = new markerService.MarkerService();
service.changeOne('far', URI.parse('some:thing'), [data]);
let marker = service.read({ resource: URI.parse('some:thing') });
assert.equal(marker.length, 1);
assert.equal(marker[0].code, '0');
});
});