This commit is contained in:
Steve Faulkner 2019-06-11 16:16:06 -04:00 коммит произвёл GitHub
Родитель 498b1ac734
Коммит fb6dd7982c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
26 изменённых файлов: 424 добавлений и 617 удалений

Просмотреть файл

@ -117,17 +117,14 @@ export class ChangeFeedIterator<T> {
feedOptions.initialHeaders[Constants.HttpHeaders.IfModifiedSince] = this.ifModifiedSince;
}
if (this.partitionKey !== undefined) {
feedOptions.partitionKey = this.partitionKey as any; // TODO: our partition key is too restrictive on the main object
}
const response: Response<Array<T & Resource>> = await (this.clientContext.queryFeed<T>({
path: this.resourceLink,
resourceType: ResourceType.item,
resourceId: this.resourceId,
resultFn: result => (result ? result.Documents : []),
query: undefined,
options: feedOptions
options: feedOptions,
partitionKey: this.partitionKey
}) as Promise<any>); // TODO: some funky issues with query feed. Probably need to change it up.
return new ChangeFeedResponse(

Просмотреть файл

@ -12,6 +12,7 @@ import { CosmosHeaders } from "./queryExecutionContext/CosmosHeaders";
import { QueryIterator } from "./queryIterator";
import { FeedOptions, RequestOptions, Response } from "./request";
import { ErrorResponse } from "./request";
import { PartitionedQueryExecutionInfo } from "./request/ErrorResponse";
import { getHeaders } from "./request/request";
import { RequestContext } from "./request/RequestContext";
import { request as executeRequest } from "./request/RequestHandler";
@ -86,7 +87,8 @@ export class ClientContext {
resultFn,
query,
options,
partitionKeyRangeId
partitionKeyRangeId,
partitionKey
}: {
path: string;
resourceType: ResourceType;
@ -99,6 +101,7 @@ export class ClientContext {
query: SqlQuerySpec | string;
options: FeedOptions;
partitionKeyRangeId?: string;
partitionKey?: PartitionKey;
}): Promise<Response<T & Resource>> {
// Query operations will use ReadEndpoint even though it uses
// GET(for queryFeed) and POST(for regular query operations)
@ -117,7 +120,7 @@ export class ClientContext {
options,
body: query,
plugins: this.cosmosClientOptions.plugins,
partitionKey: options.partitionKey
partitionKey
};
if (query !== undefined) {
@ -138,6 +141,45 @@ export class ClientContext {
return this.processQueryFeedResponse(response, !!query, resultFn);
}
public async getQueryPlan(
path: string,
resourceType: ResourceType,
resourceId: string,
query: SqlQuerySpec | string,
options: FeedOptions = {}
): Promise<Response<PartitionedQueryExecutionInfo>> {
const request: RequestContext = {
globalEndpointManager: this.globalEndpointManager,
requestAgent: this.cosmosClientOptions.agent,
connectionPolicy: this.connectionPolicy,
method: HTTPMethod.post,
path,
operationType: OperationType.Read,
client: this,
resourceId,
resourceType,
options,
body: query,
plugins: this.cosmosClientOptions.plugins
};
request.endpoint = await this.globalEndpointManager.resolveServiceEndpoint(request);
request.headers = await this.buildHeaders(request);
request.headers[Constants.HttpHeaders.IsQueryPlan] = "True";
request.headers[Constants.HttpHeaders.QueryVersion] = "1.4";
request.headers[Constants.HttpHeaders.SupportedQueryFeatures] =
"Aggregate, Distinct, MultipleOrderBy, OffsetAndLimit, OrderBy, Top, CompositeAggregate";
request.headers[Constants.HttpHeaders.ContentType] = Constants.MediaTypes.QueryJson;
if (typeof query === "string") {
request.body = { query }; // Converts query text to query object.
}
this.applySessionToken(request);
const response = await executeRequest(request);
this.captureSessionToken(undefined, path, OperationType.Query, response.headers);
return response as any;
}
public queryPartitionKeyRanges(collectionLink: string, query?: string | SqlQuerySpec, options?: FeedOptions) {
const path = getPathFromLink(collectionLink, ResourceType.pkranges);
const id = getIdFromLink(collectionLink);

Просмотреть файл

@ -7,8 +7,10 @@ import {
ResourceType
} from "../../common";
import { PartitionKeyDefinition } from "../../documents";
import { SqlQuerySpec } from "../../queryExecutionContext";
import { QueryIterator } from "../../queryIterator";
import { FeedOptions, RequestOptions, ResourceResponse } from "../../request";
import { FeedOptions, RequestOptions, ResourceResponse, Response } from "../../request";
import { PartitionedQueryExecutionInfo } from "../../request/ErrorResponse";
import { Conflict, Conflicts } from "../Conflict";
import { Database } from "../Database";
import { Item, Items } from "../Item";
@ -188,6 +190,11 @@ export class Container {
);
}
public async getQueryPlan(query: string | SqlQuerySpec): Promise<Response<PartitionedQueryExecutionInfo>> {
const path = getPathFromLink(this.url);
return this.clientContext.getQueryPlan(path + "/docs", ResourceType.item, getIdFromLink(this.url), query);
}
public readPartitionKeyRanges(feedOptions?: FeedOptions): QueryIterator<PartitionKeyRange> {
feedOptions = feedOptions || {};
return this.clientContext.queryPartitionKeyRanges(this.url, undefined, feedOptions);

Просмотреть файл

@ -60,8 +60,8 @@ export class Items {
* const {result: items} = await items.query<{firstName: string}>(querySpec).toArray();
* ```
*/
public query<T>(query: string | SqlQuerySpec, options?: FeedOptions): QueryIterator<T>;
public query<T>(query: string | SqlQuerySpec, options?: FeedOptions): QueryIterator<T> {
public query<T>(query: string | SqlQuerySpec, options: FeedOptions): QueryIterator<T>;
public query<T>(query: string | SqlQuerySpec, options: FeedOptions = {}): QueryIterator<T> {
const path = getPathFromLink(this.container.url, ResourceType.item);
const id = getIdFromLink(this.container.url);
@ -76,7 +76,7 @@ export class Items {
});
};
return new QueryIterator(this.clientContext, query, options, fetchFunction, this.container.url);
return new QueryIterator(this.clientContext, query, options, fetchFunction, this.container.url, ResourceType.item);
}
/**
@ -168,7 +168,7 @@ export class Items {
*/
public readAll<T extends ItemDefinition>(options?: FeedOptions): QueryIterator<T>;
public readAll<T extends ItemDefinition>(options?: FeedOptions): QueryIterator<T> {
return this.query<T>(undefined, options);
return this.query<T>("SELECT * from c", options);
}
/**

Просмотреть файл

@ -65,6 +65,9 @@ export const Constants = {
// Query
Query: "x-ms-documentdb-query",
IsQuery: "x-ms-documentdb-isquery",
IsQueryPlan: "x-ms-cosmos-is-query-plan-request",
SupportedQueryFeatures: "x-ms-cosmos-supported-query-features",
QueryVersion: "x-ms-cosmos-query-version",
// Our custom Azure Cosmos DB headers
Continuation: "x-ms-continuation",

Просмотреть файл

@ -217,30 +217,18 @@ export function isResourceValid(resource: any, err: any) {
}
/** @ignore */
export function getIdFromLink(resourceLink: string, isNameBased: boolean = true) {
if (isNameBased) {
resourceLink = trimSlashes(resourceLink);
return resourceLink;
} else {
return parseLink(resourceLink).objectBody.id.toLowerCase();
}
export function getIdFromLink(resourceLink: string) {
resourceLink = trimSlashes(resourceLink);
return resourceLink;
}
/** @ignore */
export function getPathFromLink(resourceLink: string, resourceType?: string, isNameBased: boolean = true) {
if (isNameBased) {
resourceLink = trimSlashes(resourceLink);
if (resourceType) {
return "/" + encodeURI(resourceLink) + "/" + resourceType;
} else {
return "/" + encodeURI(resourceLink);
}
export function getPathFromLink(resourceLink: string, resourceType?: string) {
resourceLink = trimSlashes(resourceLink);
if (resourceType) {
return "/" + encodeURI(resourceLink) + "/" + resourceType;
} else {
if (resourceType) {
return "/" + resourceLink + resourceType + "/";
} else {
return "/" + resourceLink;
}
return "/" + encodeURI(resourceLink);
}
}
export function isStringNullOrEmpty(inputString: string) {

Просмотреть файл

@ -10,6 +10,7 @@ export class AggregateEndpointComponent implements ExecutionContext {
private aggregateValues: any[];
private aggregateValuesIndex: number;
private localAggregators: any[];
private started: boolean;
/**
* Represents an endpoint in handling aggregate queries.
@ -50,31 +51,27 @@ export class AggregateEndpointComponent implements ExecutionContext {
this.aggregateValues = [];
this.aggregateValuesIndex = -1;
try {
const { result: resources, headers } = await this._getQueryResults();
const { result: resources, headers } = await this._getQueryResults();
resources.forEach((resource: any) => {
// TODO: any
this.localAggregators.forEach(aggregator => {
let itemValue;
// Get the value of the first property if it exists
if (resource && Object.keys(resource).length > 0) {
const key = Object.keys(resource)[0];
itemValue = resource[key];
}
aggregator.aggregate(itemValue);
});
});
// Get the aggregated results
resources.forEach((resource: any) => {
// TODO: any
this.localAggregators.forEach(aggregator => {
this.aggregateValues.push(aggregator.getResult());
let itemValue;
// Get the value of the first property if it exists
if (resource && Object.keys(resource).length > 0) {
const key = Object.keys(resource)[0];
itemValue = resource[key];
}
aggregator.aggregate(itemValue);
});
});
return { result: this.aggregateValues, headers };
} catch (err) {
throw err;
}
// Get the aggregated results
this.localAggregators.forEach(aggregator => {
this.aggregateValues.push(aggregator.getResult());
});
return { result: this.aggregateValues, headers };
}
/**
@ -82,18 +79,15 @@ export class AggregateEndpointComponent implements ExecutionContext {
* @ignore
*/
public async _getQueryResults(): Promise<Response<any>> {
try {
const { result: item, headers } = await this.executionContext.nextItem();
if (item === undefined) {
// no more results
return { result: this.toArrayTempResources, headers };
}
this.toArrayTempResources = this.toArrayTempResources.concat(item);
return this._getQueryResults();
} catch (err) {
throw err;
this.started = true;
const { result: item, headers } = await this.executionContext.nextItem();
if (item === undefined) {
// no more results
return { result: this.toArrayTempResources, headers };
}
this.toArrayTempResources = this.toArrayTempResources.concat(item);
return this._getQueryResults();
}
/**
@ -104,20 +98,16 @@ export class AggregateEndpointComponent implements ExecutionContext {
* the function takes two parameters error, element.
*/
public async nextItem(): Promise<Response<any>> {
try {
let resHeaders: CosmosHeaders;
if (this.aggregateValues === undefined) {
({ headers: resHeaders } = await this._getAggregateResult());
}
const resource =
this.aggregateValuesIndex < this.aggregateValues.length
? this.aggregateValues[++this.aggregateValuesIndex]
: undefined;
return { result: resource, headers: resHeaders };
} catch (err) {
throw err;
let resHeaders: CosmosHeaders;
if (this.aggregateValues === undefined) {
({ headers: resHeaders } = await this._getAggregateResult());
}
const resource =
this.aggregateValuesIndex < this.aggregateValues.length
? this.aggregateValues[++this.aggregateValuesIndex]
: undefined;
return { result: resource, headers: resHeaders };
}
/**
@ -149,6 +139,9 @@ export class AggregateEndpointComponent implements ExecutionContext {
* @returns {Boolean} true if there is other elements to process in the AggregateEndpointComponent.
*/
public hasMoreResults() {
return this.aggregateValues != null && this.aggregateValuesIndex < this.aggregateValues.length - 1;
if (!this.started) {
return true;
}
return !this.started && this.aggregateValues != null && this.aggregateValuesIndex < this.aggregateValues.length - 1;
}
}

Просмотреть файл

@ -10,4 +10,3 @@ export * from "./parallelQueryExecutionContextBase";
export * from "./parallelQueryExecutionContext";
export * from "./orderByQueryExecutionContext";
export * from "./pipelinedQueryExecutionContext";
export * from "./proxyQueryExecutionContext";

Просмотреть файл

@ -1,144 +0,0 @@
import { ClientContext } from "../ClientContext";
import { StatusCodes, SubStatusCodes } from "../common/statusCodes";
import { ErrorResponse, Response } from "../request";
import { PartitionedQueryExecutionInfo } from "../request/ErrorResponse";
import { DefaultQueryExecutionContext, FetchFunctionCallback } from "./defaultQueryExecutionContext";
import { ExecutionContext } from "./ExecutionContext";
import { PipelinedQueryExecutionContext } from "./pipelinedQueryExecutionContext";
import { SqlQuerySpec } from "./SqlQuerySpec";
/** @hidden */
export class ProxyQueryExecutionContext implements ExecutionContext {
private queryExecutionContext: ExecutionContext;
constructor(
private clientContext: ClientContext,
private query: SqlQuerySpec | string,
private options: any, // TODO: any options
private fetchFunctions: FetchFunctionCallback | FetchFunctionCallback[],
private resourceLink: string | string[]
) {
this.query = query;
this.fetchFunctions = fetchFunctions;
// clone options
this.options = JSON.parse(JSON.stringify(options || {}));
this.resourceLink = resourceLink;
this.queryExecutionContext = new DefaultQueryExecutionContext(this.options, this.fetchFunctions);
}
/**
* Execute a provided function on the next element in the ProxyQueryExecutionContext.
* @memberof ProxyQueryExecutionContext
* @instance
* @param {callback} callback - Function to execute for each element. \
* the function takes two parameters error, element.
*/
public async nextItem(): Promise<Response<any>> {
try {
const r = await this.queryExecutionContext.nextItem();
return r;
} catch (err) {
if (this._hasPartitionedExecutionInfo(err)) {
// if this's a partitioned execution info switches the execution context
const partitionedExecutionInfo = this._getParitionedExecutionInfo(err);
this.queryExecutionContext = this._createPipelinedExecutionContext(partitionedExecutionInfo);
try {
// TODO: recusion might be bad...
return this.nextItem();
} catch (e) {
throw e;
}
} else {
throw err;
}
}
}
private _createPipelinedExecutionContext(partitionedExecutionInfo: PartitionedQueryExecutionInfo) {
if (!this.resourceLink) {
throw new Error("for top/orderby resourceLink is required");
}
if (Array.isArray(this.resourceLink) && this.resourceLink.length !== 1) {
throw new Error("for top/orderby exactly one collectionLink is required");
}
const collectionLink = Array.isArray(this.resourceLink) ? this.resourceLink[0] : this.resourceLink;
return new PipelinedQueryExecutionContext(
this.clientContext,
collectionLink,
this.query,
this.options,
partitionedExecutionInfo
);
}
/**
* Retrieve the current element on the ProxyQueryExecutionContext.
* @memberof ProxyQueryExecutionContext
* @instance
* @param {callback} callback - Function to execute for the current element. \
* the function takes two parameters error, element.
*/
public async current(): Promise<Response<any>> {
try {
return await this.queryExecutionContext.current();
} catch (err) {
if (this._hasPartitionedExecutionInfo(err)) {
// if this's a partitioned execution info switches the execution context
const partitionedExecutionInfo = this._getParitionedExecutionInfo(err);
this.queryExecutionContext = this._createPipelinedExecutionContext(partitionedExecutionInfo);
// TODO: recursion
try {
return this.current();
} catch (e) {
throw e;
}
} else {
throw err;
}
}
}
/**
* Determine if there are still remaining resources to process.
* @memberof ProxyQueryExecutionContext
* @instance
* @returns {Boolean} true if there is other elements to process in the ProxyQueryExecutionContext.
*/
public hasMoreResults() {
return this.queryExecutionContext.hasMoreResults();
}
public async fetchMore(): Promise<Response<any>> {
try {
return await this.queryExecutionContext.fetchMore();
} catch (err) {
if (this._hasPartitionedExecutionInfo(err)) {
// if this's a partitioned execution info switches the execution context
const partitionedExecutionInfo = this._getParitionedExecutionInfo(err);
this.queryExecutionContext = this._createPipelinedExecutionContext(partitionedExecutionInfo);
try {
// TODO: maybe should move the others to use this pattern as it avoid the recursion issue.
return this.queryExecutionContext.fetchMore();
} catch (e) {
throw e;
}
} else {
throw err;
}
}
}
private _hasPartitionedExecutionInfo(error: ErrorResponse) {
return (
error.code === StatusCodes.BadRequest &&
"substatus" in error &&
error["substatus"] === SubStatusCodes.CrossPartitionQueryNotServable
);
}
private _getParitionedExecutionInfo(error: ErrorResponse) {
return error.body.additionalErrorInfo;
}
}

Просмотреть файл

@ -1,14 +1,18 @@
/// <reference lib="esnext.asynciterable" />
import { ClientContext } from "./ClientContext";
import { getPathFromLink, ResourceType, StatusCodes, SubStatusCodes } from "./common";
import {
CosmosHeaders,
DefaultQueryExecutionContext,
ExecutionContext,
FetchFunctionCallback,
getInitialHeader,
mergeHeaders,
ProxyQueryExecutionContext,
PipelinedQueryExecutionContext,
SqlQuerySpec
} from "./queryExecutionContext";
import { Response } from "./request";
import { ErrorResponse, PartitionedQueryExecutionInfo } from "./request/ErrorResponse";
import { FeedOptions } from "./request/FeedOptions";
import { FeedResponse } from "./request/FeedResponse";
@ -21,6 +25,7 @@ export class QueryIterator<T> {
private fetchAllTempResources: T[]; // TODO
private fetchAllLastResHeaders: CosmosHeaders;
private queryExecutionContext: ExecutionContext;
private queryPlanPromise: Promise<Response<PartitionedQueryExecutionInfo>>;
/**
* @hidden
*/
@ -29,14 +34,15 @@ export class QueryIterator<T> {
private query: SqlQuerySpec | string,
private options: FeedOptions,
private fetchFunctions: FetchFunctionCallback | FetchFunctionCallback[],
private resourceLink?: string
private resourceLink?: string,
private resourceType?: ResourceType
) {
this.query = query;
this.fetchFunctions = fetchFunctions;
this.options = options;
this.resourceLink = resourceLink;
this.queryExecutionContext = this.createQueryExecutionContext();
this.fetchAllLastResHeaders = getInitialHeader();
this.reset();
}
/**
@ -63,14 +69,25 @@ export class QueryIterator<T> {
*/
public async *getAsyncIterator(): AsyncIterable<FeedResponse<T>> {
this.reset();
this.queryPlanPromise = this.fetchQueryPlan();
while (this.queryExecutionContext.hasMoreResults()) {
const result = await this.queryExecutionContext.fetchMore();
let response: Response<any>;
try {
response = await this.queryExecutionContext.fetchMore();
} catch (error) {
if (this.needsQueryPlan(error)) {
await this.createPipelinedExecutionContext();
response = await this.queryExecutionContext.fetchMore();
} else {
throw error;
}
}
const feedResponse = new FeedResponse<T>(
result.result,
result.headers,
response.result,
response.headers,
this.queryExecutionContext.hasMoreResults()
);
if (result.result !== undefined) {
if (response.result !== undefined) {
yield feedResponse;
}
}
@ -103,7 +120,18 @@ export class QueryIterator<T> {
* before returning the first batch of responses.
*/
public async fetchNext(): Promise<FeedResponse<T>> {
const response = await this.queryExecutionContext.fetchMore();
this.queryPlanPromise = this.fetchQueryPlan();
let response: Response<any>;
try {
response = await this.queryExecutionContext.fetchMore();
} catch (error) {
if (this.needsQueryPlan(error)) {
await this.createPipelinedExecutionContext();
response = await this.queryExecutionContext.fetchMore();
} else {
throw error;
}
}
return new FeedResponse<T>(response.result, response.headers, this.queryExecutionContext.hasMoreResults());
}
@ -111,12 +139,26 @@ export class QueryIterator<T> {
* Reset the QueryIterator to the beginning and clear all the resources inside it
*/
public reset() {
this.queryExecutionContext = this.createQueryExecutionContext();
this.queryPlanPromise = undefined;
this.queryExecutionContext = new DefaultQueryExecutionContext(this.options, this.fetchFunctions);
}
private async toArrayImplementation(): Promise<FeedResponse<T>> {
this.queryPlanPromise = this.fetchQueryPlan();
while (this.queryExecutionContext.hasMoreResults()) {
const { result, headers } = await this.queryExecutionContext.nextItem();
let response: Response<any>;
try {
response = await this.queryExecutionContext.nextItem();
} catch (error) {
if (this.needsQueryPlan(error)) {
await this.createPipelinedExecutionContext();
response = await this.queryExecutionContext.nextItem();
} else {
throw error;
}
}
const { result, headers } = response;
// concatenate the results and fetch more
mergeHeaders(this.fetchAllLastResHeaders, headers);
@ -131,13 +173,40 @@ export class QueryIterator<T> {
);
}
private createQueryExecutionContext() {
return new ProxyQueryExecutionContext(
private async createPipelinedExecutionContext() {
const queryPlanResponse = await this.queryPlanPromise;
const queryPlan = queryPlanResponse.result;
const queryInfo = queryPlan.queryInfo;
if (queryInfo.aggregates.length > 0 && queryInfo.hasSelectValue === false) {
throw new Error("Aggregate queries must use the VALUE keyword");
}
this.queryExecutionContext = new PipelinedQueryExecutionContext(
this.clientContext,
this.resourceLink,
this.query,
this.options,
this.fetchFunctions,
this.resourceLink
queryPlan
);
}
private async fetchQueryPlan() {
if (!this.queryPlanPromise && this.resourceType === ResourceType.item) {
return this.clientContext.getQueryPlan(
getPathFromLink(this.resourceLink) + "/docs",
ResourceType.item,
this.resourceLink,
this.query,
this.options
);
}
return this.queryPlanPromise;
}
private needsQueryPlan(error: any): error is ErrorResponse {
return (
error.code === StatusCodes.BadRequest &&
error.substatus &&
error.substatus === SubStatusCodes.CrossPartitionQueryNotServable
);
}
}

Просмотреть файл

@ -28,6 +28,7 @@ interface QueryInfo {
aggregates?: any[];
rewrittenQuery?: any;
distinctType: string;
hasSelectValue: boolean;
}
export interface ErrorResponse extends Error {

Просмотреть файл

@ -1,4 +1,3 @@
import { PartitionKey } from "../documents";
import { SharedOptions } from "./SharedOptions";
/**
@ -7,14 +6,6 @@ import { SharedOptions } from "./SharedOptions";
export interface FeedOptions extends SharedOptions {
/** Opaque token for continuing the enumeration. */
continuation?: string;
/** Specifies a partition key definition for a particular path in the Azure Cosmos DB database service. */
partitionKey?: PartitionKey | PartitionKey[];
/**
* A value indicating whether users are enabled to send more than one request to execute the query in the Azure Cosmos DB database service.
*
* More than one request is necessary if the query is not scoped to single partition key value.
*/
enableCrossPartitionQuery?: boolean;
/** Allow scan on the queries which couldn't be served as indexing was opted out on the requested paths. */
enableScanInQuery?: boolean;
/**

Просмотреть файл

@ -71,15 +71,12 @@ async function httpRequest(requestContext: RequestContext) {
});
if (response.status >= 400) {
const errorResponse: ErrorResponse = new Error();
const errorResponse: ErrorResponse = new Error(result.message);
errorResponse.code = response.status;
errorResponse.body = result;
errorResponse.headers = headers;
if (result.additionalErrorInfo) {
errorResponse.body.additionalErrorInfo = JSON.parse(result.additionalErrorInfo);
}
if (Constants.HttpHeaders.ActivityId in headers) {
errorResponse.activityId = headers[Constants.HttpHeaders.ActivityId];
}

Просмотреть файл

@ -45,12 +45,12 @@ export async function getHeaders({
path,
resourceId,
resourceType,
options,
options = {},
partitionKeyRangeId,
useMultipleWriteLocations,
partitionKey
}: GetHeadersOptions): Promise<CosmosHeaders> {
const headers: CosmosHeaders = { ...defaultHeaders };
const headers: CosmosHeaders = { [Constants.HttpHeaders.EnableCrossPartitionQuery]: true, ...defaultHeaders };
if (useMultipleWriteLocations) {
headers[Constants.HttpHeaders.ALLOW_MULTIPLE_WRITES] = true;
@ -118,10 +118,6 @@ export async function getHeaders({
headers[Constants.HttpHeaders.EnableScanInQuery] = options.enableScanInQuery;
}
if (options.enableCrossPartitionQuery) {
headers[Constants.HttpHeaders.EnableCrossPartitionQuery] = options.enableCrossPartitionQuery;
}
if (options.populateQuotaInfo) {
headers[Constants.HttpHeaders.PopulateQuotaInfo] = options.populateQuotaInfo;
}

Просмотреть файл

@ -7,7 +7,7 @@ export class TestData {
public sum: number;
public docs: any[];
constructor(public partitionKey: string, public uniquePartitionKey: string) {
this.numberOfDocuments = 800;
this.numberOfDocuments = 50;
this.field = "field";
const docs = [];
@ -18,7 +18,7 @@ export class TestData {
docs.push(d);
}
this.numberOfDocsWithSamePartitionKey = 400;
this.numberOfDocsWithSamePartitionKey = 20;
for (let i = 0; i < this.numberOfDocsWithSamePartitionKey; ++i) {
const d: any = {};
d[partitionKey] = uniquePartitionKey;

Просмотреть файл

@ -43,7 +43,6 @@ describe("NodeJS CRUD Tests", function() {
await client.getDatabaseAccount({ abortSignal: signal });
assert.fail("Must throw when trying to connect to database");
} catch (err) {
// console.log(err);
assert.equal(err.name, "AbortError", "client should throw exception");
}
});

Просмотреть файл

@ -2,8 +2,8 @@ import assert from "assert";
import { Constants } from "../../dist-esm";
import { ContainerDefinition, Database } from "../../dist-esm/client";
import { ContainerRequest } from "../../dist-esm/client/Container/ContainerRequest";
import { DataType, Index, IndexedPath, IndexingMode, IndexingPolicy, IndexKind } from "../../dist-esm/documents";
import { getTestDatabase, removeAllDatabases } from "../common/TestHelpers";
import { DataType, IndexedPath, IndexingMode, IndexingPolicy, IndexKind } from "../../dist-esm/documents";
import { getTestDatabase, removeAllDatabases, getTestContainer } from "../common/TestHelpers";
describe("Containers", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 10000);

Просмотреть файл

@ -59,7 +59,7 @@ describe("Item CRUD", function() {
assert.equal(document.name, itemDefinition.name);
assert(document.id !== undefined);
// read documents after creation
const { resources: documents2 } = await container.items.readAll({ enableCrossPartitionQuery: true }).fetchAll();
const { resources: documents2 } = await container.items.readAll().fetchAll();
assert.equal(documents2.length, beforeCreateDocumentsCount + 1, "create should increase the number of documents");
// query documents
const querySpec = {
@ -71,13 +71,9 @@ describe("Item CRUD", function() {
}
]
};
const { resources: results } = await container.items
.query(querySpec, { enableCrossPartitionQuery: true })
.fetchAll();
const { resources: results } = await container.items.query(querySpec).fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
const { resources: results2 } = await container.items
.query(querySpec, { enableCrossPartitionQuery: true })
.fetchAll();
const { resources: results2 } = await container.items.query(querySpec).fetchAll();
assert(results2.length > 0, "number of results for the query should be > 0");
// replace document
@ -169,15 +165,8 @@ describe("Item CRUD", function() {
const querySpec = {
query: "SELECT * FROM Root"
};
try {
const { resources: badUpdate } = await container.items.query(querySpec, { enableScanInQuery: true }).fetchAll();
assert.fail("Must fail");
} catch (err) {
const badRequestErrorCode = 400;
assert.equal(err.code, badRequestErrorCode, "response should return error code " + badRequestErrorCode);
}
const { resources: results } = await container.items
.query<ItemDefinition>(querySpec, { enableScanInQuery: true, enableCrossPartitionQuery: true })
.query<ItemDefinition>(querySpec, { enableScanInQuery: true })
.fetchAll();
assert(results !== undefined, "error querying documents");
results.sort(function(doc1, doc2) {

Просмотреть файл

@ -73,13 +73,11 @@ describe("Non Partitioned Container", function() {
assert.equal(item4.newProp, newProp);
// read documents after creation
const { resources: documents } = await container.items.readAll({ enableCrossPartitionQuery: true }).fetchAll();
const { resources: documents } = await container.items.readAll().fetchAll();
assert.equal(documents.length, 2, "create should increase the number of documents");
// query documents
const { resources: results } = await container.items
.query("SELECT * FROM root r", { enableCrossPartitionQuery: true })
.fetchAll();
const { resources: results } = await container.items.query("SELECT * FROM root r").fetchAll();
assert(results.length === 2, "Container should contain two items");
// delete a document

Просмотреть файл

@ -12,83 +12,44 @@ if (!Symbol || !Symbol.asyncIterator) {
(Symbol as any).asyncIterator = Symbol.for("Symbol.asyncIterator");
}
describe("NodeJS CRUD Tests", function() {
describe("Queries", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 10000);
before(async function() {
await removeAllDatabases();
});
describe("Validate Queries CRUD", function() {
const queriesCRUDTest = async function() {
try {
// create a database
const database = await getTestDatabase("query test database");
// query databases
const querySpec0 = {
query: "SELECT * FROM root r WHERE r.id=@id",
parameters: [
{
name: "@id",
value: database.id
}
]
};
const { resources: results } = await client.databases.query(querySpec0).fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
const querySpec1 = {
query: "SELECT * FROM root r WHERE r.id='" + database.id + "'"
};
const { resources: results2 } = await client.databases.query(querySpec1).fetchAll();
assert(results2.length > 0, "number of results for the query should be > 0");
const querySpec2 = "SELECT * FROM root r WHERE r.id='" + database.id + "'";
const { resources: results3 } = await client.databases.query(querySpec2).fetchAll();
assert(results3.length > 0, "number of results for the query should be > 0");
} catch (err) {
throw err;
}
};
describe("Query CRUD", function() {
it("nativeApi Should do queries CRUD operations successfully name based", async function() {
try {
await queriesCRUDTest();
} catch (err) {
throw err;
}
});
});
describe("Validate QueryIterator Functionality For Multiple Partition container", function() {
const documentDefinitions = [
{ id: "document1" },
{ id: "document2", key: null, prop: 1 },
{ id: "document3", key: false, prop: 1 },
{ id: "document4", key: true, prop: 1 },
{ id: "document5", key: 1, prop: 1 },
{ id: "document6", key: "A", prop: 1 }
];
let container: Container;
// creates a new database, creates a new collecton, bulk inserts documents to the container
beforeEach(async function() {
const partitionKey = "key";
const containerDefinition = {
id: "coll1",
partitionKey: {
paths: ["/" + partitionKey]
}
// create a database
const database = await getTestDatabase("query test database");
// query databases
const querySpec0 = {
query: "SELECT * FROM root r WHERE r.id=@id",
parameters: [
{
name: "@id",
value: database.id
}
]
};
const containerOptions = { offerThroughput: 12000 };
container = await getTestContainer("query CRUD database 中文", client, containerDefinition, containerOptions);
await bulkInsertItems(container, documentDefinitions);
const { resources: results } = await client.databases.query(querySpec0).fetchAll();
assert(results.length > 0, "number of results for the query should be > 0");
const querySpec1 = {
query: "SELECT * FROM root r WHERE r.id='" + database.id + "'"
};
const { resources: results2 } = await client.databases.query(querySpec1).fetchAll();
assert(results2.length > 0, "number of results for the query should be > 0");
const querySpec2 = "SELECT * FROM root r WHERE r.id='" + database.id + "'";
const { resources: results3 } = await client.databases.query(querySpec2).fetchAll();
assert(results3.length > 0, "number of results for the query should be > 0");
});
});
describe("Validate QueryIterator Functionality", function() {
describe("QueryIterator", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 30000);
let resources: { container: Container; doc1: any; doc2: any; doc3: any };
beforeEach(async function() {
before(async function() {
const container = await getTestContainer("Validate QueryIterator Functionality", client);
const { resource: doc1 } = await container.items.create({ id: "doc1", prop1: "value1" });
const { resource: doc2 } = await container.items.create({ id: "doc2", prop1: "value2" });
@ -96,16 +57,16 @@ describe("NodeJS CRUD Tests", function() {
resources = { container, doc1, doc2, doc3 };
});
const queryIteratorToArrayTest = async function() {
it("toArray", async function() {
const queryIterator = resources.container.items.readAll({ maxItemCount: 2 });
const { resources: docs } = await queryIterator.fetchAll();
assert.equal(docs.length, 3, "queryIterator should return all documents using continuation");
assert.equal(docs[0].id, resources.doc1.id);
assert.equal(docs[1].id, resources.doc2.id);
assert.equal(docs[2].id, resources.doc3.id);
};
});
const queryIteratorAsyncIteratorTest = async function() {
it("asyncIterator", async function() {
const queryIterator = resources.container.items.readAll({ maxItemCount: 2 });
let counter = 0;
for await (const { resources: docs } of queryIterator.getAsyncIterator()) {
@ -118,10 +79,12 @@ describe("NodeJS CRUD Tests", function() {
counter++;
}
assert(counter === 2, "iterator should have run 3 times");
};
});
const queryIteratorExecuteNextTest = async function() {
let queryIterator = resources.container.items.readAll({ maxItemCount: 2 });
it("executeNext", async function() {
let queryIterator = resources.container.items.readAll({
maxItemCount: 2
});
const firstResponse = await queryIterator.fetchNext();
assert(firstResponse.requestCharge > 0, "RequestCharge has to be non-zero");
@ -135,24 +98,12 @@ describe("NodeJS CRUD Tests", function() {
// validate Iterator.executeNext with continuation token
queryIterator = resources.container.items.readAll({
maxItemCount: 2,
continuation: firstResponse.continuation as string
continuation: firstResponse.continuation
});
const secondResponse = await queryIterator.fetchNext();
assert(secondResponse.requestCharge > 0, "RequestCharge has to be non-zero");
assert.equal(secondResponse.resources.length, 1, "second batch size with continuation token is unexpected");
assert.equal(secondResponse.resources[0].id, resources.doc3.id, "second batch element should be doc3");
};
it("nativeApi validate QueryIterator iterator toArray name based", async function() {
await queryIteratorToArrayTest();
});
it("validate queryIterator asyncIterator", async function() {
await queryIteratorAsyncIteratorTest();
});
it("nativeApi validate queryIterator iterator executeNext name based", async function() {
await queryIteratorExecuteNextTest();
});
});
});

Просмотреть файл

@ -54,7 +54,7 @@ describe("Spatial Indexes", function() {
await createOrUpsertItem(container, location2, undefined, isUpsertTest);
const query =
"SELECT * FROM root WHERE (ST_DISTANCE(root.Location, {type: 'Point', coordinates: [20.1, 20]}) < 20000) ";
const { resources: results } = await container.items.query(query, { enableCrossPartitionQuery: true }).fetchAll();
const { resources: results } = await container.items.query(query).fetchAll();
assert.equal(1, results.length);
assert.equal("location1", results[0].id);
};

Просмотреть файл

@ -264,7 +264,7 @@ describe("Container TTL", function() {
// the upserted Item should be gone now after 10 secs from the last write(upsert) of the Item
await checkItemGone(container, upsertedItem);
const query = "SELECT * FROM root r";
const { resources: results } = await container.items.query(query, { enableCrossPartitionQuery: true }).fetchAll();
const { resources: results } = await container.items.query(query).fetchAll();
assert.equal(results.length, 0);
await container.replace({ id: container.id, partitionKey: containerResult.partitionKey });

Просмотреть файл

@ -1,5 +1,4 @@
import assert from "assert";
import * as util from "util";
import { Container, ContainerDefinition, Database } from "../../dist-esm/client";
import { DataType, IndexKind } from "../../dist-esm/documents";
import { QueryIterator } from "../../dist-esm/index";
@ -8,13 +7,12 @@ import { FeedOptions } from "../../dist-esm/request";
import { TestData } from "../common/TestData";
import { bulkInsertItems, getTestContainer, removeAllDatabases } from "../common/TestHelpers";
describe("NodeJS Aggregate Query Tests", async function() {
describe("Aggregate Query", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 20000);
const partitionKey = "key";
const uniquePartitionKey = "uniquePartitionKey";
const testdata = new TestData(partitionKey, uniquePartitionKey);
const documentDefinitions = testdata.docs;
let db: Database;
let container: Container;
const containerDefinition: ContainerDefinition = {
@ -43,220 +41,189 @@ describe("NodeJS Aggregate Query Tests", async function() {
const containerOptions = { offerThroughput: 10100 };
describe("Validate Aggregate Document Query", function() {
// - removes all the databases,
// - creates a new database,
// - creates a new collecton,
// - bulk inserts documents to the container
before(async function() {
await removeAllDatabases();
container = await getTestContainer(
"Validate Aggregate Document Query",
undefined,
containerDefinition,
containerOptions
);
db = container.database;
await bulkInsertItems(container, documentDefinitions);
before(async function() {
await removeAllDatabases();
container = await getTestContainer(
"Validate Aggregate Document Query",
undefined,
containerDefinition,
containerOptions
);
await bulkInsertItems(container, documentDefinitions);
});
const validateResult = function(actualValue: any, expectedValue: any) {
assert.deepEqual(actualValue, expectedValue, "actual value doesn't match with expected value.");
};
const validateToArray = async function(queryIterator: QueryIterator<any>, expectedResults: any) {
const { resources: results } = await queryIterator.fetchAll();
assert.equal(results.length, expectedResults.length, "invalid number of results");
assert.equal(queryIterator.hasMoreResults(), false, "hasMoreResults: no more results is left");
};
const validateExecuteNextAndHasMoreResults = async function(
queryIterator: QueryIterator<any>,
options: any,
expectedResults: any[]
) {
const pageSize = options["maxItemCount"];
const listOfResultPages: any[] = [];
let totalFetchedResults: any[] = [];
while (totalFetchedResults.length <= expectedResults.length) {
const { resources: results } = await queryIterator.fetchNext();
listOfResultPages.push(results);
if (results === undefined || totalFetchedResults.length === expectedResults.length) {
break;
}
totalFetchedResults = totalFetchedResults.concat(results);
if (totalFetchedResults.length < expectedResults.length) {
// there are more results
assert(results.length <= pageSize, "executeNext: invalid fetch block size");
assert.equal(results.length, pageSize, "executeNext: invalid fetch block size");
assert(queryIterator.hasMoreResults(), "hasMoreResults expects to return true");
} else {
// no more results
assert.equal(expectedResults.length, totalFetchedResults.length, "executeNext: didn't fetch all the results");
assert(results.length <= pageSize, "executeNext: actual fetch size is more than the requested page size");
}
}
// no more results
validateResult(totalFetchedResults, expectedResults);
assert.equal(queryIterator.hasMoreResults(), false, "hasMoreResults: no more results is left");
};
const ValidateAsyncIterator = async function(queryIterator: QueryIterator<any>, expectedResults: any[]) {
const results: any[] = [];
let completed = false;
// forEach uses callbacks still, so just wrap in a promise
for await (const { resources: items } of queryIterator.getAsyncIterator()) {
// if the previous invocation returned false, forEach must avoid invoking the callback again!
assert.equal(completed, false, "forEach called callback after the first false returned");
results.push(...items);
if (results.length === expectedResults.length) {
completed = true;
}
}
assert.equal(completed, true, "AsyncIterator should fetch expected number of results");
validateResult(results, expectedResults);
};
const executeQueryAndValidateResults = async function(query: string | SqlQuerySpec, expectedResults: any[]) {
const options: FeedOptions = { maxDegreeOfParallelism: 2, maxItemCount: 1 };
const queryIterator = container.items.query(query, options);
await validateToArray(queryIterator, expectedResults);
queryIterator.reset();
await validateExecuteNextAndHasMoreResults(queryIterator, options, expectedResults);
queryIterator.reset();
await ValidateAsyncIterator(queryIterator, expectedResults);
};
const generateTestConfigs = function() {
const testConfigs: any[] = [];
const aggregateConfigs = [
{
operator: "AVG",
expected: testdata.sum / testdata.numberOfDocumentsWithNumbericId,
condition: `IS_NUMBER(r.${partitionKey})`
},
{
operator: "COUNT",
expected: testdata.numberOfDocuments,
condition: "true"
},
{ operator: "MAX", expected: "xyz", condition: "true" },
{ operator: "MIN", expected: null, condition: "true" },
{
operator: "SUM",
expected: testdata.sum,
condition: `IS_NUMBER(r.${partitionKey})`
}
];
aggregateConfigs.forEach(function({ operator, condition, expected }) {
let query = `SELECT VALUE ${operator}(r.${partitionKey}) FROM r WHERE ${condition}`;
let testName = `${operator} ${condition}`;
testConfigs.push({
testName,
query,
expected
});
query = `SELECT VALUE ${operator}(r.${partitionKey}) FROM r WHERE ${condition} ORDER BY r.${partitionKey}`;
testName = `${operator} ${condition} OrderBy`;
testConfigs.push({
testName,
query,
expected
});
});
const validateResult = function(actualValue: any, expectedValue: any) {
assert.deepEqual(actualValue, expectedValue, "actual value doesn't match with expected value.");
};
const samePartitionSum =
(testdata.numberOfDocsWithSamePartitionKey * (testdata.numberOfDocsWithSamePartitionKey + 1)) / 2.0;
const aggregateSinglePartitionConfigs = [
{
operator: "AVG",
expected: samePartitionSum / testdata.numberOfDocsWithSamePartitionKey
},
{
operator: "COUNT",
expected: testdata.numberOfDocsWithSamePartitionKey
},
{
operator: "MAX",
expected: testdata.numberOfDocsWithSamePartitionKey
},
{ operator: "MIN", expected: 1 },
{ operator: "SUM", expected: samePartitionSum }
];
const validateToArray = async function(queryIterator: QueryIterator<any>, expectedResults: any) {
try {
const { resources: results } = await queryIterator.fetchAll();
assert.equal(results.length, expectedResults.length, "invalid number of results");
assert.equal(queryIterator.hasMoreResults(), false, "hasMoreResults: no more results is left");
} catch (err) {
throw err;
}
};
const validateExecuteNextAndHasMoreResults = async function(
queryIterator: QueryIterator<any>,
options: any,
expectedResults: any[]
) {
////////////////////////////////
// validate executeNext()
////////////////////////////////
const pageSize = options["maxItemCount"];
const listOfResultPages: any[] = [];
let totalFetchedResults: any[] = [];
try {
while (totalFetchedResults.length <= expectedResults.length) {
const { resources: results } = await queryIterator.fetchNext();
listOfResultPages.push(results);
if (results === undefined || totalFetchedResults.length === expectedResults.length) {
break;
}
totalFetchedResults = totalFetchedResults.concat(results);
if (totalFetchedResults.length < expectedResults.length) {
// there are more results
assert(results.length <= pageSize, "executeNext: invalid fetch block size");
assert.equal(results.length, pageSize, "executeNext: invalid fetch block size");
assert(queryIterator.hasMoreResults(), "hasMoreResults expects to return true");
} else {
// no more results
assert.equal(
expectedResults.length,
totalFetchedResults.length,
"executeNext: didn't fetch all the results"
);
assert(results.length <= pageSize, "executeNext: actual fetch size is more than the requested page size");
}
}
// no more results
validateResult(totalFetchedResults, expectedResults);
assert.equal(queryIterator.hasMoreResults(), false, "hasMoreResults: no more results is left");
} catch (err) {
throw err;
}
};
const ValidateAsyncIterator = async function(queryIterator: QueryIterator<any>, expectedResults: any[]) {
////////////////////////////////
// validate AsyncIterator()
////////////////////////////////
const results: any[] = [];
let completed = false;
// forEach uses callbacks still, so just wrap in a promise
for await (const { resources: items } of queryIterator.getAsyncIterator()) {
// if the previous invocation returned false, forEach must avoid invoking the callback again!
assert.equal(completed, false, "forEach called callback after the first false returned");
results.push(...items);
if (results.length === expectedResults.length) {
completed = true;
}
}
assert.equal(completed, true, "AsyncIterator should fetch expected number of results");
validateResult(results, expectedResults);
};
const executeQueryAndValidateResults = async function(query: string | SqlQuerySpec, expectedResults: any[]) {
const options: FeedOptions = { enableCrossPartitionQuery: true, maxDegreeOfParallelism: 2, maxItemCount: 1 };
const queryIterator = container.items.query(query, options);
await validateToArray(queryIterator, expectedResults);
queryIterator.reset();
await validateExecuteNextAndHasMoreResults(queryIterator, options, expectedResults);
queryIterator.reset();
await ValidateAsyncIterator(queryIterator, expectedResults);
};
const generateTestConfigs = function() {
const testConfigs: any[] = [];
const aggregateQueryFormat = "SELECT VALUE %s(r.%s) FROM r WHERE %s";
const aggregateOrderByQueryFormat = "SELECT VALUE %s(r.%s) FROM r WHERE %s ORDER BY r.%s";
const aggregateConfigs = [
{
operator: "AVG",
expected: testdata.sum / testdata.numberOfDocumentsWithNumbericId,
condition: util.format("IS_NUMBER(r.%s)", partitionKey)
},
{
operator: "COUNT",
expected: testdata.numberOfDocuments,
condition: "true"
},
{ operator: "MAX", expected: "xyz", condition: "true" },
{ operator: "MIN", expected: null, condition: "true" },
{
operator: "SUM",
expected: testdata.sum,
condition: util.format("IS_NUMBER(r.%s)", partitionKey)
}
];
aggregateConfigs.forEach(function(config) {
let query = util.format(aggregateQueryFormat, config.operator, partitionKey, config.condition);
let testName = util.format("%s %s", config.operator, config.condition);
testConfigs.push({
testName,
query,
expected: config.expected
});
query = util.format(aggregateOrderByQueryFormat, config.operator, partitionKey, config.condition, partitionKey);
testName = util.format("%s %s OrderBy", config.operator, config.condition);
testConfigs.push({
testName,
query,
expected: config.expected
});
aggregateSinglePartitionConfigs.forEach(function({ operator, expected }) {
const query = `SELECT VALUE ${operator}(r.${
testdata.field
}) FROM r WHERE r.${partitionKey} = '${uniquePartitionKey}'`;
let testName = `${operator} SinglePartition SELECT VALUE`;
testConfigs.push({
testName,
query,
expected
});
});
const aggregateSinglePartitionQueryFormat = "SELECT VALUE %s(r.%s) FROM r WHERE r.%s = '%s'";
const aggregateSinglePartitionQueryFormatSelect = "SELECT %s(r.%s) FROM r WHERE r.%s = '%s'";
const samePartitionSum =
(testdata.numberOfDocsWithSamePartitionKey * (testdata.numberOfDocsWithSamePartitionKey + 1)) / 2.0;
const aggregateSinglePartitionConfigs = [
{
operator: "AVG",
expected: samePartitionSum / testdata.numberOfDocsWithSamePartitionKey
},
{
operator: "COUNT",
expected: testdata.numberOfDocsWithSamePartitionKey
},
{
operator: "MAX",
expected: testdata.numberOfDocsWithSamePartitionKey
},
{ operator: "MIN", expected: 1 },
{ operator: "SUM", expected: samePartitionSum }
];
return testConfigs;
};
aggregateSinglePartitionConfigs.forEach(function(config) {
let query = util.format(
aggregateSinglePartitionQueryFormat,
config.operator,
testdata.field,
partitionKey,
uniquePartitionKey
);
let testName = util.format("%s SinglePartition %s", config.operator, "SELECT VALUE");
testConfigs.push({
testName,
query,
expected: config.expected
});
query = util.format(
aggregateSinglePartitionQueryFormatSelect,
config.operator,
testdata.field,
partitionKey,
uniquePartitionKey
);
testName = util.format("%s SinglePartition %s", config.operator, "SELECT");
testConfigs.push({
testName,
query,
expected: { $1: config.expected }
});
});
return testConfigs;
};
generateTestConfigs().forEach(function(test) {
it(test.testName, async function() {
try {
const expected = test.expected === undefined ? [] : [test.expected];
await executeQueryAndValidateResults(test.query, expected);
} catch (err) {
throw err;
}
});
generateTestConfigs().forEach(function(test) {
it(test.testName, async function() {
const expected = test.expected === undefined ? [] : [test.expected];
await executeQueryAndValidateResults(test.query, expected);
});
});
it("should error for non-VALUE queries", async () => {
try {
const queryIterator = container.items.query("SELECT SUM(r.key) from r WHERE IS_NUMBER(r.key)");
const response = await queryIterator.fetchAll();
assert.fail("Should throw an error");
} catch (error) {
assert(error);
}
});
it("should error for GROUP BY queries", async () => {
try {
const queryIterator = container.items.query("SELECT * from r GROUP BY r.key");
const response = await queryIterator.fetchAll();
assert.fail("Should throw an error");
} catch (error) {
assert(error);
}
});
});

Просмотреть файл

@ -208,7 +208,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2,
maxDegreeOfParallelism: 0
};
@ -224,7 +223,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2,
maxDegreeOfParallelism: -1,
populateQueryMetrics: true
@ -241,7 +239,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2,
maxDegreeOfParallelism: 1
};
@ -257,7 +254,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2,
maxDegreeOfParallelism: 3
};
@ -273,7 +269,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r order by r.spam";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2,
maxDegreeOfParallelism: 0
};
@ -290,7 +285,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r order by r.spam";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2,
maxDegreeOfParallelism: 1
};
@ -307,7 +301,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r order by r.spam";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2,
maxDegreeOfParallelism: 3
};
@ -324,7 +317,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r order by r.spam";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2,
maxDegreeOfParallelism: -1
};
@ -341,7 +333,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT DISTINCT VALUE r.spam3 FROM root r";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -353,7 +344,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT DISTINCT VALUE r.spam3 FROM root r order by r.spam3 DESC";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -367,7 +357,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT DISTINCT VALUE r.spam3 FROM root r order by r.spam3";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2,
maxDegreeOfParallelism: 3
};
@ -382,7 +371,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT DISTINCT VALUE r.spam3 FROM root r order by r.spam3";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 1
};
@ -396,7 +384,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT DISTINCT VALUE r.spam3 FROM root r order by r.spam3";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 20
};
@ -410,7 +397,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r order by r.spam";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -428,7 +414,6 @@ describe("Cross Partition", function() {
query: "SELECT * FROM root r order by r.spam"
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -450,7 +435,6 @@ describe("Cross Partition", function() {
query: "SELECT * FROM root r order by r.spam ASC"
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -472,7 +456,6 @@ describe("Cross Partition", function() {
query: "SELECT * FROM root r order by r.spam DESC"
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -498,7 +481,6 @@ describe("Cross Partition", function() {
query: util.format("SELECT top %d * FROM root r order by r.spam", topCount)
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -525,7 +507,6 @@ describe("Cross Partition", function() {
query: util.format("SELECT top %d * FROM root r order by r.spam", topCount)
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -548,7 +529,6 @@ describe("Cross Partition", function() {
const query = util.format("SELECT top %d * FROM root r", topCount);
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2,
maxDegreeOfParallelism: 3
};
@ -576,7 +556,6 @@ describe("Cross Partition", function() {
const query = util.format("SELECT top %d * FROM root r", topCount);
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -603,7 +582,6 @@ describe("Cross Partition", function() {
const query = util.format("SELECT top %d * FROM root r", topCount);
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -634,7 +612,6 @@ describe("Cross Partition", function() {
parameters: [{ name: "@n", value: topCount }]
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -665,7 +642,6 @@ describe("Cross Partition", function() {
parameters: [{ name: "@n", value: topCount }]
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -690,7 +666,6 @@ describe("Cross Partition", function() {
parameters: [{ name: "@cnt", value: 5 }]
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -717,7 +692,6 @@ describe("Cross Partition", function() {
query: "SELECT * FROM root r order by r.spam2"
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -734,7 +708,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r order by r.cnt";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -750,7 +723,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r order by r.number";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -766,7 +738,6 @@ describe("Cross Partition", function() {
// simple order by query in string format
const query = "SELECT * FROM root r order by r.boolVar";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -798,7 +769,6 @@ describe("Cross Partition", function() {
query: `SELECT * FROM root r OFFSET ${offset} LIMIT ${limit}`
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -819,7 +789,6 @@ describe("Cross Partition", function() {
query: `SELECT * FROM root r WHERE r.number > 5 OFFSET ${offset} LIMIT ${limit}`
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -842,7 +811,6 @@ describe("Cross Partition", function() {
query: `SELECT * FROM root r order by r.spam ASC OFFSET ${offset} LIMIT ${limit}`
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -870,7 +838,6 @@ describe("Cross Partition", function() {
query: `SELECT * FROM root r order by r.spam ASC OFFSET ${offset} LIMIT ${limit}`
};
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};
@ -894,7 +861,6 @@ describe("Cross Partition", function() {
const query = "SELECT * FROM root r order by r.spam";
const options = {
enableCrossPartitionQuery: true,
maxItemCount: 2
};

Просмотреть файл

@ -30,8 +30,7 @@ describe("ResourceLink Trimming of leading and trailing slashes", function() {
await container.items.create(doc);
const query = "SELECT * from " + containerId;
const queryOptions = { partitionKey: "pk" };
const queryIterator = container.items.query(query, queryOptions);
const queryIterator = container.items.query(query);
const { resources } = await queryIterator.fetchAll();
assert.equal(resources[0]["id"], "myId");
@ -57,7 +56,7 @@ describe("Test Query Metrics", function() {
await createdContainer.items.create(document);
const query = "SELECT * from " + collectionId;
const queryOptions: FeedOptions = { populateQueryMetrics: true, enableCrossPartitionQuery: true };
const queryOptions: FeedOptions = { populateQueryMetrics: true };
const queryIterator = createdContainer.items.query(query, queryOptions);
while (queryIterator.hasMoreResults()) {

Просмотреть файл

@ -221,9 +221,8 @@ describe("Session Token", function() {
);
firstPartitionToken = containerTokens.get(firstPartition);
const query = "SELECT * from " + containerId;
const queryOptions = { partitionKey: "1" };
const queryIterator = container.items.query(query, queryOptions);
const query = `SELECT * from c WHERE c.id = "1"`;
const queryIterator = container.items.query(query);
const queryToken = sessionContainer.get({
isNameBased: true,