Initial checkin of QueryStringBuilder

This commit is contained in:
2022-10-25 09:55:28 -05:00
parent 128c379f10
commit dae803f709
2 changed files with 246 additions and 0 deletions

View File

@ -0,0 +1,133 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.module.api.utils;
import java.io.Serializable;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import com.kingsrook.qqq.backend.core.utils.Pair;
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
/*******************************************************************************
** Utility for building a query string - taking care of things like:
** - do I need the "?"
** - do I need a "&"
** - urlEncoding params (depending on which method you call: (name, value) does
** encode -- (pair) does not.)
*******************************************************************************/
public class QueryStringBuilder
{
private List<Pair<String, String>> pairs = new ArrayList<>();
/*******************************************************************************
** Assumes both name and value have NOT been previous URL Encoded
*******************************************************************************/
public void addPair(String name, Serializable value)
{
String valueString = urlEncode(ValueUtils.getValueAsString(value));
pairs.add(new Pair<>(urlEncode(name), valueString));
}
/*******************************************************************************
** Assumes both name and value have NOT been previous URL Encoded
*******************************************************************************/
public QueryStringBuilder withPair(String name, Serializable value)
{
addPair(name, value);
return (this);
}
/*******************************************************************************
** Assumes both parts are already properly uri encoded
*******************************************************************************/
public void addPair(String pair)
{
String[] parts = pair.split("=", 2);
if(parts.length == 1)
{
pairs.add(new Pair<>(parts[0], ""));
}
else
{
pairs.add(new Pair<>(parts[0], parts[1]));
}
}
/*******************************************************************************
** Assumes both parts are already properly uri encoded
*******************************************************************************/
public QueryStringBuilder withPair(String pair)
{
addPair(pair);
return (this);
}
/*******************************************************************************
**
*******************************************************************************/
public String toQueryString()
{
if(pairs.isEmpty())
{
return ("");
}
return ("?" + pairs.stream().map(p -> p.getA() + "=" + p.getB()).collect(Collectors.joining("&")));
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public String toString()
{
return (toQueryString());
}
/*******************************************************************************
**
*******************************************************************************/
private String urlEncode(Serializable s)
{
return (URLEncoder.encode(ValueUtils.getValueAsString(s), StandardCharsets.UTF_8));
}
}

View File

@ -0,0 +1,113 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.module.api.utils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*******************************************************************************
** Unit test for QueryStringBuilder
*******************************************************************************/
class QueryStringBuilderTest
{
/*******************************************************************************
**
*******************************************************************************/
@Test
void testEmpty()
{
assertEquals("", new QueryStringBuilder().toQueryString());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testSimpleWithoutAnd()
{
QueryStringBuilder queryStringBuilder = new QueryStringBuilder();
queryStringBuilder.addPair("foo", 1);
assertEquals("?foo=1", queryStringBuilder.toQueryString());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testSimpleWithAnd()
{
QueryStringBuilder queryStringBuilder = new QueryStringBuilder();
queryStringBuilder.addPair("foo", 1);
queryStringBuilder.addPair("bar=2");
assertEquals("?foo=1&bar=2", queryStringBuilder.toQueryString());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testFluent()
{
assertEquals("?foo=1&bar=2", new QueryStringBuilder()
.withPair("foo", 1)
.withPair("bar=2")
.toQueryString());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testEncoding()
{
QueryStringBuilder queryStringBuilder = new QueryStringBuilder();
queryStringBuilder.addPair("percent", "99%"); // % should get encoded to %25
queryStringBuilder.addPair("and=this%26that"); // %26 should stay as-is -- not be re-encoded.
assertEquals("?percent=99%25&and=this%26that", queryStringBuilder.toQueryString());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testPairWithoutValue()
{
QueryStringBuilder queryStringBuilder = new QueryStringBuilder();
queryStringBuilder.addPair("name1");
queryStringBuilder.addPair("name2=");
assertEquals("?name1=&name2=", queryStringBuilder.toString());
}
}