/*
* Copyright (c) 2016 Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.couchbase.client.java.query;
import com.couchbase.client.deps.io.netty.buffer.Unpooled;
import com.couchbase.client.deps.io.netty.util.CharsetUtil;
import com.couchbase.client.java.CouchbaseAsyncBucket;
import com.couchbase.client.java.document.json.JsonArray;
import com.couchbase.client.java.document.json.JsonObject;
import com.couchbase.client.java.query.consistency.ScanConsistency;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.couchbase.client.java.query.Select.select;
import static com.couchbase.client.java.query.dsl.Expression.s;
import static com.couchbase.client.java.query.dsl.Expression.x;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* Verifies various combinations of N1QL queries and their transformation to N1QL string.
*
* @author Simon Baslé
* @since 2.1
*/
public class QueryToN1qlTest {
@Test
public void simpleQueryShouldJustProduceStatement() {
SimpleN1qlQuery query = new SimpleN1qlQuery(select("*").from("tutorial").where(x("fname").eq(s("ian"))), null);
//notice ian is between escaped quotes since inside json
assertEquals("{\"statement\":\"SELECT * FROM tutorial WHERE fname = \\\"ian\\\"\"}", query.n1ql().toString());
}
@Test
public void rawSimpleQueryShouldJustProduceStatementAsIs() {
SimpleN1qlQuery query = N1qlQuery.simple("Here goes anything even not \"JSON\"");
//notice JSON is between escaped quotes since inside json
assertEquals("{\"statement\":\"Here goes anything even not \\\"JSON\\\"\"}", query.n1ql().toString());
}
@Test
public void parameterizedQueryWithArrayShouldProduceStatementAndArgs() {
ParameterizedN1qlQuery query = new ParameterizedN1qlQuery(select("*"), JsonArray.from("aString", 123, true), null);
JsonObject expected = JsonObject.create()
.put("statement", "SELECT *")
.put("args", JsonArray.from("aString", 123, true));
assertEquals(expected, query.n1ql());
}
@Test
public void shouldReuseNameWhenRepreparingPayload() {
PreparedPayload fakePayload = new PreparedPayload(select("*"), "testName", "plan1234");
PrepareStatement preparedStatement = PrepareStatement.prepare(fakePayload);
assertEquals(fakePayload.originalStatement().toString(), preparedStatement.originalStatement().toString());
assertEquals(fakePayload.preparedName(), preparedStatement.preparedName());
}
@Test
public void shouldNotWrapAPrepareStatement() {
PrepareStatement statement = PrepareStatement.prepare(select("*"));
assertEquals(statement, PrepareStatement.prepare(statement));
}
@Test
public void shouldNotDoublePrefixAStringPreparedStatementWithoutName() {
String alreadyPrepare = "PREPARE SELECT *";
String secondPrepare = PrepareStatement.prepare(alreadyPrepare).toString();
assertFalse(secondPrepare.contains("FROM PREPARE"));
assertFalse(secondPrepare.substring("PREPARE ".length()).contains("PREPARE"));
}
@Test
public void shouldPrependStatementWithPrepare() {
Statement toPrepare = select("*").from("default");
PrepareStatement prepare = PrepareStatement.prepare(toPrepare);
PrepareStatement prepareFromString = PrepareStatement.prepare("SELECT * FROM default");
Pattern p = Pattern.compile("PREPARE `\\w+` FROM ");
Matcher prepareMatcher = p.matcher(prepare.toString());
Matcher prepareFromStringMatcher = p.matcher(prepareFromString.toString());
assertTrue(prepareMatcher.find());
assertTrue(prepareFromStringMatcher.find());
assertEquals("SELECT * FROM default", prepareMatcher.replaceAll(""));
assertEquals("SELECT * FROM default", prepareFromStringMatcher.replaceAll(""));
}
@Test
public void preparedQueryWithArrayShouldProducePreparedAndArgs() {
PreparedPayload fakePlan = new PreparedPayload(select("*"), "planName", "plan1234");
JsonArray params =JsonArray.from("aString", 123, true);
PreparedN1qlQuery query = new PreparedN1qlQuery(fakePlan, params, null);
JsonObject expected = JsonObject.create()
.put("prepared", "planName")
.put("args", JsonArray.from("aString", 123, true))
.put("encoded_plan", "plan1234");
assertEquals(expected, query.n1ql());
}
@Test
public void parameterizedQueryWithObjectShouldProduceStatementAndNamedParameters() {
JsonObject args = JsonObject.create()
.put("myParamString", "aString")
.put("someInt", 123)
.put("$fullN1qlParam", true);
ParameterizedN1qlQuery query = new ParameterizedN1qlQuery(select("*"), args, null);
JsonObject expected = JsonObject.create()
.put("statement", "SELECT *")
.put("$myParamString", "aString")
.put("$someInt", 123)
.put("$fullN1qlParam", true);
assertEquals(expected, query.n1ql());
}
@Test
public void preparedQueryWithObjectShouldProducePreparedAndNamedParameters() {
PreparedPayload fakePlan = new PreparedPayload(select("*"), "planName", "plan1234");
JsonObject args = JsonObject.create()
.put("myParamString", "aString")
.put("someInt", 123)
.put("$fullN1qlParam", true);
PreparedN1qlQuery query = new PreparedN1qlQuery(fakePlan, args, null);
JsonObject expected = JsonObject.create()
.put("prepared", "planName")
.put("$myParamString", "aString")
.put("$someInt", 123)
.put("$fullN1qlParam", true)
.put("encoded_plan", "plan1234");
assertEquals(expected, query.n1ql());
}
@Test
public void queryParamsShouldBeInjectedInQuery() {
N1qlParams fullParams = N1qlParams.build()
.consistency(ScanConsistency.REQUEST_PLUS)
.scanWait(12, TimeUnit.SECONDS)
.serverSideTimeout(20, TimeUnit.SECONDS)
.withContextId("test");
JsonObject expected = JsonObject.create()
.put("statement", "SELECT * FROM default")
.put("scan_consistency", "request_plus")
.put("scan_wait", "12s")
.put("timeout", "20s")
.put("client_context_id", "test");
SimpleN1qlQuery query1 = new SimpleN1qlQuery(select(x("*")).from("default"), fullParams);
assertEquals(expected, query1.n1ql());
ParameterizedN1qlQuery query2 = new ParameterizedN1qlQuery(select(x("*")).from("default"), JsonObject.empty(), fullParams);
assertEquals(expected, query2.n1ql());
expected
.removeKey("statement")
.put("prepared", "planName")
.put("encoded_plan", "plan1234");
PreparedN1qlQuery query3 = new PreparedN1qlQuery(new PreparedPayload(select("*"), "planName", "plan1234"), JsonArray.empty(), fullParams);
assertEquals(expected, query3.n1ql());
}
private Object unmarshallSignature(String value) throws Exception {
return CouchbaseAsyncBucket.JSON_OBJECT_TRANSCODER.byteBufJsonValueToObject(
Unpooled.copiedBuffer(value, CharsetUtil.UTF_8));
}
@Test
public void testQuerySignaturesAreCorrectlyUnmarshalled() throws Exception {
Object stringScalar = unmarshallSignature(" \t\n\r\"a\"");
Object numberScalar = unmarshallSignature(" \t\n\r\n123");
Object booleanScalar = unmarshallSignature(" \t\n\r\ntrue");
Object nullScalar = unmarshallSignature(" \t\n\r\nnull");
Object jsonObject = unmarshallSignature(" \t\n\r\n{\"a\": 123}");
Object jsonArray = unmarshallSignature(" \t\n\r\n[1, 2, 3]");
assertTrue(stringScalar.getClass().getSimpleName(), stringScalar instanceof String);
assertTrue(numberScalar.getClass().getSimpleName(), numberScalar instanceof Number);
assertTrue(booleanScalar.getClass().getSimpleName(), booleanScalar instanceof Boolean);
assertNull(nullScalar);
assertTrue(jsonObject.getClass().getSimpleName(), jsonObject instanceof JsonObject);
assertTrue(jsonArray.getClass().getSimpleName(), jsonArray instanceof JsonArray);
assertEquals("a", stringScalar);
assertEquals(123, numberScalar);
assertEquals(true, booleanScalar);
assertNull(nullScalar);
assertEquals(JsonObject.create().put("a", 123), jsonObject);
assertEquals(JsonArray.from(1, 2, 3), jsonArray);
}
}