Escape quotes in identifiers in CQL queries

This commit is contained in:
Armando Trejo Oliver 2020-10-12 11:00:11 -07:00 committed by GitHub
parent a9a57f4ba9
commit 5ffa746adb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 3 deletions

View File

@ -0,0 +1,18 @@
import { getQuotedCqlIdentifier } from "./CqlUtilities";
describe("getQuotedCqlIdentifier", () => {
it("undefined id", () => {
const result = getQuotedCqlIdentifier(undefined);
expect(result).toBe(undefined);
});
it("id with no quotes", () => {
const result = getQuotedCqlIdentifier("foo");
expect(result).toBe('"foo"');
});
it("id with quotes", () => {
const result = getQuotedCqlIdentifier('"foo"');
expect(result).toBe('"""foo"""');
});
});

View File

@ -0,0 +1,12 @@
export function getQuotedCqlIdentifier(identifier: string): string {
let result = identifier;
if (!identifier) {
return result;
}
if (identifier.includes('"')) {
result = identifier.replace(/"/g, '""');
}
return `"${result}"`;
}

View File

@ -6,6 +6,7 @@ import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
import { CassandraTableKey, CassandraAPIDataClient } from "../TableDataClient"; import { CassandraTableKey, CassandraAPIDataClient } from "../TableDataClient";
import DataTableViewModel from "./DataTableViewModel"; import DataTableViewModel from "./DataTableViewModel";
import * as DataTableUtilities from "./DataTableUtilities"; import * as DataTableUtilities from "./DataTableUtilities";
import { getQuotedCqlIdentifier } from "../CqlUtilities";
import TableCommands from "./TableCommands"; import TableCommands from "./TableCommands";
import TableEntityCache from "./TableEntityCache"; import TableEntityCache from "./TableEntityCache";
import * as Constants from "../Constants"; import * as Constants from "../Constants";
@ -57,7 +58,9 @@ export default class TableEntityListViewModel extends DataTableViewModel {
this.queryTablesTab = queryTablesTab; this.queryTablesTab = queryTablesTab;
this.id = `tableEntityListViewModel${this.queryTablesTab.tabId}`; this.id = `tableEntityListViewModel${this.queryTablesTab.tabId}`;
this.cqlQuery = ko.observable<string>( this.cqlQuery = ko.observable<string>(
`SELECT * FROM ${this.queryTablesTab.collection.databaseId}.${this.queryTablesTab.collection.id()}` `SELECT * FROM ${getQuotedCqlIdentifier(this.queryTablesTab.collection.databaseId)}.${getQuotedCqlIdentifier(
this.queryTablesTab.collection.id()
)}`
); );
this.oDataQuery = ko.observable<string>(); this.oDataQuery = ko.observable<string>();
this.sqlQuery = ko.observable<string>("SELECT * FROM c"); this.sqlQuery = ko.observable<string>("SELECT * FROM c");

View File

@ -1,5 +1,6 @@
import * as ko from "knockout"; import * as ko from "knockout";
import * as CustomTimestampHelper from "./CustomTimestampHelper"; import * as CustomTimestampHelper from "./CustomTimestampHelper";
import { getQuotedCqlIdentifier } from "../CqlUtilities";
import QueryClauseViewModel from "./QueryClauseViewModel"; import QueryClauseViewModel from "./QueryClauseViewModel";
import ClauseGroup from "./ClauseGroup"; import ClauseGroup from "./ClauseGroup";
import ClauseGroupViewModel from "./ClauseGroupViewModel"; import ClauseGroupViewModel from "./ClauseGroupViewModel";
@ -237,7 +238,7 @@ export default class QueryBuilderViewModel {
public getCqlFilterFromClauses = (): string => { public getCqlFilterFromClauses = (): string => {
const databaseId = this._queryViewModel.queryTablesTab.collection.databaseId; const databaseId = this._queryViewModel.queryTablesTab.collection.databaseId;
const collectionId = this._queryViewModel.queryTablesTab.collection.id(); const collectionId = this._queryViewModel.queryTablesTab.collection.id();
const tableToQuery = `${databaseId}.${collectionId}`; const tableToQuery = `${getQuotedCqlIdentifier(databaseId)}.${getQuotedCqlIdentifier(collectionId)}`;
var filterString: string = `SELECT * FROM ${tableToQuery}`; var filterString: string = `SELECT * FROM ${tableToQuery}`;
if (this._queryViewModel.selectText() && this._queryViewModel.selectText().length > 0) { if (this._queryViewModel.selectText() && this._queryViewModel.selectText().length > 0) {
filterString = "SELECT"; filterString = "SELECT";

View File

@ -7,6 +7,7 @@ import TableEntityListViewModel from "../DataTable/TableEntityListViewModel";
import QueryTablesTab from "../../Tabs/QueryTablesTab"; import QueryTablesTab from "../../Tabs/QueryTablesTab";
import * as DataTableUtilities from "../DataTable/DataTableUtilities"; import * as DataTableUtilities from "../DataTable/DataTableUtilities";
import { KeyCodes } from "../../../Common/Constants"; import { KeyCodes } from "../../../Common/Constants";
import { getQuotedCqlIdentifier } from "../CqlUtilities";
export default class QueryViewModel { export default class QueryViewModel {
public topValueLimitMessage: string = "Please input a number between 0 and 1000."; public topValueLimitMessage: string = "Please input a number between 0 and 1000.";
@ -189,7 +190,9 @@ export default class QueryViewModel {
this._tableEntityListViewModel.oDataQuery(""); this._tableEntityListViewModel.oDataQuery("");
this._tableEntityListViewModel.sqlQuery("SELECT * FROM c"); this._tableEntityListViewModel.sqlQuery("SELECT * FROM c");
this._tableEntityListViewModel.cqlQuery( this._tableEntityListViewModel.cqlQuery(
`SELECT * FROM ${this.queryTablesTab.collection.databaseId}.${this.queryTablesTab.collection.id()}` `SELECT * FROM ${getQuotedCqlIdentifier(this.queryTablesTab.collection.databaseId)}.${getQuotedCqlIdentifier(
this.queryTablesTab.collection.id()
)}`
); );
return this._tableEntityListViewModel.reloadTable(false); return this._tableEntityListViewModel.reloadTable(false);
}; };