Class SafeQuery
It's best practice for your db layer API to require SafeQuery instead of
String as the parameter to ensure safety. Internally, you can use
toString()
to access the query string.
This class supports generating SQL based on a string template in the syntax
of TemplateString
, and with the same compile-time protection. To
prevent SQL injection errors, special characters of string values are
automatically escaped; and negative numbers are automatically enclosed by
parenthesis.
This class is Android compatible.
- Since:
- 7.0
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic class
An SPI class for subclasses to provide additional translation from placeholder values to safe query strings. -
Method Summary
Modifier and TypeMethodDescriptionand()
A collector that joins boolean query snippets usingAND
operator.boolean
int
hashCode()
Returns a collector that can joinSafeQuery
objects usingdelim
as the delimiter.static SafeQuery
Returns a query using a constant query template filled withargs
.or()
A collector that joins boolean query snippets usingOR
operator.static StringFormat.Template
<SafeQuery> Creates a template with the placeholders to be filled by subsequentStringFormat.To.with(java.lang.Object...)
calls.toString()
Returns the encapsulated SQL query.static SafeQuery
with
(String name1, SafeQuery subquery1, String name2, SafeQuery subquery2, String name3, SafeQuery subquery3, String template, Object... args) Creates a SafeQuery with 3 CTEs (Common Table Expression).static SafeQuery
with
(String name1, SafeQuery subquery1, String name2, SafeQuery subquery2, String template, Object... args) Creates a SafeQuery with two CTEs (Common Table Expression).static SafeQuery
Creates a SafeQuery with a single CTE (Common Table Expression).
-
Method Details
-
of
@TemplateFormatMethod public static SafeQuery of(@CompileTimeConstant @TemplateString String query, Object... args) Returns a query using a constant query template filled withargs
. -
template
Creates a template with the placeholders to be filled by subsequentStringFormat.To.with(java.lang.Object...)
calls. For example:private static final Template<SafeQuery> FIND_CASE_BY_ID = SafeQuery .template("SELECT * FROM `{project_id}.{dataset}.Cases` WHERE CaseId = '{case_id}'"); // ... SafeQuery query = FIND_CASE_BY_ID.with(projectId, dataset, caseId);
Placeholders must follow the following rules:
- String placeholder values can only be used when the corresponding
placeholder is quoted in the template string (such as '{case_id}').
- If quoted by single quotes (') or double quotes ("), the placeholder value will be auto-escaped.
- If quoted by backticks (`), the placeholder value cannot contain backtick, quotes and other special characters.
- Unquoted placeholders are assumed to be symbols or subqueries. Strings
(CharSequence) and characters cannot be used as placeholder value. If you
have to pass a string, wrap it inside a
TrustedSqlString
(you can configure the type you trust by setting the "com.google.mu.safesql.SafeQuery.trusted_sql_type" system property). - An Iterable's elements are auto expanded and joined by a comma and space (", ").
- If the iterable's placeholder is quoted as in
WHERE id IN ('{ids}')
, every expanded element is quoted (and auto-escaped). For example, passingasList("foo", "bar")
as the value for placeholder'{ids}'
will result inWHERE id IN ('foo', 'bar')
. - If the Iterable's placeholder is backtick-quoted, every expanded element
is backtick-quoted. For example, passing
asList("col1", "col2")
as the value for placeholder`{cols}`
will result in`col`, `col2`
. - Subqueries can be composed by using
SafeQuery
as the placeholder value.
The placeholder values passed through
StringFormat.To.with(java.lang.Object...)
are checked by ErrorProne to ensure the correct number of arguments are passed, and in the expected order.Supported expression types:
- null (NULL)
- Boolean
- Numeric (negative numbers will be enclosed in parenthesis to avoid semantic change)
- Enum
- String (must be quoted in the template)
TrustedSqlString
SafeQuery
- Iterable
If you are trying to create SafeQuery inline like
SafeQuery.template(tmpl).with(a, b)
, please useSafeQuery.of(tmpl, a, b)
instead. - String placeholder values can only be used when the corresponding
placeholder is quoted in the template string (such as '{case_id}').
-
with
@TemplateFormatMethod public static SafeQuery with(@CompileTimeConstant String subqueryName, SafeQuery subquery, @TemplateString @CompileTimeConstant String template, Object... args) Creates a SafeQuery with a single CTE (Common Table Expression). That is, the query intemplate
refers tosubquery
bysubqueryName
.For example:
is equivalent to:SafeQuery.with( "jobs", SafeQuery.of("SELECT * FROM INFO_SCHEMA.JOBS WHERE id = {project}", projectId), "SELECT `{columns}` FROM jobs", columns);
WITH jobs AS ( SELECT * FROM INFO_SCHEMA.JOBS WHERE id = ... ) SELECT ... FROM jobs
- Since:
- 8.1
-
with
@TemplateFormatMethod public static SafeQuery with(@CompileTimeConstant String name1, SafeQuery subquery1, @CompileTimeConstant String name2, SafeQuery subquery2, @TemplateString @CompileTimeConstant String template, Object... args) Creates a SafeQuery with two CTEs (Common Table Expression). That is, the query intemplate
refers tosubquery1
byname1
andsubquery2
byname2
.For example:
is equivalent to:SafeQuery.with( "jobs", SafeQuery.of("SELECT * FROM INFO_SCHEMA.JOBS WHERE id = {project}", projectId), "days", SafeQuery.of("SELECT ..."), "SELECT `{columns}` FROM jobs, days", columns);
WITH jobs AS ( SELECT * FROM INFO_SCHEMA.JOBS WHERE id = ... ), days AS ( SELECT ... ) SELECT ... FROM jobs, days
- Since:
- 8.1
-
with
@TemplateFormatMethod public static SafeQuery with(@CompileTimeConstant String name1, SafeQuery subquery1, @CompileTimeConstant String name2, SafeQuery subquery2, @CompileTimeConstant String name3, SafeQuery subquery3, @TemplateString @CompileTimeConstant String template, Object... args) Creates a SafeQuery with 3 CTEs (Common Table Expression). That is, the query intemplate
refers tosubquery1
byname1
,subquery2
byname2
andsubquery3
byname3
.For example:
is equivalent to:SafeQuery.with( "jobs", SafeQuery.of("SELECT * FROM INFO_SCHEMA.JOBS WHERE id = {project}", projectId), "days", SafeQuery.of("SELECT ..."), "editions", SafeQuery.of("SELECT ..."), "SELECT `{columns}` FROM jobs, days, editions", columns);
WITH jobs AS ( SELECT * FROM INFO_SCHEMA.JOBS WHERE id = ... ), days AS ( SELECT ... ), editions AS ( SELECT ... ) SELECT ... FROM jobs, days, editions
- Since:
- 8.1
-
and
A collector that joins boolean query snippets usingAND
operator. The AND'ed sub-queries will be enclosed in pairs of parenthesis to avoid ambiguity. If the input is empty, the result will be "TRUE".- Since:
- 7.2
-
or
A collector that joins boolean query snippets usingOR
operator. The OR'ed sub-queries will be enclosed in pairs of parenthesis to avoid ambiguity. If the input is empty, the result will be "FALSE".- Since:
- 7.2
-
joining
Returns a collector that can joinSafeQuery
objects usingdelim
as the delimiter. -
toString
Returns the encapsulated SQL query. -
equals
-
hashCode
public int hashCode()
-