Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions Microsoft.Azure.Cosmos/src/GatewayStoreModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ await GatewayStoreModel.ApplySessionTokenAsync(
// This is applicable for both per partition automatic failover and per partition circuit breaker.
if ((isPPAFEnabled || this.isThinClientEnabled)
&& !ReplicatedResourceClient.IsMasterResource(request.ResourceType)
&& request.ResourceType.IsPartitioned())
&& (request.ResourceType.IsPartitioned() || request.ResourceType == ResourceType.StoredProcedure))
{
(bool isSuccess, PartitionKeyRange partitionKeyRange) = await TryResolvePartitionKeyRangeAsync(
request: request,
Expand Down Expand Up @@ -553,15 +553,28 @@ internal static bool IsStoredProcedureCrudOperation(

internal static bool IsOperationSupportedByThinClient(DocumentServiceRequest request)
{
return request.ResourceType == ResourceType.Document
&& (request.OperationType == OperationType.Batch
|| request.OperationType == OperationType.Patch
|| request.OperationType == OperationType.Create
|| request.OperationType == OperationType.Read
|| request.OperationType == OperationType.Upsert
|| request.OperationType == OperationType.Replace
|| request.OperationType == OperationType.Delete
|| request.OperationType == OperationType.Query);
// Document operations
if (request.ResourceType == ResourceType.Document
&& (request.OperationType == OperationType.Batch
|| request.OperationType == OperationType.Patch
|| request.OperationType == OperationType.Create
|| request.OperationType == OperationType.Read
|| request.OperationType == OperationType.Upsert
|| request.OperationType == OperationType.Replace
|| request.OperationType == OperationType.Delete
|| request.OperationType == OperationType.Query))
{
return true;
}

// Stored Procedure execution
if (request.ResourceType == ResourceType.StoredProcedure
&& request.OperationType == OperationType.ExecuteJavaScript)
{
return true;
}

return false;
}
private async Task<AccountProperties> GetDatabaseAccountPropertiesAsync()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,189 @@ public async Task RegionalDatabaseAccountNameIsEmptyInPayload()
await database.DeleteAsync();
}

[TestMethod]
[TestCategory("ThinClient")]
public async Task TestThinClientWithExecuteStoredProcedureAsync()
{
Environment.SetEnvironmentVariable(ConfigurationManager.ThinClientModeEnabled, "true");
Comment thread
aavasthy marked this conversation as resolved.

JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = null,
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
this.cosmosSystemTextJsonSerializer = new MultiRegionSetupHelpers.CosmosSystemTextJsonSerializer(jsonSerializerOptions);

this.client = new CosmosClient(
this.connectionString,
new CosmosClientOptions()
{
ConnectionMode = ConnectionMode.Gateway,
Serializer = this.cosmosSystemTextJsonSerializer,
});

string uniqueDbName = "TestDbStoreProc_" + Guid.NewGuid().ToString();
this.database = await this.client.CreateDatabaseIfNotExistsAsync(uniqueDbName);
string uniqueContainerName = "TestDbStoreProcContainer_" + Guid.NewGuid().ToString();
this.container = await this.database.CreateContainerIfNotExistsAsync(uniqueContainerName, "/pk");


string sprocId = "testSproc_" + Guid.NewGuid().ToString();
string sprocBody = @"function(itemToCreate) {
var context = getContext();
var collection = context.getCollection();
var response = context.getResponse();

if (!itemToCreate) throw new Error('Item is undefined or null.');

// Create a document
var accepted = collection.createDocument(
collection.getSelfLink(),
itemToCreate,
function(err, newItem) {
if (err) throw err;

// Query the created document
var query = 'SELECT * FROM c WHERE c.id = ""' + newItem.id + '""';
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
query,
function(queryErr, documents) {
if (queryErr) throw queryErr;
response.setBody({
created: newItem,
queried: documents[0]
});
}
);
if (!isAccepted) throw 'Query not accepted';
});

if (!accepted) throw new Error('Create was not accepted.');
}";

// Create stored procedure
Scripts.StoredProcedureResponse createResponse = await this.container.Scripts.CreateStoredProcedureAsync(
new Scripts.StoredProcedureProperties(sprocId, sprocBody));
Assert.AreEqual(HttpStatusCode.Created, createResponse.StatusCode);

// Execute stored procedure
string testPartitionId = Guid.NewGuid().ToString();
TestObject testItem = new TestObject
{
Id = Guid.NewGuid().ToString(),
Pk = testPartitionId,
Other = "Created by Stored Procedure"
};

Scripts.StoredProcedureExecuteResponse<dynamic> executeResponse =
await this.container.Scripts.ExecuteStoredProcedureAsync<dynamic>(
sprocId,
new PartitionKey(testPartitionId),
new dynamic[] { testItem });

Assert.AreEqual(HttpStatusCode.OK, executeResponse.StatusCode);
Assert.IsNotNull(executeResponse.Resource);
string diagnostics = executeResponse.Diagnostics.ToString();
Assert.IsTrue(diagnostics.Contains("|F4"), "Diagnostics User Agent should contain '|F4' for ThinClient");

// Delete stored procedure
await this.container.Scripts.DeleteStoredProcedureAsync(sprocId);
}

[TestMethod]
[TestCategory("ThinClient")]
public async Task TestThinClientWithExecuteStoredProcedureStreamAsync()
{
Environment.SetEnvironmentVariable(ConfigurationManager.ThinClientModeEnabled, "true");

JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = null,
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
this.cosmosSystemTextJsonSerializer = new MultiRegionSetupHelpers.CosmosSystemTextJsonSerializer(jsonSerializerOptions);

this.client = new CosmosClient(
this.connectionString,
new CosmosClientOptions()
{
ConnectionMode = ConnectionMode.Gateway,
Serializer = this.cosmosSystemTextJsonSerializer,
});

string uniqueDbName = "TestDbStoreProc_" + Guid.NewGuid().ToString();
this.database = await this.client.CreateDatabaseIfNotExistsAsync(uniqueDbName);
string uniqueContainerName = "TestDbStoreProcContainer_" + Guid.NewGuid().ToString();
this.container = await this.database.CreateContainerIfNotExistsAsync(uniqueContainerName, "/pk");


string sprocId = "testSproc_" + Guid.NewGuid().ToString();
string sprocBody = @"function(itemToCreate) {
var context = getContext();
var collection = context.getCollection();
var response = context.getResponse();

if (!itemToCreate) throw new Error('Item is undefined or null.');

// Create a document
var accepted = collection.createDocument(
collection.getSelfLink(),
itemToCreate,
function(err, newItem) {
if (err) throw err;

// Query the created document
var query = 'SELECT * FROM c WHERE c.id = ""' + newItem.id + '""';
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
query,
function(queryErr, documents) {
if (queryErr) throw queryErr;
response.setBody({
created: newItem,
queried: documents[0]
});
}
);
if (!isAccepted) throw 'Query not accepted';
});

if (!accepted) throw new Error('Create was not accepted.');
}";

// Create stored procedure
Scripts.StoredProcedureResponse createResponse = await this.container.Scripts.CreateStoredProcedureAsync(
new Scripts.StoredProcedureProperties(sprocId, sprocBody));
Assert.AreEqual(HttpStatusCode.Created, createResponse.StatusCode);

// Execute stored procedure
string testPartitionId = Guid.NewGuid().ToString();
TestObject testItem = new TestObject
{
Id = Guid.NewGuid().ToString(),
Pk = testPartitionId,
Other = "Created by Stored Procedure"
};

using (ResponseMessage executeResponse =
await this.container.Scripts.ExecuteStoredProcedureStreamAsync(
sprocId,
new PartitionKey(testPartitionId),
new dynamic[] { testItem }))
{
Assert.AreEqual(HttpStatusCode.OK, executeResponse.StatusCode);
Assert.IsNotNull(executeResponse.Content);
string diagnostics = executeResponse.Diagnostics.ToString();
Assert.IsTrue(diagnostics.Contains("|F4"), "Diagnostics User Agent should contain '|F4' for ThinClient");
}

// Delete stored procedure
await this.container.Scripts.DeleteStoredProcedureAsync(sprocId);
}

[TestMethod]
[TestCategory("ThinClient")]
public async Task HttpRequestVersionIsTwoPointZeroWhenUsingThinClientMode()
Expand Down
Loading