mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-20 17:30:46 +00:00
Initial Move from Azure DevOps to GitHub
This commit is contained in:
327
src/Explorer/Tables/QueryBuilder/ClauseGroup.ts
Normal file
327
src/Explorer/Tables/QueryBuilder/ClauseGroup.ts
Normal file
@@ -0,0 +1,327 @@
|
||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||
import * as Utilities from "../Utilities";
|
||||
|
||||
export default class ClauseGroup {
|
||||
public isRootGroup: boolean;
|
||||
public children = new Array();
|
||||
public parentGroup: ClauseGroup;
|
||||
private _id: string;
|
||||
|
||||
constructor(isRootGroup: boolean, parentGroup: ClauseGroup, id?: string) {
|
||||
this.isRootGroup = isRootGroup;
|
||||
this.parentGroup = parentGroup;
|
||||
this._id = id ? id : Utilities.guid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens the clause tree into an array, depth-first, left to right.
|
||||
*/
|
||||
public flattenClauses(targetArray: ko.ObservableArray<QueryClauseViewModel>): void {
|
||||
var tempArray = new Array<QueryClauseViewModel>();
|
||||
|
||||
this.flattenClausesImpl(this, tempArray);
|
||||
targetArray.removeAll();
|
||||
tempArray.forEach(element => {
|
||||
targetArray.push(element);
|
||||
});
|
||||
}
|
||||
|
||||
public insertClauseBefore(newClause: QueryClauseViewModel, insertBefore?: QueryClauseViewModel): void {
|
||||
if (!insertBefore) {
|
||||
newClause.clauseGroup = this;
|
||||
this.children.push(newClause);
|
||||
} else {
|
||||
var targetGroup = insertBefore.clauseGroup;
|
||||
|
||||
if (targetGroup) {
|
||||
var insertBeforeIndex = targetGroup.children.indexOf(insertBefore);
|
||||
newClause.clauseGroup = targetGroup;
|
||||
targetGroup.children.splice(insertBeforeIndex, 0, newClause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public deleteClause(clause: QueryClauseViewModel): void {
|
||||
var targetGroup = clause.clauseGroup;
|
||||
|
||||
if (targetGroup) {
|
||||
var index = targetGroup.children.indexOf(clause);
|
||||
targetGroup.children.splice(index, 1);
|
||||
clause.dispose();
|
||||
|
||||
if (targetGroup.children.length <= 1 && !targetGroup.isRootGroup) {
|
||||
var parent = targetGroup.parentGroup;
|
||||
var targetGroupIndex = parent.children.indexOf(targetGroup);
|
||||
|
||||
if (targetGroup.children.length === 1) {
|
||||
var orphan = targetGroup.children.shift();
|
||||
|
||||
if (orphan instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>orphan).clauseGroup = parent;
|
||||
} else if (orphan instanceof ClauseGroup) {
|
||||
(<ClauseGroup>orphan).parentGroup = parent;
|
||||
}
|
||||
|
||||
parent.children.splice(targetGroupIndex, 1, orphan);
|
||||
} else {
|
||||
parent.children.splice(targetGroupIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public removeAll(): void {
|
||||
var allClauses: QueryClauseViewModel[] = new Array<QueryClauseViewModel>();
|
||||
|
||||
this.flattenClausesImpl(this, allClauses);
|
||||
|
||||
while (allClauses.length > 0) {
|
||||
allClauses.shift().dispose();
|
||||
}
|
||||
|
||||
this.children = new Array<any>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups selected items. Returns True if a new group was created, otherwise False.
|
||||
*/
|
||||
public groupSelectedItems(): boolean {
|
||||
// Find the selection start & end, also check for gaps between selected items (if found, cannot proceed).
|
||||
var selection = this.getCheckedItemsInfo();
|
||||
|
||||
if (selection.canGroup) {
|
||||
var newGroup = new ClauseGroup(false, this);
|
||||
// Replace the selected items with the new group, and then move the selected items into the new group.
|
||||
var groupedItems = this.children.splice(selection.begin, selection.end - selection.begin + 1, newGroup);
|
||||
|
||||
groupedItems &&
|
||||
groupedItems.forEach(element => {
|
||||
newGroup.children.push(element);
|
||||
|
||||
if (element instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>element).clauseGroup = newGroup;
|
||||
} else if (element instanceof ClauseGroup) {
|
||||
(<ClauseGroup>element).parentGroup = newGroup;
|
||||
}
|
||||
});
|
||||
|
||||
this.unselectAll();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ungroup(): void {
|
||||
if (this.isRootGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
var parentGroup = this.parentGroup;
|
||||
var index = parentGroup.children.indexOf(this);
|
||||
|
||||
if (index >= 0) {
|
||||
parentGroup.children.splice(index, 1);
|
||||
|
||||
var toPromote = this.children.splice(0, this.children.length);
|
||||
|
||||
// Move all children one level up.
|
||||
toPromote &&
|
||||
toPromote.forEach(element => {
|
||||
if (element instanceof ClauseGroup) {
|
||||
(<ClauseGroup>element).parentGroup = parentGroup;
|
||||
} else if (element instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>element).clauseGroup = parentGroup;
|
||||
}
|
||||
|
||||
parentGroup.children.splice(index, 0, element);
|
||||
index++;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public canGroupSelectedItems(): boolean {
|
||||
return this.getCheckedItemsInfo().canGroup;
|
||||
}
|
||||
|
||||
public findDeepestGroupInChildren(skipIndex?: number): ClauseGroup {
|
||||
var deepest: ClauseGroup = this;
|
||||
var level: number = 0;
|
||||
var func = (currentGroup: ClauseGroup): void => {
|
||||
level++;
|
||||
if (currentGroup.getCurrentGroupDepth() > deepest.getCurrentGroupDepth()) {
|
||||
deepest = currentGroup;
|
||||
}
|
||||
|
||||
for (var i = 0; i < currentGroup.children.length; i++) {
|
||||
var currentItem = currentGroup.children[i];
|
||||
|
||||
if ((i !== skipIndex || level > 1) && currentItem instanceof ClauseGroup) {
|
||||
func(currentItem);
|
||||
}
|
||||
}
|
||||
level--;
|
||||
};
|
||||
|
||||
func(this);
|
||||
|
||||
return deepest;
|
||||
}
|
||||
|
||||
private getCheckedItemsInfo(): { canGroup: boolean; begin: number; end: number } {
|
||||
var beginIndex = -1;
|
||||
var endIndex = -1;
|
||||
// In order to perform group, all selected items must be next to each other.
|
||||
// If one or more items are not selected between the first and the last selected item, the gapFlag will be set to True, meaning cannot perform group.
|
||||
var gapFlag = false;
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
var subGroupSelectionState: { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean };
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
subGroupSelectionState = (<ClauseGroup>currentItem).getSelectionState();
|
||||
|
||||
if (subGroupSelectionState.partiallySelected) {
|
||||
gapFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
beginIndex < 0 &&
|
||||
endIndex < 0 &&
|
||||
((currentItem instanceof QueryClauseViewModel && currentItem.checkedForGrouping.peek()) ||
|
||||
(currentItem instanceof ClauseGroup && subGroupSelectionState.allSelected))
|
||||
) {
|
||||
beginIndex = i;
|
||||
}
|
||||
|
||||
if (
|
||||
beginIndex >= 0 &&
|
||||
endIndex < 0 &&
|
||||
((currentItem instanceof QueryClauseViewModel && !currentItem.checkedForGrouping.peek()) ||
|
||||
(currentItem instanceof ClauseGroup && !subGroupSelectionState.allSelected))
|
||||
) {
|
||||
endIndex = i - 1;
|
||||
}
|
||||
|
||||
if (beginIndex >= 0 && endIndex < 0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (
|
||||
beginIndex >= 0 &&
|
||||
endIndex >= 0 &&
|
||||
((currentItem instanceof QueryClauseViewModel && currentItem.checkedForGrouping.peek()) ||
|
||||
(currentItem instanceof ClauseGroup && !subGroupSelectionState.nonSelected))
|
||||
) {
|
||||
gapFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gapFlag && endIndex < 0) {
|
||||
endIndex = this.children.length - 1;
|
||||
}
|
||||
|
||||
return {
|
||||
canGroup: beginIndex >= 0 && !gapFlag && count > 1,
|
||||
begin: beginIndex,
|
||||
end: endIndex
|
||||
};
|
||||
}
|
||||
|
||||
private getSelectionState(): { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean } {
|
||||
var selectedCount = 0;
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup && (<ClauseGroup>currentItem).getSelectionState().allSelected) {
|
||||
selectedCount++;
|
||||
}
|
||||
|
||||
if (
|
||||
currentItem instanceof QueryClauseViewModel &&
|
||||
(<QueryClauseViewModel>currentItem).checkedForGrouping.peek()
|
||||
) {
|
||||
selectedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
allSelected: selectedCount === this.children.length,
|
||||
partiallySelected: selectedCount > 0 && selectedCount < this.children.length,
|
||||
nonSelected: selectedCount === 0
|
||||
};
|
||||
}
|
||||
|
||||
private unselectAll(): void {
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
(<ClauseGroup>currentItem).unselectAll();
|
||||
}
|
||||
|
||||
if (currentItem instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>currentItem).checkedForGrouping(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private flattenClausesImpl(queryGroup: ClauseGroup, targetArray: QueryClauseViewModel[]): void {
|
||||
if (queryGroup.isRootGroup) {
|
||||
targetArray.splice(0, targetArray.length);
|
||||
}
|
||||
|
||||
for (var i = 0; i < queryGroup.children.length; i++) {
|
||||
var currentItem = queryGroup.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
this.flattenClausesImpl(currentItem, targetArray);
|
||||
}
|
||||
|
||||
if (currentItem instanceof QueryClauseViewModel) {
|
||||
targetArray.push(currentItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public getTreeDepth(): number {
|
||||
var currentDepth = this.getCurrentGroupDepth();
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
var newDepth = (<ClauseGroup>currentItem).getTreeDepth();
|
||||
|
||||
if (newDepth > currentDepth) {
|
||||
currentDepth = newDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currentDepth;
|
||||
}
|
||||
|
||||
public getCurrentGroupDepth(): number {
|
||||
var group = <ClauseGroup>this;
|
||||
var depth = 0;
|
||||
|
||||
while (!group.isRootGroup) {
|
||||
depth++;
|
||||
group = group.parentGroup;
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
}
|
||||
49
src/Explorer/Tables/QueryBuilder/ClauseGroupViewModel.ts
Normal file
49
src/Explorer/Tables/QueryBuilder/ClauseGroupViewModel.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import * as ko from "knockout";
|
||||
import ClauseGroup from "./ClauseGroup";
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import * as Constants from "../Constants";
|
||||
|
||||
/**
|
||||
* View model for showing group indicators on UI, contains information such as group color and border styles.
|
||||
*/
|
||||
export default class ClauseGroupViewModel {
|
||||
public ungroupClausesLabel = "Ungroup clauses"; // localize
|
||||
|
||||
public backgroundColor: ko.Observable<string>;
|
||||
public canUngroup: ko.Observable<boolean>;
|
||||
public showTopBorder: ko.Observable<boolean>;
|
||||
public showLeftBorder: ko.Observable<boolean>;
|
||||
public showBottomBorder: ko.Observable<boolean>;
|
||||
public depth: ko.Observable<number>; // for debugging purpose only, now showing the number on UI.
|
||||
public borderBackgroundColor: ko.Observable<string>;
|
||||
|
||||
private _clauseGroup: ClauseGroup;
|
||||
private _queryBuilderViewModel: QueryBuilderViewModel;
|
||||
|
||||
constructor(clauseGroup: ClauseGroup, canUngroup: boolean, queryBuilderViewModel: QueryBuilderViewModel) {
|
||||
this._clauseGroup = clauseGroup;
|
||||
this._queryBuilderViewModel = queryBuilderViewModel;
|
||||
this.backgroundColor = ko.observable<string>(this.getGroupBackgroundColor(clauseGroup));
|
||||
this.canUngroup = ko.observable<boolean>(canUngroup);
|
||||
this.showTopBorder = ko.observable<boolean>(false);
|
||||
this.showLeftBorder = ko.observable<boolean>(false);
|
||||
this.showBottomBorder = ko.observable<boolean>(false);
|
||||
this.depth = ko.observable<number>(clauseGroup.getCurrentGroupDepth());
|
||||
this.borderBackgroundColor = ko.observable<string>("solid thin " + this.getGroupBackgroundColor(clauseGroup));
|
||||
}
|
||||
|
||||
public ungroupClauses = (): void => {
|
||||
this._clauseGroup.ungroup();
|
||||
this._queryBuilderViewModel.updateClauseArray();
|
||||
};
|
||||
|
||||
private getGroupBackgroundColor(group: ClauseGroup): string {
|
||||
var colorCount = Constants.clauseGroupColors.length;
|
||||
|
||||
if (group.isRootGroup) {
|
||||
return Constants.transparentColor;
|
||||
} else {
|
||||
return Constants.clauseGroupColors[group.getCurrentGroupDepth() % colorCount];
|
||||
}
|
||||
}
|
||||
}
|
||||
377
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
Normal file
377
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
Normal file
@@ -0,0 +1,377 @@
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||
import * as DateTimeUtilities from "./DateTimeUtilities";
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
export var utc = "utc";
|
||||
export var local = "local";
|
||||
|
||||
export interface ITimestampQuery {
|
||||
queryType: string; // valid values are "last" and "range"
|
||||
lastNumber: number; // number value of a custom timestamp using the last option
|
||||
lastTimeUnit: string; // timeunit of a custom timestamp using the last option
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
timeZone: string; // timezone of custom range timestamp, valid values are "local" and "utc"
|
||||
}
|
||||
|
||||
export interface ILastQuery {
|
||||
lastNumber: number;
|
||||
lastTimeUnit: string;
|
||||
}
|
||||
|
||||
export enum TimeUnit {
|
||||
Seconds,
|
||||
Minutes,
|
||||
Hours,
|
||||
Days
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting helpers
|
||||
*/
|
||||
|
||||
export function addRangeTimestamp(
|
||||
timestamp: ITimestampQuery,
|
||||
queryBuilderViewModel: QueryBuilderViewModel,
|
||||
queryClauseViewModel: QueryClauseViewModel
|
||||
): void {
|
||||
queryBuilderViewModel.addCustomRange(timestamp, queryClauseViewModel);
|
||||
}
|
||||
|
||||
export function getDefaultStart(localTime: boolean, durationHours: number = 24): string {
|
||||
var startTimestamp: string;
|
||||
|
||||
var utcNowString: string = new Date().toISOString();
|
||||
var yesterday: Date = new Date(utcNowString);
|
||||
|
||||
yesterday.setHours(yesterday.getHours() - durationHours);
|
||||
startTimestamp = yesterday.toISOString();
|
||||
|
||||
if (localTime) {
|
||||
startTimestamp = localFromUtcDateString(startTimestamp);
|
||||
}
|
||||
|
||||
return startTimestamp;
|
||||
}
|
||||
|
||||
export function getDefaultEnd(localTime: boolean): string {
|
||||
var endTimestamp: string;
|
||||
|
||||
var utcNowString: string = new Date().toISOString();
|
||||
|
||||
endTimestamp = utcNowString;
|
||||
|
||||
if (localTime) {
|
||||
endTimestamp = localFromUtcDateString(endTimestamp);
|
||||
}
|
||||
|
||||
return endTimestamp;
|
||||
}
|
||||
|
||||
export function parseDate(dateString: string, isUTC: boolean): Date {
|
||||
// TODO validate dateString
|
||||
var date: Date = null;
|
||||
|
||||
if (dateString) {
|
||||
try {
|
||||
// Date string is assumed to be UTC in Storage Explorer Standalone.
|
||||
// Behavior may vary in other browsers.
|
||||
// Here's an example of how the string looks like "2015-10-24T21:44:12"
|
||||
var millisecondTime = Date.parse(dateString),
|
||||
parsed: Date = new Date(millisecondTime);
|
||||
|
||||
if (isUTC) {
|
||||
date = parsed;
|
||||
} else {
|
||||
// Since we parsed in UTC, accessors are flipped - we get local time from the getUTC* group
|
||||
// Reinstating, the date is parsed above as UTC, and here we are creating a new date object
|
||||
// in local time.
|
||||
var year = parsed.getUTCFullYear(),
|
||||
month = parsed.getUTCMonth(),
|
||||
day = parsed.getUTCDate(),
|
||||
hours = parsed.getUTCHours(),
|
||||
minutes = parsed.getUTCMinutes(),
|
||||
seconds = parsed.getUTCSeconds(),
|
||||
milliseconds = parsed.getUTCMilliseconds();
|
||||
|
||||
date = new Date(year, month, day, hours, minutes, seconds, milliseconds);
|
||||
}
|
||||
} catch (error) {
|
||||
//Debug.error("Error parsing date string: ", dateString, error);
|
||||
}
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
export function utcFromLocalDateString(localDateString: string): string {
|
||||
// TODO validate localDateString
|
||||
var localDate = parseDate(localDateString, false),
|
||||
utcDateString: string = null;
|
||||
|
||||
if (localDate) {
|
||||
utcDateString = localDate.toISOString();
|
||||
}
|
||||
|
||||
return utcDateString;
|
||||
}
|
||||
|
||||
function padIfNeeded(value: number): string {
|
||||
var padded: string = String(value);
|
||||
|
||||
if (0 <= value && value < 10) {
|
||||
padded = "0" + padded;
|
||||
}
|
||||
|
||||
return padded;
|
||||
}
|
||||
|
||||
function toLocalDateString(date: Date): string {
|
||||
var localDateString: string = null;
|
||||
|
||||
if (date) {
|
||||
localDateString =
|
||||
date.getFullYear() +
|
||||
"-" +
|
||||
padIfNeeded(date.getMonth() + 1) +
|
||||
"-" +
|
||||
padIfNeeded(date.getDate()) +
|
||||
"T" +
|
||||
padIfNeeded(date.getHours()) +
|
||||
":" +
|
||||
padIfNeeded(date.getMinutes()) +
|
||||
":" +
|
||||
padIfNeeded(date.getSeconds());
|
||||
}
|
||||
|
||||
return localDateString;
|
||||
}
|
||||
|
||||
export function localFromUtcDateString(utcDateString: string): string {
|
||||
// TODO validate utcDateString
|
||||
var utcDate: Date = parseDate(utcDateString, true),
|
||||
localDateString: string = null;
|
||||
|
||||
if (utcDate) {
|
||||
localDateString = toLocalDateString(utcDate);
|
||||
}
|
||||
|
||||
return localDateString;
|
||||
}
|
||||
|
||||
export function tryChangeTimestampTimeZone(koTimestamp: ko.Observable<string>, toUTC: boolean): void {
|
||||
if (koTimestamp) {
|
||||
var currentDateString: string = koTimestamp(),
|
||||
newDateString: string;
|
||||
|
||||
if (currentDateString) {
|
||||
if (toUTC) {
|
||||
newDateString = utcFromLocalDateString(currentDateString);
|
||||
// removing last character because cannot format it to html binding with the 'Z' at the end
|
||||
newDateString = newDateString.substring(0, newDateString.length - 1);
|
||||
} else {
|
||||
newDateString = localFromUtcDateString(currentDateString);
|
||||
}
|
||||
|
||||
// utcFromLocalDateString and localFromUtcDateString could return null if currentDateString is invalid.
|
||||
// Hence, only set koTimestamp if newDateString is not null.
|
||||
if (newDateString) {
|
||||
koTimestamp(newDateString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Input validation helpers
|
||||
*/
|
||||
|
||||
export var noTooltip = "",
|
||||
invalidStartTimeTooltip = "Please provide a valid start time.", // localize
|
||||
invalidExpiryTimeRequiredTooltip = "Required field. Please provide a valid expiry time.", // localize
|
||||
invalidExpiryTimeGreaterThanStartTimeTooltip = "The expiry time must be greater than the start time."; // localize
|
||||
|
||||
export function isDateString(dateString: string): boolean {
|
||||
var success: boolean = false;
|
||||
|
||||
if (dateString) {
|
||||
var date: number = Date.parse(dateString);
|
||||
|
||||
success = $.isNumeric(date);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Is date string and earlier than expiry time; or is empty
|
||||
// export function isInvalidStartTimeInput(startTimestamp: string, expiryTimestamp: string, isUTC: boolean): DialogsCommon.IValidationResult {
|
||||
// var tooltip: string = noTooltip,
|
||||
// isValid: boolean = isDateString(startTimestamp),
|
||||
// startDate: Date,
|
||||
// expiryDate: Date;
|
||||
|
||||
// if (!isValid) {
|
||||
// isValid = (startTimestamp === "");
|
||||
// }
|
||||
|
||||
// if (!isValid) {
|
||||
// tooltip = invalidStartTimeTooltip;
|
||||
// }
|
||||
|
||||
// if (isValid && !!startTimestamp && isDateString(expiryTimestamp)) {
|
||||
// startDate = parseDate(startTimestamp, isUTC);
|
||||
// expiryDate = parseDate(expiryTimestamp, isUTC);
|
||||
|
||||
// isValid = (startDate < expiryDate);
|
||||
|
||||
// if (!isValid) {
|
||||
// tooltip = invalidExpiryTimeGreaterThanStartTimeTooltip;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return { isInvalid: !isValid, help: tooltip };
|
||||
// }
|
||||
|
||||
// Is date string, and later than start time (if any)
|
||||
// export function isInvalidExpiryTimeInput(startTimestamp: string, expiryTimestamp: string, isUTC: boolean): DialogsCommon.IValidationResult {
|
||||
// var isValid: boolean = isDateString(expiryTimestamp),
|
||||
// tooltip: string = isValid ? noTooltip : invalidExpiryTimeRequiredTooltip,
|
||||
// startDate: Date,
|
||||
// expiryDate: Date;
|
||||
|
||||
// if (isValid && startTimestamp) {
|
||||
// if (isDateString(startTimestamp)) {
|
||||
// startDate = parseDate(startTimestamp, isUTC);
|
||||
// expiryDate = parseDate(expiryTimestamp, isUTC);
|
||||
// isValid = (startDate < expiryDate);
|
||||
|
||||
// if (!isValid) {
|
||||
// tooltip = invalidExpiryTimeGreaterThanStartTimeTooltip;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return { isInvalid: !isValid, help: tooltip };
|
||||
// }
|
||||
|
||||
/**
|
||||
* Functions to calculate DateTime Strings
|
||||
*/
|
||||
|
||||
function _getLocalIsoDateTimeString(time: Date): string {
|
||||
// yyyy-mm-ddThh:mm:ss.sss
|
||||
// Not using the timezone offset (or 'Z'), which will make the
|
||||
// date/time represent local time by default.
|
||||
// var formatted = _string.sprintf(
|
||||
// "%sT%02d:%02d:%02d.%03d",
|
||||
// _getLocalIsoDateString(time),
|
||||
// time.getHours(),
|
||||
// time.getMinutes(),
|
||||
// time.getSeconds(),
|
||||
// time.getMilliseconds()
|
||||
// );
|
||||
// return formatted;
|
||||
return (
|
||||
_getLocalIsoDateString(time) +
|
||||
"T" +
|
||||
DateTimeUtilities.ensureDoubleDigits(time.getHours()) +
|
||||
":" +
|
||||
DateTimeUtilities.ensureDoubleDigits(time.getMinutes()) +
|
||||
":" +
|
||||
DateTimeUtilities.ensureDoubleDigits(time.getSeconds()) +
|
||||
"." +
|
||||
DateTimeUtilities.ensureTripleDigits(time.getMilliseconds())
|
||||
);
|
||||
}
|
||||
|
||||
function _getLocalIsoDateString(date: Date): string {
|
||||
return _getLocalIsoDateStringFromParts(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
}
|
||||
|
||||
function _getLocalIsoDateStringFromParts(
|
||||
fullYear: number,
|
||||
month: number /* 0..11 */,
|
||||
date: number /* 1..31 */
|
||||
): string {
|
||||
month = month + 1;
|
||||
return (
|
||||
fullYear + "-" + DateTimeUtilities.ensureDoubleDigits(month) + "-" + DateTimeUtilities.ensureDoubleDigits(date)
|
||||
);
|
||||
// return _string.sprintf(
|
||||
// "%04d-%02d-%02d",
|
||||
// fullYear,
|
||||
// month + 1, // JS month is 0..11
|
||||
// date); // but date is 1..31
|
||||
}
|
||||
|
||||
function _addDaysHours(time: Date, days: number, hours: number): Date {
|
||||
var msPerHour = 1000 * 60 * 60;
|
||||
var daysMs = days * msPerHour * 24;
|
||||
var hoursMs = hours * msPerHour;
|
||||
var newTimeMs = time.getTime() + daysMs + hoursMs;
|
||||
return new Date(newTimeMs);
|
||||
}
|
||||
|
||||
function _daysHoursBeforeNow(days: number, hours: number): Date {
|
||||
return _addDaysHours(new Date(), -days, -hours);
|
||||
}
|
||||
|
||||
export function _queryLastDaysHours(days: number, hours: number): string {
|
||||
/* tslint:disable: no-unused-variable */
|
||||
var daysHoursAgo = _getLocalIsoDateTimeString(_daysHoursBeforeNow(days, hours));
|
||||
daysHoursAgo = DateTimeUtilities.getUTCDateTime(daysHoursAgo);
|
||||
|
||||
return daysHoursAgo;
|
||||
/* tslint:enable: no-unused-variable */
|
||||
}
|
||||
|
||||
export function _queryCurrentMonthLocal(): string {
|
||||
var now = new Date();
|
||||
var start = _getLocalIsoDateStringFromParts(now.getFullYear(), now.getMonth(), 1);
|
||||
start = DateTimeUtilities.getUTCDateTime(start);
|
||||
return start;
|
||||
}
|
||||
|
||||
export function _queryCurrentYearLocal(): string {
|
||||
var now = new Date();
|
||||
var start = _getLocalIsoDateStringFromParts(now.getFullYear(), 0, 1); // Month is 0..11, date is 1..31
|
||||
start = DateTimeUtilities.getUTCDateTime(start);
|
||||
return start;
|
||||
}
|
||||
|
||||
function _addTime(time: Date, lastNumber: number, timeUnit: string): Date {
|
||||
var timeMS: number;
|
||||
switch (TimeUnit[Number(timeUnit)]) {
|
||||
case TimeUnit.Days.toString():
|
||||
timeMS = lastNumber * 1000 * 60 * 60 * 24;
|
||||
break;
|
||||
case TimeUnit.Hours.toString():
|
||||
timeMS = lastNumber * 1000 * 60 * 60;
|
||||
break;
|
||||
case TimeUnit.Minutes.toString():
|
||||
timeMS = lastNumber * 1000 * 60;
|
||||
break;
|
||||
case TimeUnit.Seconds.toString():
|
||||
timeMS = lastNumber * 1000;
|
||||
break;
|
||||
default:
|
||||
//throw new Errors.ArgumentOutOfRangeError(timeUnit);
|
||||
}
|
||||
var newTimeMS = time.getTime() + timeMS;
|
||||
return new Date(newTimeMS);
|
||||
}
|
||||
|
||||
function _timeBeforeNow(lastNumber: number, timeUnit: string): Date {
|
||||
return _addTime(new Date(), -lastNumber, timeUnit);
|
||||
}
|
||||
|
||||
export function _queryLastTime(lastNumber: number, timeUnit: string): string {
|
||||
/* tslint:disable: no-unused-variable */
|
||||
var daysHoursAgo = _getLocalIsoDateTimeString(_timeBeforeNow(lastNumber, timeUnit));
|
||||
daysHoursAgo = DateTimeUtilities.getUTCDateTime(daysHoursAgo);
|
||||
return daysHoursAgo;
|
||||
/* tslint:enable: no-unused-variable */
|
||||
}
|
||||
110
src/Explorer/Tables/QueryBuilder/DateTimeUtilities.test.ts
Normal file
110
src/Explorer/Tables/QueryBuilder/DateTimeUtilities.test.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import * as DateTimeUtilities from "./DateTimeUtilities";
|
||||
|
||||
describe("DateTimeUtilities", () => {
|
||||
const testDateTime1 = new Date("Fri Jul 26 2019 17:03:02 GMT-0700 (Pacific Daylight Time)");
|
||||
const testDateTime2 = new Date("Mon Dec 31 2018 16:00:00 GMT-0800 (Pacific Standard Time)");
|
||||
const testUnixTime1 = 1564185782;
|
||||
const testUnixTime2 = 1546300800;
|
||||
const testTicks1 = "00636997825820000000";
|
||||
const testTicks2 = "00636818976000000000";
|
||||
|
||||
describe("getLocalDateTime", () => {
|
||||
it("should return right local time for date time 1", () => {
|
||||
const time = DateTimeUtilities.getLocalDateTime(testDateTime1.toISOString());
|
||||
expect(new Date(time).toLocaleString()).toBe(testDateTime1.toLocaleString());
|
||||
});
|
||||
it("should return right local time for date time 2", () => {
|
||||
const time = DateTimeUtilities.getLocalDateTime(testDateTime2.toISOString());
|
||||
expect(new Date(time).toLocaleString()).toBe(testDateTime2.toLocaleString());
|
||||
});
|
||||
});
|
||||
|
||||
describe("getUTCDateTime", () => {
|
||||
it("should return right utc time for date time 1", () => {
|
||||
const time = DateTimeUtilities.getUTCDateTime(testDateTime1.toISOString());
|
||||
expect(time).toBe("2019-07-27T00:03:02.000Z");
|
||||
});
|
||||
it("should return right utc time for date time 2", () => {
|
||||
const time = DateTimeUtilities.getUTCDateTime(testDateTime2.toISOString());
|
||||
expect(time).toBe("2019-01-01T00:00:00.000Z");
|
||||
});
|
||||
});
|
||||
|
||||
describe("ensureDoubleDigits", () => {
|
||||
it("should return correct double digits with input of single digit", () => {
|
||||
const digits = DateTimeUtilities.ensureDoubleDigits(2);
|
||||
expect(digits).toBe("02");
|
||||
});
|
||||
it("should return correct double digits with input of double digit", () => {
|
||||
const digits = DateTimeUtilities.ensureDoubleDigits(53);
|
||||
expect(digits).toBe("53");
|
||||
});
|
||||
it("should return correct double digits with input of multi digit", () => {
|
||||
const digits = DateTimeUtilities.ensureDoubleDigits(321654);
|
||||
expect(digits).toBe("32");
|
||||
});
|
||||
});
|
||||
|
||||
describe("ensureTripleDigits", () => {
|
||||
it("should return correct triple digits with input of single digit", () => {
|
||||
const digits = DateTimeUtilities.ensureTripleDigits(2);
|
||||
expect(digits).toBe("002");
|
||||
});
|
||||
it("should return correct triple digits with double digit", () => {
|
||||
const digits = DateTimeUtilities.ensureTripleDigits(53);
|
||||
expect(digits).toBe("053");
|
||||
});
|
||||
it("should return correct triple digits with triple digit", () => {
|
||||
const digits = DateTimeUtilities.ensureTripleDigits(344);
|
||||
expect(digits).toBe("344");
|
||||
});
|
||||
it("should return correct triple digits with multi digit", () => {
|
||||
const digits = DateTimeUtilities.ensureTripleDigits(321654);
|
||||
expect(digits).toBe("321");
|
||||
});
|
||||
});
|
||||
|
||||
describe("convertUnixToJSDate", () => {
|
||||
it("should convert unix number to JS Date for date time 1", () => {
|
||||
const time = DateTimeUtilities.convertUnixToJSDate(testUnixTime1);
|
||||
expect(time.toISOString()).toBe("2019-07-27T00:03:02.000Z");
|
||||
});
|
||||
it("should convert unix number to JS Date for date time 2", () => {
|
||||
const time = DateTimeUtilities.convertUnixToJSDate(testUnixTime2);
|
||||
expect(time.toISOString()).toBe(testDateTime2.toISOString());
|
||||
});
|
||||
});
|
||||
|
||||
describe("convertJSDateToUnix", () => {
|
||||
it("should convert JS Date to unix number for date time 1", () => {
|
||||
const time = DateTimeUtilities.convertJSDateToUnix(testDateTime1.toISOString());
|
||||
expect(time).toBe(testUnixTime1);
|
||||
});
|
||||
it("should convert JS Date to unix number for date time 2", () => {
|
||||
const time = DateTimeUtilities.convertJSDateToUnix(testDateTime2.toISOString());
|
||||
expect(time).toBe(testUnixTime2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("convertTicksToJSDate", () => {
|
||||
it("should convert ticks to JS Date for date time 1", () => {
|
||||
const time = DateTimeUtilities.convertTicksToJSDate(testTicks1);
|
||||
expect(time.toISOString()).toBe(testDateTime1.toISOString());
|
||||
});
|
||||
it("should convert ticks to JS Date for date time 2", () => {
|
||||
const time = DateTimeUtilities.convertTicksToJSDate(testTicks2);
|
||||
expect(time.toISOString()).toBe(testDateTime2.toISOString());
|
||||
});
|
||||
});
|
||||
|
||||
describe("convertJSDateToTicksWithPadding", () => {
|
||||
it("should convert JS Date to ticks for date time 1", () => {
|
||||
const time = DateTimeUtilities.convertJSDateToTicksWithPadding(testDateTime1.toISOString());
|
||||
expect(time).toBe(testTicks1);
|
||||
});
|
||||
it("should convert JS Date to ticks for date time 2", () => {
|
||||
const time = DateTimeUtilities.convertJSDateToTicksWithPadding(testDateTime2.toISOString());
|
||||
expect(time).toBe(testTicks2);
|
||||
});
|
||||
});
|
||||
});
|
||||
67
src/Explorer/Tables/QueryBuilder/DateTimeUtilities.ts
Normal file
67
src/Explorer/Tables/QueryBuilder/DateTimeUtilities.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
const epochTicks = 621355968000000000;
|
||||
const ticksPerMillisecond = 10000;
|
||||
|
||||
export function getLocalDateTime(dateTime: string): string {
|
||||
var dateTimeObject: Date = new Date(dateTime);
|
||||
var year: number = dateTimeObject.getFullYear();
|
||||
var month: string = ensureDoubleDigits(dateTimeObject.getMonth() + 1); // Month ranges from 0 to 11
|
||||
var day: string = ensureDoubleDigits(dateTimeObject.getDate());
|
||||
var hours: string = ensureDoubleDigits(dateTimeObject.getHours());
|
||||
var minutes: string = ensureDoubleDigits(dateTimeObject.getMinutes());
|
||||
var seconds: string = ensureDoubleDigits(dateTimeObject.getSeconds());
|
||||
var milliseconds: string = ensureTripleDigits(dateTimeObject.getMilliseconds());
|
||||
|
||||
var localDateTime: string = `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}`;
|
||||
return localDateTime;
|
||||
}
|
||||
|
||||
export function getUTCDateTime(dateTime: string): string {
|
||||
var dateTimeObject: Date = new Date(dateTime);
|
||||
return dateTimeObject.toISOString();
|
||||
}
|
||||
|
||||
export function ensureDoubleDigits(num: number): string {
|
||||
var doubleDigitsString: string = num.toString();
|
||||
if (num < 10) {
|
||||
doubleDigitsString = `0${doubleDigitsString}`;
|
||||
} else if (num > 99) {
|
||||
doubleDigitsString = doubleDigitsString.substring(0, 2);
|
||||
}
|
||||
return doubleDigitsString;
|
||||
}
|
||||
|
||||
export function ensureTripleDigits(num: number): string {
|
||||
var tripleDigitsString: string = num.toString();
|
||||
if (num < 10) {
|
||||
tripleDigitsString = `00${tripleDigitsString}`;
|
||||
} else if (num < 100) {
|
||||
tripleDigitsString = `0${tripleDigitsString}`;
|
||||
} else if (num > 999) {
|
||||
tripleDigitsString = tripleDigitsString.substring(0, 3);
|
||||
}
|
||||
return tripleDigitsString;
|
||||
}
|
||||
|
||||
export function convertUnixToJSDate(unixTime: number): Date {
|
||||
return new Date(unixTime * 1000);
|
||||
}
|
||||
|
||||
export function convertJSDateToUnix(dateTime: string): number {
|
||||
return Number((new Date(dateTime).getTime() / 1000).toFixed(0));
|
||||
}
|
||||
|
||||
export function convertTicksToJSDate(ticks: string): Date {
|
||||
var ticksJSBased = Number(ticks) - epochTicks;
|
||||
var timeInMillisecond = ticksJSBased / ticksPerMillisecond;
|
||||
return new Date(timeInMillisecond);
|
||||
}
|
||||
|
||||
export function convertJSDateToTicksWithPadding(dateTime: string): string {
|
||||
var ticks = epochTicks + new Date(dateTime).getTime() * ticksPerMillisecond;
|
||||
return padDateTicksWithZeros(ticks.toString());
|
||||
}
|
||||
|
||||
function padDateTicksWithZeros(value: string): string {
|
||||
var s = "0000000000000000000" + value;
|
||||
return s.substr(s.length - 20);
|
||||
}
|
||||
796
src/Explorer/Tables/QueryBuilder/QueryBuilderViewModel.ts
Normal file
796
src/Explorer/Tables/QueryBuilder/QueryBuilderViewModel.ts
Normal file
@@ -0,0 +1,796 @@
|
||||
import * as ko from "knockout";
|
||||
import * as CustomTimestampHelper from "./CustomTimestampHelper";
|
||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||
import ClauseGroup from "./ClauseGroup";
|
||||
import ClauseGroupViewModel from "./ClauseGroupViewModel";
|
||||
import QueryViewModel from "./QueryViewModel";
|
||||
import * as Constants from "../Constants";
|
||||
import TableEntityListViewModel from "../DataTable/TableEntityListViewModel";
|
||||
import * as DateTimeUtilities from "./DateTimeUtilities";
|
||||
import * as DataTableUtilities from "../DataTable/DataTableUtilities";
|
||||
import * as TableEntityProcessor from "../TableEntityProcessor";
|
||||
import * as Utilities from "../Utilities";
|
||||
import { KeyCodes } from "../../../Common/Constants";
|
||||
|
||||
export default class QueryBuilderViewModel {
|
||||
/* Labels */
|
||||
public andLabel = "And/Or"; // localize
|
||||
public actionLabel = "Action"; // localize
|
||||
public fieldLabel = "Field"; // localize
|
||||
public dataTypeLabel = "Type"; // localize
|
||||
public operatorLabel = "Operator"; // localize
|
||||
public valueLabel = "Value"; // localize
|
||||
|
||||
/* controls */
|
||||
public addNewClauseLine = "Add new clause"; // localize
|
||||
public insertNewFilterLine = "Insert new filter line"; // localize
|
||||
public removeThisFilterLine = "Remove this filter line"; // localize
|
||||
public groupSelectedClauses = "Group selected clauses"; // localize
|
||||
public clauseArray = ko.observableArray<QueryClauseViewModel>(); // This is for storing the clauses in flattened form queryClauses for easier UI data binding.
|
||||
public queryClauses = new ClauseGroup(true, null); // The actual data structure containing the clause information.
|
||||
public columnOptions: ko.ObservableArray<string>;
|
||||
public canGroupClauses = ko.observable<boolean>(false);
|
||||
|
||||
/* Observables */
|
||||
public edmTypes = ko.observableArray([
|
||||
Constants.TableType.String,
|
||||
Constants.TableType.Boolean,
|
||||
Constants.TableType.Binary,
|
||||
Constants.TableType.DateTime,
|
||||
Constants.TableType.Double,
|
||||
Constants.TableType.Guid,
|
||||
Constants.TableType.Int32,
|
||||
Constants.TableType.Int64,
|
||||
""
|
||||
]);
|
||||
public operators = ko.observableArray([
|
||||
Constants.Operator.Equal,
|
||||
Constants.Operator.GreaterThan,
|
||||
Constants.Operator.GreaterThanOrEqualTo,
|
||||
Constants.Operator.LessThan,
|
||||
Constants.Operator.LessThanOrEqualTo,
|
||||
Constants.Operator.NotEqualTo,
|
||||
""
|
||||
]);
|
||||
public clauseRules = ko.observableArray([Constants.ClauseRule.And, Constants.ClauseRule.Or]);
|
||||
public timeOptions = ko.observableArray([
|
||||
Constants.timeOptions.lastHour,
|
||||
Constants.timeOptions.last24Hours,
|
||||
Constants.timeOptions.last7Days,
|
||||
Constants.timeOptions.last31Days,
|
||||
Constants.timeOptions.last365Days,
|
||||
Constants.timeOptions.currentMonth,
|
||||
Constants.timeOptions.currentYear
|
||||
//Constants.timeOptions.custom
|
||||
]);
|
||||
public queryString = ko.observable<string>();
|
||||
private _queryViewModel: QueryViewModel;
|
||||
public tableEntityListViewModel: TableEntityListViewModel;
|
||||
private scrollEventListener: boolean;
|
||||
|
||||
constructor(queryViewModel: QueryViewModel, tableEntityListViewModel: TableEntityListViewModel) {
|
||||
if (tableEntityListViewModel.queryTablesTab.container.isPreferredApiCassandra()) {
|
||||
this.edmTypes([
|
||||
Constants.CassandraType.Text,
|
||||
Constants.CassandraType.Ascii,
|
||||
Constants.CassandraType.Bigint,
|
||||
Constants.CassandraType.Blob,
|
||||
Constants.CassandraType.Boolean,
|
||||
Constants.CassandraType.Decimal,
|
||||
Constants.CassandraType.Double,
|
||||
Constants.CassandraType.Float,
|
||||
Constants.CassandraType.Int,
|
||||
Constants.CassandraType.Uuid,
|
||||
Constants.CassandraType.Varchar,
|
||||
Constants.CassandraType.Varint,
|
||||
Constants.CassandraType.Inet,
|
||||
Constants.CassandraType.Smallint,
|
||||
Constants.CassandraType.Tinyint
|
||||
]);
|
||||
this.clauseRules([
|
||||
Constants.ClauseRule.And
|
||||
// OR is not supported in CQL
|
||||
]);
|
||||
this.andLabel = "And";
|
||||
}
|
||||
this.clauseArray();
|
||||
|
||||
this._queryViewModel = queryViewModel;
|
||||
this.tableEntityListViewModel = tableEntityListViewModel;
|
||||
this.columnOptions = ko.observableArray<string>(queryViewModel.columnOptions());
|
||||
|
||||
this.columnOptions.subscribe(newColumnOptions => {
|
||||
queryViewModel.columnOptions(newColumnOptions);
|
||||
});
|
||||
}
|
||||
|
||||
public setExample() {
|
||||
var example1 = new QueryClauseViewModel(
|
||||
this,
|
||||
"",
|
||||
"PartitionKey",
|
||||
this.edmTypes()[0],
|
||||
Constants.Operator.Equal,
|
||||
this.tableEntityListViewModel.items()[0].PartitionKey._,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
//null,
|
||||
true
|
||||
);
|
||||
var example2 = new QueryClauseViewModel(
|
||||
this,
|
||||
"And",
|
||||
"RowKey",
|
||||
this.edmTypes()[0],
|
||||
Constants.Operator.Equal,
|
||||
this.tableEntityListViewModel.items()[0].RowKey._,
|
||||
true,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
//null,
|
||||
true
|
||||
);
|
||||
this.addClauseImpl(example1, 0);
|
||||
this.addClauseImpl(example2, 1);
|
||||
}
|
||||
|
||||
public getODataFilterFromClauses = (): string => {
|
||||
var filterString: string = "";
|
||||
var treeTraversal = (group: ClauseGroup): void => {
|
||||
for (var i = 0; i < group.children.length; i++) {
|
||||
var currentItem = group.children[i];
|
||||
|
||||
if (currentItem instanceof QueryClauseViewModel) {
|
||||
var clause = <QueryClauseViewModel>currentItem;
|
||||
this.timestampToValue(clause);
|
||||
filterString = filterString.concat(
|
||||
this.constructODataClause(
|
||||
filterString === "" ? "" : clause.and_or(),
|
||||
this.generateLeftParentheses(clause),
|
||||
clause.field(),
|
||||
clause.type(),
|
||||
clause.operator(),
|
||||
clause.value(),
|
||||
this.generateRightParentheses(clause)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
treeTraversal(<ClauseGroup>currentItem);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
treeTraversal(this.queryClauses);
|
||||
|
||||
return filterString.trim();
|
||||
};
|
||||
|
||||
public getSqlFilterFromClauses = (): string => {
|
||||
var filterString: string = "SELECT * FROM c";
|
||||
if (this._queryViewModel.selectText() && this._queryViewModel.selectText().length > 0) {
|
||||
filterString = "SELECT";
|
||||
const selectText = this._queryViewModel && this._queryViewModel.selectText && this._queryViewModel.selectText();
|
||||
selectText &&
|
||||
selectText.forEach((value: string) => {
|
||||
if (value === Constants.EntityKeyNames.PartitionKey) {
|
||||
value = `["${TableEntityProcessor.keyProperties.PartitionKey}"]`;
|
||||
filterString = filterString.concat(filterString === "SELECT" ? " c" : ", c");
|
||||
} else if (value === Constants.EntityKeyNames.RowKey) {
|
||||
value = `["${TableEntityProcessor.keyProperties.Id2}"]`;
|
||||
filterString = filterString.concat(filterString === "SELECT" ? " c" : ", c");
|
||||
} else {
|
||||
if (value === Constants.EntityKeyNames.Timestamp) {
|
||||
value = TableEntityProcessor.keyProperties.Timestamp;
|
||||
}
|
||||
filterString = filterString.concat(filterString === "SELECT" ? " c." : ", c.");
|
||||
}
|
||||
filterString = filterString.concat(value);
|
||||
});
|
||||
filterString = filterString.concat(" FROM c");
|
||||
}
|
||||
if (this.queryClauses.children.length === 0) {
|
||||
return filterString;
|
||||
}
|
||||
filterString = filterString.concat(" WHERE");
|
||||
var first = true;
|
||||
var treeTraversal = (group: ClauseGroup): void => {
|
||||
for (var i = 0; i < group.children.length; i++) {
|
||||
var currentItem = group.children[i];
|
||||
|
||||
if (currentItem instanceof QueryClauseViewModel) {
|
||||
var clause = <QueryClauseViewModel>currentItem;
|
||||
let timeStampValue: string = this.timestampToSqlValue(clause);
|
||||
var value = clause.value();
|
||||
if (!clause.isValue()) {
|
||||
value = timeStampValue;
|
||||
}
|
||||
filterString = filterString.concat(
|
||||
this.constructSqlClause(
|
||||
first ? "" : clause.and_or(),
|
||||
this.generateLeftParentheses(clause),
|
||||
clause.field(),
|
||||
clause.type(),
|
||||
clause.operator(),
|
||||
value,
|
||||
this.generateRightParentheses(clause)
|
||||
)
|
||||
);
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
treeTraversal(<ClauseGroup>currentItem);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
treeTraversal(this.queryClauses);
|
||||
|
||||
return filterString.trim();
|
||||
};
|
||||
|
||||
public getCqlFilterFromClauses = (): string => {
|
||||
const databaseId = this._queryViewModel.queryTablesTab.collection.databaseId;
|
||||
const collectionId = this._queryViewModel.queryTablesTab.collection.id();
|
||||
const tableToQuery = `${databaseId}.${collectionId}`;
|
||||
var filterString: string = `SELECT * FROM ${tableToQuery}`;
|
||||
if (this._queryViewModel.selectText() && this._queryViewModel.selectText().length > 0) {
|
||||
filterString = "SELECT";
|
||||
const selectText = this._queryViewModel && this._queryViewModel.selectText && this._queryViewModel.selectText();
|
||||
selectText &&
|
||||
selectText.forEach((value: string) => {
|
||||
filterString = filterString.concat(filterString === "SELECT" ? " " : ", ");
|
||||
filterString = filterString.concat(value);
|
||||
});
|
||||
filterString = filterString.concat(` FROM ${tableToQuery}`);
|
||||
}
|
||||
if (this.queryClauses.children.length === 0) {
|
||||
return filterString;
|
||||
}
|
||||
filterString = filterString.concat(" WHERE");
|
||||
var first = true;
|
||||
var treeTraversal = (group: ClauseGroup): void => {
|
||||
for (var i = 0; i < group.children.length; i++) {
|
||||
var currentItem = group.children[i];
|
||||
|
||||
if (currentItem instanceof QueryClauseViewModel) {
|
||||
var clause = <QueryClauseViewModel>currentItem;
|
||||
let timeStampValue: string = this.timestampToSqlValue(clause);
|
||||
var value = clause.value();
|
||||
if (!clause.isValue()) {
|
||||
value = timeStampValue;
|
||||
}
|
||||
filterString = filterString.concat(
|
||||
this.constructCqlClause(
|
||||
first ? "" : clause.and_or(),
|
||||
this.generateLeftParentheses(clause),
|
||||
clause.field(),
|
||||
clause.type(),
|
||||
clause.operator(),
|
||||
value,
|
||||
this.generateRightParentheses(clause)
|
||||
)
|
||||
);
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
treeTraversal(<ClauseGroup>currentItem);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
treeTraversal(this.queryClauses);
|
||||
|
||||
return filterString.trim();
|
||||
};
|
||||
|
||||
public updateColumnOptions = (): void => {
|
||||
let originalHeaders = this.columnOptions();
|
||||
let newHeaders = this.tableEntityListViewModel.headers;
|
||||
this.columnOptions(newHeaders.sort(DataTableUtilities.compareTableColumns));
|
||||
};
|
||||
|
||||
private generateLeftParentheses(clause: QueryClauseViewModel): string {
|
||||
var result = "";
|
||||
|
||||
if (clause.clauseGroup.isRootGroup || clause.clauseGroup.children.indexOf(clause) !== 0) {
|
||||
return result;
|
||||
} else {
|
||||
result = result.concat("(");
|
||||
}
|
||||
|
||||
var currentGroup: ClauseGroup = clause.clauseGroup;
|
||||
|
||||
while (
|
||||
!currentGroup.isRootGroup &&
|
||||
!currentGroup.parentGroup.isRootGroup &&
|
||||
currentGroup.parentGroup.children.indexOf(currentGroup) === 0
|
||||
) {
|
||||
result = result.concat("(");
|
||||
currentGroup = currentGroup.parentGroup;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private generateRightParentheses(clause: QueryClauseViewModel): string {
|
||||
var result = "";
|
||||
|
||||
if (
|
||||
clause.clauseGroup.isRootGroup ||
|
||||
clause.clauseGroup.children.indexOf(clause) !== clause.clauseGroup.children.length - 1
|
||||
) {
|
||||
return result;
|
||||
} else {
|
||||
result = result.concat(")");
|
||||
}
|
||||
|
||||
var currentGroup: ClauseGroup = clause.clauseGroup;
|
||||
|
||||
while (
|
||||
!currentGroup.isRootGroup &&
|
||||
!currentGroup.parentGroup.isRootGroup &&
|
||||
currentGroup.parentGroup.children.indexOf(currentGroup) === currentGroup.parentGroup.children.length - 1
|
||||
) {
|
||||
result = result.concat(")");
|
||||
currentGroup = currentGroup.parentGroup;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private constructODataClause = (
|
||||
clauseRule: string,
|
||||
leftParentheses: string,
|
||||
propertyName: string,
|
||||
type: string,
|
||||
operator: string,
|
||||
value: string,
|
||||
rightParentheses: string
|
||||
): string => {
|
||||
switch (type) {
|
||||
case Constants.TableType.DateTime:
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
||||
operator
|
||||
)} ${value}${rightParentheses}`;
|
||||
case Constants.TableType.String:
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
||||
operator
|
||||
)} \'${value}\'${rightParentheses}`;
|
||||
case Constants.TableType.Guid:
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
||||
operator
|
||||
)} guid\'${value}\'${rightParentheses}`;
|
||||
case Constants.TableType.Binary:
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
||||
operator
|
||||
)} binary\'${value}\'${rightParentheses}`;
|
||||
default:
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
||||
operator
|
||||
)} ${value}${rightParentheses}`;
|
||||
}
|
||||
};
|
||||
|
||||
private constructSqlClause = (
|
||||
clauseRule: string,
|
||||
leftParentheses: string,
|
||||
propertyName: string,
|
||||
type: string,
|
||||
operator: string,
|
||||
value: string,
|
||||
rightParentheses: string
|
||||
): string => {
|
||||
if (propertyName === Constants.EntityKeyNames.PartitionKey) {
|
||||
propertyName = TableEntityProcessor.keyProperties.PartitionKey;
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c["${propertyName}"] ${operator} \'${value}\'${rightParentheses}`;
|
||||
} else if (propertyName === Constants.EntityKeyNames.RowKey) {
|
||||
propertyName = TableEntityProcessor.keyProperties.Id;
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName} ${operator} \'${value}\'${rightParentheses}`;
|
||||
} else if (propertyName === Constants.EntityKeyNames.Timestamp) {
|
||||
propertyName = TableEntityProcessor.keyProperties.Timestamp;
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName} ${operator} ${DateTimeUtilities.convertJSDateToUnix(
|
||||
value
|
||||
)}${rightParentheses}`;
|
||||
}
|
||||
switch (type) {
|
||||
case Constants.TableType.DateTime:
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${DateTimeUtilities.convertJSDateToTicksWithPadding(
|
||||
value
|
||||
)}\'${rightParentheses}`;
|
||||
case Constants.TableType.Int64:
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${Utilities.padLongWithZeros(
|
||||
value
|
||||
)}\'${rightParentheses}`;
|
||||
case Constants.TableType.String:
|
||||
case Constants.TableType.Guid:
|
||||
case Constants.TableType.Binary:
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${value}\'${rightParentheses}`;
|
||||
default:
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} ${value}${rightParentheses}`;
|
||||
}
|
||||
};
|
||||
|
||||
private constructCqlClause = (
|
||||
clauseRule: string,
|
||||
leftParentheses: string,
|
||||
propertyName: string,
|
||||
type: string,
|
||||
operator: string,
|
||||
value: string,
|
||||
rightParentheses: string
|
||||
): string => {
|
||||
if (
|
||||
type === Constants.CassandraType.Text ||
|
||||
type === Constants.CassandraType.Inet ||
|
||||
type === Constants.CassandraType.Ascii ||
|
||||
type === Constants.CassandraType.Varchar
|
||||
) {
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses} ${propertyName} ${operator} \'${value}\'${rightParentheses}`;
|
||||
}
|
||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses} ${propertyName} ${operator} ${value}${rightParentheses}`;
|
||||
};
|
||||
|
||||
private operatorConverter = (operator: string): string => {
|
||||
switch (operator) {
|
||||
case Constants.Operator.Equal:
|
||||
return Constants.ODataOperator.EqualTo;
|
||||
case Constants.Operator.GreaterThan:
|
||||
return Constants.ODataOperator.GreaterThan;
|
||||
case Constants.Operator.GreaterThanOrEqualTo:
|
||||
return Constants.ODataOperator.GreaterThanOrEqualTo;
|
||||
case Constants.Operator.LessThan:
|
||||
return Constants.ODataOperator.LessThan;
|
||||
case Constants.Operator.LessThanOrEqualTo:
|
||||
return Constants.ODataOperator.LessThanOrEqualTo;
|
||||
case Constants.Operator.NotEqualTo:
|
||||
return Constants.ODataOperator.NotEqualTo;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
public groupClauses = (): void => {
|
||||
this.queryClauses.groupSelectedItems();
|
||||
this.updateClauseArray();
|
||||
this.updateCanGroupClauses();
|
||||
};
|
||||
|
||||
public addClauseIndex = (index: number, data: any): void => {
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
var newClause = new QueryClauseViewModel(
|
||||
this,
|
||||
"And",
|
||||
"",
|
||||
this.edmTypes()[0],
|
||||
Constants.Operator.EqualTo,
|
||||
"",
|
||||
true,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
//null,
|
||||
true
|
||||
);
|
||||
this.addClauseImpl(newClause, index);
|
||||
if (index === this.clauseArray().length - 1) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
this.updateCanGroupClauses();
|
||||
newClause.isAndOrFocused(true);
|
||||
$(window).resize();
|
||||
};
|
||||
|
||||
// adds a new clause to the end of the array
|
||||
public addNewClause = (): void => {
|
||||
this.addClauseIndex(this.clauseArray().length, null);
|
||||
};
|
||||
|
||||
public onAddClauseKeyDown = (index: number, data: any, event: KeyboardEvent, source: any): boolean => {
|
||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||
this.addClauseIndex(index, data);
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
public onAddNewClauseKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||
this.addClauseIndex(this.clauseArray().length - 1, null);
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
public deleteClause = (index: number, data: any): void => {
|
||||
this.deleteClauseImpl(index);
|
||||
if (this.clauseArray().length !== 0) {
|
||||
this.clauseArray()[0].and_or("");
|
||||
this.clauseArray()[0].canAnd(false);
|
||||
}
|
||||
this.updateCanGroupClauses();
|
||||
$(window).resize();
|
||||
};
|
||||
|
||||
public onDeleteClauseKeyDown = (index: number, data: any, event: KeyboardEvent, source: any): boolean => {
|
||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||
this.deleteClause(index, data);
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates an array of ClauseGroupViewModel objects for UI to display group information for this clause.
|
||||
* All clauses have the same number of ClauseGroupViewModel objects, which is the depth of the clause tree.
|
||||
* If the current clause is not the deepest in the tree, then the array will be filled by either a placeholder
|
||||
* (transparent) or its parent group view models.
|
||||
*/
|
||||
public getClauseGroupViewModels = (clause: QueryClauseViewModel): ClauseGroupViewModel[] => {
|
||||
var placeHolderGroupViewModel = new ClauseGroupViewModel(this.queryClauses, false, this);
|
||||
var treeDepth = this.queryClauses.getTreeDepth();
|
||||
var groupViewModels = new Array<ClauseGroupViewModel>(treeDepth);
|
||||
|
||||
// Prefill the arry with placeholders.
|
||||
for (var i = 0; i < groupViewModels.length; i++) {
|
||||
groupViewModels[i] = placeHolderGroupViewModel;
|
||||
}
|
||||
|
||||
var currentGroup = clause.clauseGroup;
|
||||
|
||||
// This function determines whether the path from clause to the current group is on the left most.
|
||||
var isLeftMostPath = (): boolean => {
|
||||
var group = clause.clauseGroup;
|
||||
|
||||
if (group.children.indexOf(clause) !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (group.getId() === currentGroup.getId()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (group.parentGroup.children.indexOf(group) !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
group = group.parentGroup;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// This function determines whether the path from clause to the current group is on the right most.
|
||||
var isRightMostPath = (): boolean => {
|
||||
var group = clause.clauseGroup;
|
||||
|
||||
if (group.children.indexOf(clause) !== group.children.length - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (group.getId() === currentGroup.getId()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (group.parentGroup.children.indexOf(group) !== group.parentGroup.children.length - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
group = group.parentGroup;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var vmIndex = groupViewModels.length - 1;
|
||||
var skipIndex = -1;
|
||||
var lastDepth = clause.groupDepth;
|
||||
|
||||
while (!currentGroup.isRootGroup) {
|
||||
// The current group will be rendered at least once, and if there are any sibling groups deeper
|
||||
// than the current group, we will repeat rendering the current group to fill up the gap between
|
||||
// current & deepest sibling.
|
||||
var deepestInSiblings = currentGroup.findDeepestGroupInChildren(skipIndex).getCurrentGroupDepth();
|
||||
// Find out the depth difference between the deepest group under the siblings of currentGroup and
|
||||
// the deepest group under currentGroup. If the result n is a positive number, it means there are
|
||||
// deeper groups in siblings and we need to draw n + 1 group blocks on UI to fill up the depth
|
||||
// differences. If the result n is a negative number, it means current group contains the deepest
|
||||
// sub-group, we only need to draw the group block once.
|
||||
var repeatCount = Math.max(deepestInSiblings - lastDepth, 0);
|
||||
|
||||
for (var i = 0; i <= repeatCount; i++) {
|
||||
var isLeftMost = isLeftMostPath();
|
||||
var isRightMost = isRightMostPath();
|
||||
var groupViewModel = new ClauseGroupViewModel(currentGroup, i === 0 && isLeftMost, this);
|
||||
|
||||
groupViewModel.showTopBorder(isLeftMost);
|
||||
groupViewModel.showBottomBorder(isRightMost);
|
||||
groupViewModel.showLeftBorder(i === repeatCount);
|
||||
groupViewModels[vmIndex] = groupViewModel;
|
||||
vmIndex--;
|
||||
}
|
||||
|
||||
skipIndex = currentGroup.parentGroup.children.indexOf(currentGroup);
|
||||
currentGroup = currentGroup.parentGroup;
|
||||
lastDepth = Math.max(deepestInSiblings, lastDepth);
|
||||
}
|
||||
|
||||
return groupViewModels;
|
||||
};
|
||||
|
||||
public runQuery = (): DataTables.DataTable => {
|
||||
return this._queryViewModel.runQuery();
|
||||
};
|
||||
|
||||
public addCustomRange(timestamp: CustomTimestampHelper.ITimestampQuery, clauseToAdd: QueryClauseViewModel): void {
|
||||
var index = this.clauseArray.peek().indexOf(clauseToAdd);
|
||||
|
||||
var newClause = new QueryClauseViewModel(
|
||||
this,
|
||||
//this._tableEntityListViewModel.tableExplorerContext.hostProxy,
|
||||
"And",
|
||||
clauseToAdd.field(),
|
||||
"DateTime",
|
||||
Constants.Operator.LessThan,
|
||||
"",
|
||||
true,
|
||||
Constants.timeOptions.custom,
|
||||
timestamp.endTime,
|
||||
"range",
|
||||
//null,
|
||||
true
|
||||
);
|
||||
|
||||
newClause.isLocal = ko.observable(timestamp.timeZone === "local");
|
||||
this.addClauseImpl(newClause, index + 1);
|
||||
|
||||
if (index + 1 === this.clauseArray().length - 1) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
private scrollToBottom(): void {
|
||||
var scrollBox = document.getElementById("scroll");
|
||||
if (!this.scrollEventListener) {
|
||||
scrollBox.addEventListener("scroll", function() {
|
||||
var translate = "translate(0," + this.scrollTop + "px)";
|
||||
const allTh = <NodeListOf<HTMLElement>>this.querySelectorAll("thead td");
|
||||
for (let i = 0; i < allTh.length; i++) {
|
||||
allTh[i].style.transform = translate;
|
||||
}
|
||||
});
|
||||
this.scrollEventListener = true;
|
||||
}
|
||||
var isScrolledToBottom = scrollBox.scrollHeight - scrollBox.clientHeight <= scrollBox.scrollHeight + 1;
|
||||
if (isScrolledToBottom) {
|
||||
scrollBox.scrollTop = scrollBox.scrollHeight - scrollBox.clientHeight;
|
||||
}
|
||||
}
|
||||
|
||||
private addClauseImpl(clause: QueryClauseViewModel, position: number): void {
|
||||
this.queryClauses.insertClauseBefore(clause, this.clauseArray()[position]);
|
||||
this.updateClauseArray();
|
||||
}
|
||||
|
||||
private deleteClauseImpl(index: number): void {
|
||||
var clause = this.clauseArray()[index];
|
||||
var previousClause = index === 0 ? 0 : index - 1;
|
||||
this.queryClauses.deleteClause(clause);
|
||||
this.updateClauseArray();
|
||||
if (this.clauseArray()[previousClause]) {
|
||||
this.clauseArray()[previousClause].isDeleteButtonFocused(true);
|
||||
}
|
||||
}
|
||||
|
||||
public updateCanGroupClauses(): void {
|
||||
this.canGroupClauses(this.queryClauses.canGroupSelectedItems());
|
||||
}
|
||||
|
||||
public updateClauseArray(): void {
|
||||
if (this.clauseArray().length > 0) {
|
||||
this.clauseArray()[0].canAnd(true);
|
||||
}
|
||||
|
||||
this.queryClauses.flattenClauses(this.clauseArray);
|
||||
|
||||
if (this.clauseArray().length > 0) {
|
||||
this.clauseArray()[0].canAnd(false);
|
||||
}
|
||||
|
||||
// Fix for 261924, forces the resize event so DataTableBindingManager will redo the calculation on table size.
|
||||
//DataTableUtilities.forceRecalculateTableSize();
|
||||
}
|
||||
|
||||
private timestampToValue(clause: QueryClauseViewModel): void {
|
||||
if (clause.isValue()) {
|
||||
return;
|
||||
} else if (clause.isTimestamp()) {
|
||||
this.getTimeStampToQuery(clause);
|
||||
// } else if (clause.isCustomLastTimestamp()) {
|
||||
// clause.value(`datetime'${CustomTimestampHelper._queryLastTime(clause.customLastTimestamp().lastNumber, clause.customLastTimestamp().lastTimeUnit)}'`);
|
||||
} else if (clause.isCustomRangeTimestamp()) {
|
||||
if (clause.isLocal()) {
|
||||
clause.value(`datetime'${DateTimeUtilities.getUTCDateTime(clause.customTimeValue())}'`);
|
||||
} else {
|
||||
clause.value(`datetime'${clause.customTimeValue()}Z'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private timestampToSqlValue(clause: QueryClauseViewModel): string {
|
||||
if (clause.isValue()) {
|
||||
return null;
|
||||
} else if (clause.isTimestamp()) {
|
||||
return this.getTimeStampToSqlQuery(clause);
|
||||
// } else if (clause.isCustomLastTimestamp()) {
|
||||
// clause.value(CustomTimestampHelper._queryLastTime(clause.customLastTimestamp().lastNumber, clause.customLastTimestamp().lastTimeUnit));
|
||||
} else if (clause.isCustomRangeTimestamp()) {
|
||||
if (clause.isLocal()) {
|
||||
return DateTimeUtilities.getUTCDateTime(clause.customTimeValue());
|
||||
} else {
|
||||
return clause.customTimeValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private getTimeStampToQuery(clause: QueryClauseViewModel): void {
|
||||
switch (clause.timeValue()) {
|
||||
case Constants.timeOptions.lastHour:
|
||||
clause.value(`datetime'${CustomTimestampHelper._queryLastDaysHours(0, 1)}'`);
|
||||
break;
|
||||
case Constants.timeOptions.last24Hours:
|
||||
clause.value(`datetime'${CustomTimestampHelper._queryLastDaysHours(0, 24)}'`);
|
||||
break;
|
||||
case Constants.timeOptions.last7Days:
|
||||
clause.value(`datetime'${CustomTimestampHelper._queryLastDaysHours(7, 0)}'`);
|
||||
break;
|
||||
case Constants.timeOptions.last31Days:
|
||||
clause.value(`datetime'${CustomTimestampHelper._queryLastDaysHours(31, 0)}'`);
|
||||
break;
|
||||
case Constants.timeOptions.last365Days:
|
||||
clause.value(`datetime'${CustomTimestampHelper._queryLastDaysHours(365, 0)}'`);
|
||||
break;
|
||||
case Constants.timeOptions.currentMonth:
|
||||
clause.value(`datetime'${CustomTimestampHelper._queryCurrentMonthLocal()}'`);
|
||||
break;
|
||||
case Constants.timeOptions.currentYear:
|
||||
clause.value(`datetime'${CustomTimestampHelper._queryCurrentYearLocal()}'`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private getTimeStampToSqlQuery(clause: QueryClauseViewModel): string {
|
||||
switch (clause.timeValue()) {
|
||||
case Constants.timeOptions.lastHour:
|
||||
return CustomTimestampHelper._queryLastDaysHours(0, 1);
|
||||
case Constants.timeOptions.last24Hours:
|
||||
return CustomTimestampHelper._queryLastDaysHours(0, 24);
|
||||
case Constants.timeOptions.last7Days:
|
||||
return CustomTimestampHelper._queryLastDaysHours(7, 0);
|
||||
case Constants.timeOptions.last31Days:
|
||||
return CustomTimestampHelper._queryLastDaysHours(31, 0);
|
||||
case Constants.timeOptions.last365Days:
|
||||
return CustomTimestampHelper._queryLastDaysHours(365, 0);
|
||||
case Constants.timeOptions.currentMonth:
|
||||
return CustomTimestampHelper._queryCurrentMonthLocal();
|
||||
case Constants.timeOptions.currentYear:
|
||||
return CustomTimestampHelper._queryCurrentYearLocal();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public checkIfClauseChanged(clause: QueryClauseViewModel): void {
|
||||
this._queryViewModel.checkIfBuilderChanged(clause);
|
||||
}
|
||||
}
|
||||
285
src/Explorer/Tables/QueryBuilder/QueryClauseViewModel.ts
Normal file
285
src/Explorer/Tables/QueryBuilder/QueryClauseViewModel.ts
Normal file
@@ -0,0 +1,285 @@
|
||||
import * as ko from "knockout";
|
||||
import _ from "underscore";
|
||||
import * as QueryBuilderConstants from "../Constants";
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import ClauseGroup from "./ClauseGroup";
|
||||
import * as Utilities from "../Utilities";
|
||||
|
||||
export default class QueryClauseViewModel {
|
||||
public checkedForGrouping: ko.Observable<boolean>;
|
||||
public isFirstInGroup: ko.Observable<boolean>;
|
||||
public clauseGroup: ClauseGroup;
|
||||
public and_or: ko.Observable<string>;
|
||||
public field: ko.Observable<string>;
|
||||
public type: ko.Observable<string>;
|
||||
public operator: ko.Observable<string>;
|
||||
public value: ko.Observable<any>;
|
||||
public timeValue: ko.Observable<string>;
|
||||
public customTimeValue: ko.Observable<string>;
|
||||
public canAnd: ko.Observable<boolean>;
|
||||
public timestampType: ko.Observable<string>;
|
||||
//public customLastTimestamp: ko.Observable<CustomTimestampHelper.ILastQuery>;
|
||||
public isLocal: ko.Observable<boolean>;
|
||||
public isOperaterEditable: ko.PureComputed<boolean>;
|
||||
public isTypeEditable: ko.PureComputed<boolean>;
|
||||
public isValue: ko.Observable<boolean>;
|
||||
public isTimestamp: ko.Observable<boolean>;
|
||||
public isCustomLastTimestamp: ko.Observable<boolean>;
|
||||
public isCustomRangeTimestamp: ko.Observable<boolean>;
|
||||
private _queryBuilderViewModel: QueryBuilderViewModel;
|
||||
private _groupCheckSubscription: ko.Subscription;
|
||||
private _id: string;
|
||||
public isAndOrFocused: ko.Observable<boolean>;
|
||||
public isDeleteButtonFocused: ko.Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
queryBuilderViewModel: QueryBuilderViewModel,
|
||||
and_or: string,
|
||||
field: string,
|
||||
type: string,
|
||||
operator: string,
|
||||
value: any,
|
||||
canAnd: boolean,
|
||||
timeValue: string,
|
||||
customTimeValue: string,
|
||||
timestampType: string,
|
||||
//customLastTimestamp: CustomTimestampHelper.ILastQuery,
|
||||
isLocal: boolean,
|
||||
id?: string
|
||||
) {
|
||||
this._queryBuilderViewModel = queryBuilderViewModel;
|
||||
this.checkedForGrouping = ko.observable<boolean>(false);
|
||||
this.isFirstInGroup = ko.observable<boolean>(false);
|
||||
this.and_or = ko.observable<string>(and_or);
|
||||
this.field = ko.observable<string>(field);
|
||||
this.type = ko.observable<string>(type);
|
||||
this.operator = ko.observable<string>(operator);
|
||||
this.value = ko.observable<string>(value);
|
||||
this.timeValue = ko.observable<string>(timeValue);
|
||||
this.customTimeValue = ko.observable<string>(customTimeValue);
|
||||
this.canAnd = ko.observable<boolean>(canAnd);
|
||||
this.isLocal = ko.observable<boolean>(isLocal);
|
||||
this._id = id ? id : Utilities.guid();
|
||||
|
||||
//this.customLastTimestamp = ko.observable<CustomTimestampHelper.ILastQuery>(customLastTimestamp);
|
||||
//this.setCustomLastTimestamp();
|
||||
|
||||
this.timestampType = ko.observable<string>(timestampType);
|
||||
this.getValueType();
|
||||
|
||||
this.isOperaterEditable = ko.pureComputed<boolean>(() => {
|
||||
const isPreferredApiCassandra = this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.container.isPreferredApiCassandra();
|
||||
const cassandraKeys = isPreferredApiCassandra
|
||||
? this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.collection.cassandraKeys.partitionKeys.map(
|
||||
key => key.property
|
||||
)
|
||||
: [];
|
||||
return (
|
||||
(this.isValue() || this.isCustomRangeTimestamp()) &&
|
||||
(!isPreferredApiCassandra || !_.contains(cassandraKeys, this.field()))
|
||||
);
|
||||
});
|
||||
this.isTypeEditable = ko.pureComputed<boolean>(
|
||||
() =>
|
||||
this.field() !== "Timestamp" &&
|
||||
this.field() !== "PartitionKey" &&
|
||||
this.field() !== "RowKey" &&
|
||||
!this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.container.isPreferredApiCassandra()
|
||||
);
|
||||
|
||||
this.and_or.subscribe(value => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this.field.subscribe(value => {
|
||||
this.changeField();
|
||||
});
|
||||
this.type.subscribe(value => {
|
||||
this.changeType();
|
||||
});
|
||||
this.timeValue.subscribe(value => {
|
||||
// if (this.timeValue() === QueryBuilderConstants.timeOptions.custom) {
|
||||
// this.customTimestampDialog();
|
||||
// }
|
||||
});
|
||||
this.customTimeValue.subscribe(value => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this.value.subscribe(value => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this.operator.subscribe(value => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this._groupCheckSubscription = this.checkedForGrouping.subscribe(value => {
|
||||
this._queryBuilderViewModel.updateCanGroupClauses();
|
||||
});
|
||||
this.isAndOrFocused = ko.observable<boolean>(false);
|
||||
this.isDeleteButtonFocused = ko.observable<boolean>(false);
|
||||
}
|
||||
|
||||
// private setCustomLastTimestamp() : void {
|
||||
// if (this.customLastTimestamp() === null) {
|
||||
// var lastNumberandType: CustomTimestampHelper.ILastQuery = {
|
||||
// lastNumber: 7,
|
||||
// lastTimeUnit: "Days"
|
||||
// };
|
||||
// this.customLastTimestamp(lastNumberandType);
|
||||
// }
|
||||
// }
|
||||
|
||||
private getValueType(): void {
|
||||
switch (this.timestampType()) {
|
||||
case "time":
|
||||
this.isValue = ko.observable<boolean>(false);
|
||||
this.isTimestamp = ko.observable<boolean>(true);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(false);
|
||||
break;
|
||||
case "last":
|
||||
this.isValue = ko.observable<boolean>(false);
|
||||
this.isTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(true);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(false);
|
||||
break;
|
||||
case "range":
|
||||
this.isValue = ko.observable<boolean>(false);
|
||||
this.isTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(true);
|
||||
break;
|
||||
default:
|
||||
this.isValue = ko.observable<boolean>(true);
|
||||
this.isTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(false);
|
||||
}
|
||||
}
|
||||
|
||||
private changeField(): void {
|
||||
this.isCustomLastTimestamp(false);
|
||||
this.isCustomRangeTimestamp(false);
|
||||
|
||||
if (this.field() === "Timestamp") {
|
||||
this.isValue(false);
|
||||
this.isTimestamp(true);
|
||||
this.type(QueryBuilderConstants.TableType.DateTime);
|
||||
this.operator(QueryBuilderConstants.Operator.GreaterThanOrEqualTo);
|
||||
this.timestampType("time");
|
||||
} else if (this.field() === "PartitionKey" || this.field() === "RowKey") {
|
||||
this.resetFromTimestamp();
|
||||
this.type(QueryBuilderConstants.TableType.String);
|
||||
} else {
|
||||
this.resetFromTimestamp();
|
||||
if (this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.container.isPreferredApiCassandra()) {
|
||||
const cassandraSchema = this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.collection
|
||||
.cassandraSchema;
|
||||
for (let i = 0, len = cassandraSchema.length; i < len; i++) {
|
||||
if (cassandraSchema[i].property === this.field()) {
|
||||
this.type(cassandraSchema[i].type);
|
||||
i = len;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.type(QueryBuilderConstants.TableType.String);
|
||||
}
|
||||
}
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
}
|
||||
|
||||
private resetFromTimestamp(): void {
|
||||
this.isValue(true);
|
||||
this.isTimestamp(false);
|
||||
this.operator(QueryBuilderConstants.Operator.Equal);
|
||||
this.value("");
|
||||
this.timestampType("");
|
||||
this.timeValue("");
|
||||
this.customTimeValue("");
|
||||
}
|
||||
|
||||
private changeType(): void {
|
||||
this.isCustomLastTimestamp(false);
|
||||
this.isCustomRangeTimestamp(false);
|
||||
|
||||
if (this.type() === QueryBuilderConstants.TableType.DateTime) {
|
||||
this.isValue(false);
|
||||
this.isTimestamp(true);
|
||||
this.operator(QueryBuilderConstants.Operator.GreaterThanOrEqualTo);
|
||||
this.timestampType("time");
|
||||
} else {
|
||||
this.isValue(true);
|
||||
this.isTimestamp(false);
|
||||
this.timeValue("");
|
||||
this.operator(QueryBuilderConstants.Operator.EqualTo);
|
||||
this.value("");
|
||||
this.timestampType("");
|
||||
this.timeValue("");
|
||||
this.customTimeValue("");
|
||||
}
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
}
|
||||
|
||||
// private customTimestampDialog(): Promise<any> {
|
||||
// var lastNumber = this.customLastTimestamp().lastNumber;
|
||||
// var lastTimeUnit = this.customLastTimestamp().lastTimeUnit;
|
||||
|
||||
// return this._host.executeOperation("Environment.openDialog", [{
|
||||
// id: AzureConstants.registeredDialogs.customTimestampQueryDialog,
|
||||
// width: 500,
|
||||
// height: 300,
|
||||
// parameters: { lastNumber, lastTimeUnit }
|
||||
// }]).then((timestamp: CustomTimestampHelper.ITimestampQuery) => {
|
||||
// if (timestamp) {
|
||||
// this.isValue(false);
|
||||
// this.isTimestamp(false);
|
||||
// this.timestampType(timestamp.queryType);
|
||||
|
||||
// if (timestamp.queryType === "last") {
|
||||
// this.isCustomLastTimestamp(true);
|
||||
// this.isCustomRangeTimestamp(false);
|
||||
|
||||
// var lastNumberandType: CustomTimestampHelper.ILastQuery = {
|
||||
// lastNumber: timestamp.lastNumber,
|
||||
// lastTimeUnit: timestamp.lastTimeUnit
|
||||
// };
|
||||
|
||||
// this.customLastTimestamp(lastNumberandType);
|
||||
// this.customTimeValue(`Last ${timestamp.lastNumber} ${timestamp.lastTimeUnit}`);
|
||||
|
||||
// } else {
|
||||
// if (timestamp.timeZone === "local") {
|
||||
// this.isLocal = ko.observable(true);
|
||||
// } else {
|
||||
// this.isLocal = ko.observable(false);
|
||||
// }
|
||||
// this.isCustomLastTimestamp(false);
|
||||
// this.isCustomRangeTimestamp(true);
|
||||
// this.customTimeValue(timestamp.startTime);
|
||||
// CustomTimestampHelper.addRangeTimestamp(timestamp, this._queryBuilderViewModel, this);
|
||||
// }
|
||||
// } else {
|
||||
// this.timeValue(QueryBuilderConstants.timeOptions.lastHour);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get groupDepth(): number {
|
||||
if (this.clauseGroup) {
|
||||
return this.clauseGroup.getCurrentGroupDepth();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this._groupCheckSubscription) {
|
||||
this._groupCheckSubscription.dispose();
|
||||
}
|
||||
|
||||
this.clauseGroup = null;
|
||||
this._queryBuilderViewModel = null;
|
||||
}
|
||||
}
|
||||
234
src/Explorer/Tables/QueryBuilder/QueryViewModel.ts
Normal file
234
src/Explorer/Tables/QueryBuilder/QueryViewModel.ts
Normal file
@@ -0,0 +1,234 @@
|
||||
import * as ko from "knockout";
|
||||
import * as _ from "underscore";
|
||||
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||
import TableEntityListViewModel from "../DataTable/TableEntityListViewModel";
|
||||
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
||||
import * as DataTableUtilities from "../DataTable/DataTableUtilities";
|
||||
import { KeyCodes } from "../../../Common/Constants";
|
||||
|
||||
export default class QueryViewModel {
|
||||
public topValueLimitMessage: string = "Please input a number between 0 and 1000.";
|
||||
public queryBuilderViewModel = ko.observable<QueryBuilderViewModel>();
|
||||
public isHelperActive = ko.observable<boolean>(true);
|
||||
public isEditorActive = ko.observable<boolean>(false);
|
||||
public isExpanded = ko.observable<boolean>(false);
|
||||
public isWarningBox = ko.observable<boolean>();
|
||||
public hasQueryError: ko.Computed<boolean>;
|
||||
public queryErrorMessage: ko.Computed<string>;
|
||||
public isSaveEnabled: ko.PureComputed<boolean>;
|
||||
public isExceedingLimit: ko.Computed<boolean>;
|
||||
public canRunQuery: ko.Computed<boolean>;
|
||||
public queryTextIsReadOnly: ko.Computed<boolean>;
|
||||
public queryText = ko.observable<string>();
|
||||
public topValue = ko.observable<number>();
|
||||
public selectText = ko.observableArray<string>();
|
||||
public unchangedText = ko.observable<string>();
|
||||
public unchangedSaveText = ko.observable<string>();
|
||||
public unchangedSaveTop = ko.observable<number>();
|
||||
public unchangedSaveSelect = ko.observableArray<string>();
|
||||
public focusTopResult: ko.Observable<boolean>;
|
||||
public focusExpandIcon: ko.Observable<boolean>;
|
||||
|
||||
public savedQueryName = ko.observable<string>();
|
||||
public selectMessage = ko.observable<string>();
|
||||
|
||||
public columnOptions: ko.ObservableArray<string>;
|
||||
|
||||
public queryTablesTab: QueryTablesTab;
|
||||
public id: string;
|
||||
private _tableEntityListViewModel: TableEntityListViewModel;
|
||||
|
||||
constructor(queryTablesTab: QueryTablesTab) {
|
||||
this.queryTablesTab = queryTablesTab;
|
||||
this.id = `queryViewModel${this.queryTablesTab.tabId}`;
|
||||
this._tableEntityListViewModel = queryTablesTab.tableEntityListViewModel();
|
||||
|
||||
this.queryTextIsReadOnly = ko.computed<boolean>(() => {
|
||||
return !this.queryTablesTab.container.isPreferredApiCassandra();
|
||||
});
|
||||
let initialOptions = this._tableEntityListViewModel.headers;
|
||||
this.columnOptions = ko.observableArray<string>(initialOptions);
|
||||
this.focusTopResult = ko.observable<boolean>(false);
|
||||
this.focusExpandIcon = ko.observable<boolean>(false);
|
||||
|
||||
this.queryBuilderViewModel(new QueryBuilderViewModel(this, this._tableEntityListViewModel));
|
||||
|
||||
this.isSaveEnabled = ko.pureComputed<boolean>(
|
||||
() =>
|
||||
this.queryText() !== this.unchangedSaveText() ||
|
||||
this.selectText() !== this.unchangedSaveSelect() ||
|
||||
this.topValue() !== this.unchangedSaveTop()
|
||||
);
|
||||
|
||||
this.queryBuilderViewModel().clauseArray.subscribe(value => {
|
||||
this.setFilter();
|
||||
});
|
||||
|
||||
this.isExceedingLimit = ko.computed<boolean>(() => {
|
||||
var currentTopValue: number = this.topValue();
|
||||
return currentTopValue < 0 || currentTopValue > 1000;
|
||||
});
|
||||
|
||||
this.canRunQuery = ko.computed<boolean>(() => {
|
||||
return !this.isExceedingLimit();
|
||||
});
|
||||
|
||||
this.hasQueryError = ko.computed<boolean>(() => {
|
||||
return !!this._tableEntityListViewModel.queryErrorMessage();
|
||||
});
|
||||
|
||||
this.queryErrorMessage = ko.computed<string>(() => {
|
||||
return this._tableEntityListViewModel.queryErrorMessage();
|
||||
});
|
||||
}
|
||||
|
||||
public selectHelper = (): void => {
|
||||
this.isHelperActive(true);
|
||||
this.isEditorActive(false);
|
||||
DataTableUtilities.forceRecalculateTableSize();
|
||||
};
|
||||
|
||||
public selectEditor = (): void => {
|
||||
this.setFilter();
|
||||
if (!this.isEditorActive()) {
|
||||
this.unchangedText(this.queryText());
|
||||
}
|
||||
this.isEditorActive(true);
|
||||
this.isHelperActive(false);
|
||||
DataTableUtilities.forceRecalculateTableSize();
|
||||
};
|
||||
|
||||
public toggleAdvancedOptions = () => {
|
||||
this.isExpanded(!this.isExpanded());
|
||||
if (this.isExpanded()) {
|
||||
this.focusTopResult(true);
|
||||
} else {
|
||||
this.focusExpandIcon(true);
|
||||
}
|
||||
DataTableUtilities.forceRecalculateTableSize(); // Fix for 261924, forces the resize event so DataTableBindingManager will redo the calculation on table size.
|
||||
};
|
||||
|
||||
public ontoggleAdvancedOptionsKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||
this.toggleAdvancedOptions();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
private _getSelectedResults = (): Array<string> => {
|
||||
return this.selectText();
|
||||
};
|
||||
|
||||
private setFilter = (): string => {
|
||||
var queryString = this.isEditorActive()
|
||||
? this.queryText()
|
||||
: this.queryTablesTab.container.isPreferredApiCassandra()
|
||||
? this.queryBuilderViewModel().getCqlFilterFromClauses()
|
||||
: this.queryBuilderViewModel().getODataFilterFromClauses();
|
||||
var filter = queryString;
|
||||
this.queryText(filter);
|
||||
return this.queryText();
|
||||
};
|
||||
|
||||
private setSqlFilter = (): string => {
|
||||
var filter = this.queryBuilderViewModel().getSqlFilterFromClauses();
|
||||
return filter;
|
||||
};
|
||||
|
||||
private setCqlFilter = (): string => {
|
||||
var filter = this.queryBuilderViewModel().getCqlFilterFromClauses();
|
||||
return filter;
|
||||
};
|
||||
|
||||
public isHelperEnabled = ko
|
||||
.computed<boolean>(() => {
|
||||
return (
|
||||
this.queryText() === this.unchangedText() ||
|
||||
this.queryText() === null ||
|
||||
this.queryText() === "" ||
|
||||
this.isHelperActive()
|
||||
);
|
||||
})
|
||||
.extend({
|
||||
notify: "always"
|
||||
});
|
||||
|
||||
public runQuery = (): DataTables.DataTable => {
|
||||
var filter = this.setFilter();
|
||||
if (filter && !this.queryTablesTab.container.isPreferredApiCassandra()) {
|
||||
filter = filter.replace(/"/g, "'");
|
||||
}
|
||||
var top = this.topValue();
|
||||
var selectOptions = this._getSelectedResults();
|
||||
var select = selectOptions;
|
||||
this._tableEntityListViewModel.tableQuery.filter = filter;
|
||||
this._tableEntityListViewModel.tableQuery.top = top;
|
||||
this._tableEntityListViewModel.tableQuery.select = select;
|
||||
this._tableEntityListViewModel.oDataQuery(filter);
|
||||
this._tableEntityListViewModel.sqlQuery(this.setSqlFilter());
|
||||
this._tableEntityListViewModel.cqlQuery(filter);
|
||||
|
||||
return this._tableEntityListViewModel.reloadTable(/*useSetting*/ false, /*resetHeaders*/ false);
|
||||
};
|
||||
|
||||
public clearQuery = (): DataTables.DataTable => {
|
||||
this.queryText(null);
|
||||
this.topValue(null);
|
||||
this.selectText(null);
|
||||
this.selectMessage("");
|
||||
// clears the queryBuilder and adds a new blank clause
|
||||
this.queryBuilderViewModel().queryClauses.removeAll();
|
||||
this.queryBuilderViewModel().addNewClause();
|
||||
this._tableEntityListViewModel.tableQuery.filter = null;
|
||||
this._tableEntityListViewModel.tableQuery.top = null;
|
||||
this._tableEntityListViewModel.tableQuery.select = null;
|
||||
this._tableEntityListViewModel.oDataQuery("");
|
||||
this._tableEntityListViewModel.sqlQuery("SELECT * FROM c");
|
||||
this._tableEntityListViewModel.cqlQuery(
|
||||
`SELECT * FROM ${this.queryTablesTab.collection.databaseId}.${this.queryTablesTab.collection.id()}`
|
||||
);
|
||||
return this._tableEntityListViewModel.reloadTable(false);
|
||||
};
|
||||
|
||||
public selectQueryOptions(): Promise<any> {
|
||||
this.queryTablesTab.container.querySelectPane.queryViewModel = this;
|
||||
this.queryTablesTab.container.querySelectPane.open();
|
||||
return null;
|
||||
}
|
||||
|
||||
public onselectQueryOptionsKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||
this.selectQueryOptions();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
public getSelectMessage(): void {
|
||||
if (_.isEmpty(this.selectText()) || this.selectText() === null) {
|
||||
this.selectMessage("");
|
||||
} else {
|
||||
this.selectMessage(`${this.selectText().length} of ${this.columnOptions().length} columns selected.`);
|
||||
}
|
||||
}
|
||||
|
||||
public isSelected = ko.computed<boolean>(() => {
|
||||
return !(_.isEmpty(this.selectText()) || this.selectText() === null);
|
||||
});
|
||||
|
||||
private setCheckToSave(): void {
|
||||
this.unchangedSaveText(this.setFilter());
|
||||
this.unchangedSaveTop(this.topValue());
|
||||
this.unchangedSaveSelect(this.selectText());
|
||||
this.isSaveEnabled(false);
|
||||
}
|
||||
|
||||
public checkIfBuilderChanged(clause: QueryClauseViewModel): void {
|
||||
this.setFilter();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user