Skip to content
This repository has been archived by the owner on Aug 29, 2024. It is now read-only.

Commit

Permalink
Fix invalid identifier of SQL parameters, fix #221. (#222)
Browse files Browse the repository at this point in the history
* For nested query with DocumentQuery, replace user.name to user_name.

Signed-off-by: Pan Li <[email protected]>
  • Loading branch information
Incarnation-p-lee authored Oct 12, 2018
1 parent e684b63 commit d856516
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class AbstractQueryGenerator {

private String generateQueryParameter(@NonNull String subject) {
return subject.replaceAll("\\.", "_"); // user.name is not valid sql parameter identifier.
}

private String generateUnaryQuery(@NonNull Criteria criteria) {
Assert.isTrue(criteria.getSubjectValues().isEmpty(), "Unary criteria should have no one subject value");
Assert.isTrue(CriteriaType.isUnary(criteria.getType()), "Criteria type should be unary operation");
Expand All @@ -48,13 +52,14 @@ private String generateBinaryQuery(@NonNull Criteria criteria, @NonNull List<Pai

final String subject = criteria.getSubject();
final Object subjectValue = toDocumentDBValue(criteria.getSubjectValues().get(0));
final String parameter = generateQueryParameter(subject);

parameters.add(Pair.with(subject, subjectValue));
parameters.add(Pair.with(parameter, subjectValue));

if (CriteriaType.isFunction(criteria.getType())) {
return String.format("%s(r.%s, @%s)", criteria.getType().getSqlKeyword(), subject, subject);
return String.format("%s(r.%s, @%s)", criteria.getType().getSqlKeyword(), subject, parameter);
} else {
return String.format("r.%s %s @%s", subject, criteria.getType().getSqlKeyword(), subject);
return String.format("r.%s %s @%s", subject, criteria.getType().getSqlKeyword(), parameter);
}
}

Expand All @@ -64,10 +69,14 @@ private String generateBetween(@NonNull Criteria criteria, @NonNull List<Pair<St
final Object value2 = toDocumentDBValue(criteria.getSubjectValues().get(1));
final String subject1 = "start";
final String subject2 = "end";
parameters.add(Pair.with(subject1, value1));
parameters.add(Pair.with(subject2, value2));
final String parameter1 = generateQueryParameter(subject1);
final String parameter2 = generateQueryParameter(subject2);
final String keyword = criteria.getType().getSqlKeyword();

parameters.add(Pair.with(parameter1, value1));
parameters.add(Pair.with(parameter2, value2));

return String.format("(r.%s %s @%s AND @%s)", subject, criteria.getType().getSqlKeyword(), subject1, subject2);
return String.format("(r.%s %s @%s AND @%s)", subject, keyword, parameter1, parameter2);
}

private String generateClosedQuery(@NonNull String left, @NonNull String right, CriteriaType type) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.data.annotation.Id;

@Data
@AllArgsConstructor
public class Customer {

@Id
private String id;

private Long level;

private User user;

@Data
@AllArgsConstructor
public static class User {

private String name;

private Long age;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.repository.integration;

import com.microsoft.azure.spring.data.cosmosdb.domain.Customer;
import com.microsoft.azure.spring.data.cosmosdb.repository.TestRepositoryConfig;
import com.microsoft.azure.spring.data.cosmosdb.repository.repository.CustomerRepository;
import lombok.NonNull;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestRepositoryConfig.class)
public class CustomerRepositoryIT {

private static final String USER_NAME_0 = "username-0";
private static final String USER_NAME_1 = "username-1";
private static final String FAKE_USER_NAME = "username-fake";

private static final Long USER_AGE_0 = 34L;
private static final Long USER_AGE_1 = 45L;

private static final String CUSTOMER_ID_0 = "id-0";
private static final String CUSTOMER_ID_1 = "id-1";
private static final String CUSTOMER_ID_2 = "id-2";

private static final Long CUSTOMER_LEVEL_0 = 1L;
private static final Long CUSTOMER_LEVEL_1 = 2L;

private static final Customer.User USER_0 = new Customer.User(USER_NAME_0, USER_AGE_0);
private static final Customer.User USER_1 = new Customer.User(USER_NAME_1, USER_AGE_1);
private static final Customer.User USER_2 = new Customer.User(USER_NAME_0, USER_AGE_1);

private static final Customer CUSTOMER_0 = new Customer(CUSTOMER_ID_0, CUSTOMER_LEVEL_0, USER_0);
private static final Customer CUSTOMER_1 = new Customer(CUSTOMER_ID_1, CUSTOMER_LEVEL_1, USER_1);
private static final Customer CUSTOMER_2 = new Customer(CUSTOMER_ID_2, CUSTOMER_LEVEL_1, USER_2);

@Autowired
private CustomerRepository repository;

@Before
public void setup() {
this.repository.saveAll(Arrays.asList(CUSTOMER_0, CUSTOMER_1, CUSTOMER_2));
}

@After
public void cleanup() {
this.repository.deleteAll();
}

private void assertCustomerListEquals(@NonNull List<Customer> customers, @NonNull List<Customer> reference) {
Assert.assertEquals(customers.size(), reference.size());

customers.sort(Comparator.comparing(Customer::getId));
reference.sort(Comparator.comparing(Customer::getId));

Assert.assertEquals(customers, reference);
}

@Test
public void testFindByUserAndLevel() {
final List<Customer> references = Arrays.asList(CUSTOMER_0, CUSTOMER_2);
List<Customer> customers = this.repository.findByUser_Name(USER_NAME_0);

assertCustomerListEquals(references, customers);

customers = this.repository.findByUser_Name(FAKE_USER_NAME);

Assert.assertTrue(customers.isEmpty());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.repository.repository;

import com.microsoft.azure.spring.data.cosmosdb.domain.Customer;
import com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository;

import java.util.List;

public interface CustomerRepository extends DocumentDbRepository<Customer, String> {
List<Customer> findByUser_Name(String name);
}

0 comments on commit d856516

Please sign in to comment.