sea_query/query/with.rs
1use crate::{
2 ColumnRef, DynIden, IntoIden, QueryStatementBuilder, QueryStatementWriter, SelectExpr,
3 SelectStatement, SimpleExpr, SqlWriter, SubQueryStatement, TableRef, Values,
4 {Alias, QueryBuilder},
5};
6use inherent::inherent;
7
8/// A table definition inside a WITH clause ([WithClause]).
9///
10/// A WITH clause can contain one or multiple common table expressions ([CommonTableExpression]).
11///
12/// These named queries can act as a "query local table" that are materialized during execution and
13/// then can be used by the query prefixed with the WITH clause.
14///
15/// A WITH clause can contain multiple of these [CommonTableExpression]. (Except in the case of
16/// recursive WITH query which can only contain one [CommonTableExpression]).
17///
18/// A [CommonTableExpression] is a name, column names and a query returning data for those columns.
19///
20/// Some databases (like sqlite) restrict the acceptable kinds of queries inside of the WITH clause
21/// common table expressions. These databases only allow [SelectStatement]s to form a common table
22/// expression.
23///
24/// Other databases like postgres allow modification queries (UPDATE, DELETE) inside of the WITH
25/// clause but they have to return a table. (They must have a RETURNING clause).
26///
27/// sea-query doesn't check this or restrict the kind of [CommonTableExpression] that you can create
28/// in rust. This means that you can put an UPDATE or DELETE queries into WITH clause and sea-query
29/// will succeed in generating that kind of sql query but the execution inside the database will
30/// fail because they are invalid.
31///
32/// It is your responsibility to ensure that the kind of WITH clause that you put together makes
33/// sense and valid for that database that you are using.
34///
35/// NOTE that for recursive WITH queries (in sql: "WITH RECURSIVE") you can only have a
36/// single [CommonTableExpression] inside of the WITH clause. That query must match certain
37/// requirements:
38/// * It is a query of UNION or UNION ALL of two queries.
39/// * The first part of the query (the left side of the UNION) must be executable first in itself.
40/// It must be non-recursive. (Cannot contain self reference)
41/// * The self reference must appear in the right hand side of the UNION.
42/// * The query can only have a single self-reference.
43/// * Recursive data-modifying statements are not supported, but you can use the results of a
44/// recursive SELECT query in a data-modifying statement. (like so: WITH RECURSIVE
45/// cte_name(a,b,c,d) AS (SELECT ... UNION SELECT ... FROM ... JOIN cte_name ON ... WHERE ...)
46/// DELETE FROM table WHERE table.a = cte_name.a)
47///
48/// It is mandatory to set the [Self::table_name] and the [Self::query].
49#[derive(Debug, Clone, Default, PartialEq)]
50pub struct CommonTableExpression {
51 pub(crate) table_name: Option<DynIden>,
52 pub(crate) cols: Vec<DynIden>,
53 pub(crate) query: Option<Box<SubQueryStatement>>,
54 pub(crate) materialized: Option<bool>,
55}
56
57impl CommonTableExpression {
58 /// Construct a new [`CommonTableExpression`]
59 pub fn new() -> CommonTableExpression {
60 Self::default()
61 }
62
63 /// Sets the CTE table name of the query.
64 pub fn table_name<T>(&mut self, table_name: T) -> &mut Self
65 where
66 T: IntoIden,
67 {
68 self.table_name = Some(table_name.into_iden());
69 self
70 }
71
72 /// Adds a named column to the CTE table definition.
73 pub fn column<C>(&mut self, col: C) -> &mut Self
74 where
75 C: IntoIden,
76 {
77 self.cols.push(col.into_iden());
78 self
79 }
80
81 /// Adds a named columns to the CTE table definition.
82 pub fn columns<T, I>(&mut self, cols: I) -> &mut Self
83 where
84 T: IntoIden,
85 I: IntoIterator<Item = T>,
86 {
87 self.cols
88 .extend(cols.into_iter().map(|col| col.into_iden()));
89 self
90 }
91
92 /// Some databases allow you to put "MATERIALIZED" or "NOT MATERIALIZED" in the CTE definition.
93 /// This will affect how during the execution of [WithQuery] the CTE in the [WithClause] will be
94 /// executed. If the database doesn't support this syntax this option specified here will be
95 /// ignored and not appear in the generated sql.
96 pub fn materialized(&mut self, materialized: bool) -> &mut Self {
97 self.materialized = Some(materialized);
98 self
99 }
100
101 /// Set the query generating the CTE content. The query's result must match the defined
102 /// columns.
103 pub fn query<Q>(&mut self, query: Q) -> &mut Self
104 where
105 Q: QueryStatementBuilder,
106 {
107 self.query = Some(Box::new(query.into_sub_query_statement()));
108 self
109 }
110
111 /// Create a CTE from a [SelectStatement] if the selections are named columns then this will
112 /// return a [CommonTableExpression] that has the column names set. The [Self::table_name] is
113 /// set if the [SelectStatement] from clause contains at least one table.
114 pub fn from_select(select: SelectStatement) -> Self {
115 let mut cte = Self::default();
116 cte.try_set_cols_from_selects(&select.selects);
117 if let Some(from) = select.from.first() {
118 match from {
119 TableRef::Table(iden) => cte.set_table_name_from_select(iden),
120 TableRef::SchemaTable(_, iden) => cte.set_table_name_from_select(iden),
121 TableRef::DatabaseSchemaTable(_, _, iden) => cte.set_table_name_from_select(iden),
122 TableRef::TableAlias(_, iden) => cte.set_table_name_from_select(iden),
123 TableRef::SchemaTableAlias(_, _, iden) => cte.set_table_name_from_select(iden),
124 TableRef::DatabaseSchemaTableAlias(_, _, _, iden) => {
125 cte.set_table_name_from_select(iden)
126 }
127 _ => {}
128 }
129 }
130 cte.query = Some(Box::new(select.into_sub_query_statement()));
131 cte
132 }
133
134 fn set_table_name_from_select(&mut self, iden: &DynIden) {
135 self.table_name = Some(Alias::new(format!("cte_{}", iden.to_string())).into_iden())
136 }
137
138 /// Set up the columns of the CTE to match the given [SelectStatement] selected columns.
139 /// This will fail if the select contains non named columns like expressions of wildcards.
140 ///
141 /// Returns true if the column setup from the select query was successful. If the returned
142 /// value is false the columns are untouched.
143 pub fn try_set_cols_from_select(&mut self, select: &SelectStatement) -> bool {
144 self.try_set_cols_from_selects(&select.selects)
145 }
146
147 fn try_set_cols_from_selects(&mut self, selects: &[SelectExpr]) -> bool {
148 let vec: Option<Vec<DynIden>> = selects
149 .iter()
150 .map(|select| {
151 if let Some(ident) = &select.alias {
152 Some(ident.clone())
153 } else {
154 match &select.expr {
155 SimpleExpr::Column(column) => match column {
156 ColumnRef::Column(iden) => Some(iden.clone()),
157 ColumnRef::TableColumn(table, column) => Some(
158 Alias::new(format!("{}_{}", table.to_string(), column.to_string()))
159 .into_iden(),
160 ),
161 ColumnRef::SchemaTableColumn(schema, table, column) => Some(
162 Alias::new(format!(
163 "{}_{}_{}",
164 schema.to_string(),
165 table.to_string(),
166 column.to_string()
167 ))
168 .into_iden(),
169 ),
170 _ => None,
171 },
172 _ => None,
173 }
174 }
175 })
176 .collect();
177
178 if let Some(c) = vec {
179 self.cols = c;
180 return true;
181 }
182
183 false
184 }
185}
186
187/// For recursive [WithQuery] [WithClause]s the traversing order can be specified in some databases
188/// that support this functionality.
189#[derive(Debug, Clone, PartialEq)]
190pub enum SearchOrder {
191 /// Breadth first traversal during the execution of the recursive query.
192 BREADTH,
193 /// Depth first traversal during the execution of the recursive query.
194 DEPTH,
195}
196
197/// For recursive [WithQuery] [WithClause]s the traversing order can be specified in some databases
198/// that support this functionality.
199///
200/// The clause contains the type of traversal: [SearchOrder] and the expression that is used to
201/// construct the current path.
202///
203/// A query can have both SEARCH and CYCLE clauses.
204///
205/// Setting [Self::order] and [Self::expr] is mandatory. The [SelectExpr] used must specify an alias
206/// which will be the name that you can use to order the result of the [CommonTableExpression].
207#[derive(Debug, Clone, Default, PartialEq)]
208pub struct Search {
209 pub(crate) order: Option<SearchOrder>,
210 pub(crate) expr: Option<SelectExpr>,
211}
212
213impl Search {
214 /// Create a complete [Search] specification from the [SearchOrder] and a [SelectExpr]. The
215 /// given [SelectExpr] must have an alias specified.
216 pub fn new_from_order_and_expr<EXPR>(order: SearchOrder, expr: EXPR) -> Self
217 where
218 EXPR: Into<SelectExpr>,
219 {
220 let expr = expr.into();
221 expr.alias.as_ref().unwrap();
222 Self {
223 order: Some(order),
224 expr: Some(expr),
225 }
226 }
227
228 /// Constructs a new empty [Search].
229 pub fn new() -> Self {
230 Self::default()
231 }
232
233 /// The traversal order to be used.
234 pub fn order(&mut self, order: SearchOrder) -> &mut Self {
235 self.order = Some(order);
236 self
237 }
238
239 /// The given [SelectExpr] must have an alias specified.
240 ///
241 /// The actual expression will be the one used to track the path in the graph.
242 ///
243 /// The alias of the given [SelectExpr] will be the name of the order column generated by this
244 /// clause.
245 pub fn expr<EXPR>(&mut self, expr: EXPR) -> &mut Self
246 where
247 EXPR: Into<SelectExpr>,
248 {
249 let expr = expr.into();
250 expr.alias.as_ref().unwrap();
251 self.expr = Some(expr);
252 self
253 }
254}
255
256/// For recursive [WithQuery] [WithClause]s the CYCLE sql clause can be specified to avoid creating
257/// an infinite traversals that loops on graph cycles indefinitely. You specify an expression that
258/// identifies a node in the graph and that will be used to determine during the iteration of
259/// the execution of the query when appending of new values whether the new values are distinct new
260/// nodes or are already visited and therefore they should be added again into the result.
261///
262/// A query can have both SEARCH and CYCLE clauses.
263///
264/// Setting [Self::set], [Self::expr] and [Self::using] is mandatory.
265#[derive(Debug, Clone, Default, PartialEq)]
266pub struct Cycle {
267 pub(crate) expr: Option<SimpleExpr>,
268 pub(crate) set_as: Option<DynIden>,
269 pub(crate) using: Option<DynIden>,
270}
271
272impl Cycle {
273 /// Create a complete [Search] specification from the [SearchOrder] and a [SelectExpr]. The
274 /// given [SelectExpr] must have an alias specified.
275 pub fn new_from_expr_set_using<EXPR, ID1, ID2>(expr: EXPR, set: ID1, using: ID2) -> Self
276 where
277 EXPR: Into<SimpleExpr>,
278 ID1: IntoIden,
279 ID2: IntoIden,
280 {
281 Self {
282 expr: Some(expr.into()),
283 set_as: Some(set.into_iden()),
284 using: Some(using.into_iden()),
285 }
286 }
287
288 /// Constructs a new empty [Cycle].
289 pub fn new() -> Self {
290 Self::default()
291 }
292
293 /// The expression identifying nodes.
294 pub fn expr<EXPR>(&mut self, expr: EXPR) -> &mut Self
295 where
296 EXPR: Into<SimpleExpr>,
297 {
298 self.expr = Some(expr.into());
299 self
300 }
301
302 /// The name of the boolean column containing whether we have completed a cycle or not yet
303 /// generated by this clause.
304 pub fn set<ID>(&mut self, set: ID) -> &mut Self
305 where
306 ID: IntoIden,
307 {
308 self.set_as = Some(set.into_iden());
309 self
310 }
311
312 /// The name of the array typed column that contains the node ids (generated using the
313 /// [Self::expr]) that specify the current nodes path that will be generated by this clause.
314 pub fn using<ID>(&mut self, using: ID) -> &mut Self
315 where
316 ID: IntoIden,
317 {
318 self.using = Some(using.into_iden());
319 self
320 }
321}
322
323/// A WITH clause can contain one or multiple common table expressions ([CommonTableExpression]).
324///
325/// You can use this to generate [WithQuery] by calling [WithClause::query].
326///
327/// These named queries can act as a "query local table" that are materialized during execution and
328/// then can be used by the query prefixed with the WITH clause.
329///
330/// A WITH clause can contain multiple of these [CommonTableExpression]. (Except in the case of
331/// recursive WITH query which can only contain one [CommonTableExpression]).
332///
333/// A [CommonTableExpression] is a name, column names and a query returning data for those columns.
334///
335/// Some databases (like sqlite) restrict the acceptable kinds of queries inside of the WITH clause
336/// common table expressions. These databases only allow [SelectStatement]s to form a common table
337/// expression.
338///
339/// Other databases like postgres allow modification queries (UPDATE, DELETE) inside of the WITH
340/// clause but they have to return a table. (They must have a RETURNING clause).
341///
342/// sea-query doesn't check this or restrict the kind of [CommonTableExpression] that you can create
343/// in rust. This means that you can put an UPDATE or DELETE queries into WITH clause and sea-query
344/// will succeed in generating that kind of sql query but the execution inside the database will
345/// fail because they are invalid.
346///
347/// It is your responsibility to ensure that the kind of WITH clause that you put together makes
348/// sense and valid for that database that you are using.
349///
350/// NOTE that for recursive WITH queries (in sql: "WITH RECURSIVE") you can only have a
351/// single [CommonTableExpression] inside of the WITH clause. That query must match certain
352/// requirements:
353/// * It is a query of UNION or UNION ALL of two queries.
354/// * The first part of the query (the left side of the UNION) must be executable first in itself.
355/// It must be non-recursive. (Cannot contain self reference)
356/// * The self reference must appear in the right hand side of the UNION.
357/// * The query can only have a single self-reference.
358/// * Recursive data-modifying statements are not supported, but you can use the results of a
359/// recursive SELECT query in a data-modifying statement. (like so: WITH RECURSIVE
360/// cte_name(a,b,c,d) AS (SELECT ... UNION SELECT ... FROM ... JOIN cte_name ON ... WHERE ...)
361/// DELETE FROM table WHERE table.a = cte_name.a)
362///
363/// It is mandatory to set the [Self::cte]. With queries must have at least one CTE.
364/// Recursive with query generation will panic if you specify more than one CTE.
365///
366/// # Examples
367///
368/// ```
369/// use sea_query::{*, IntoCondition, IntoIden, tests_cfg::*};
370///
371/// let base_query = SelectStatement::new()
372/// .column(Alias::new("id"))
373/// .expr(1i32)
374/// .column(Alias::new("next"))
375/// .column(Alias::new("value"))
376/// .from(Alias::new("table"))
377/// .to_owned();
378///
379/// let cte_referencing = SelectStatement::new()
380/// .column(Alias::new("id"))
381/// .expr(Expr::col(Alias::new("depth")).add(1i32))
382/// .column(Alias::new("next"))
383/// .column(Alias::new("value"))
384/// .from(Alias::new("table"))
385/// .join(
386/// JoinType::InnerJoin,
387/// Alias::new("cte_traversal"),
388/// Expr::col((Alias::new("cte_traversal"), Alias::new("next"))).equals((Alias::new("table"), Alias::new("id")))
389/// )
390/// .to_owned();
391///
392/// let common_table_expression = CommonTableExpression::new()
393/// .query(
394/// base_query.clone().union(UnionType::All, cte_referencing).to_owned()
395/// )
396/// .column(Alias::new("id"))
397/// .column(Alias::new("depth"))
398/// .column(Alias::new("next"))
399/// .column(Alias::new("value"))
400/// .table_name(Alias::new("cte_traversal"))
401/// .to_owned();
402///
403/// let select = SelectStatement::new()
404/// .column(ColumnRef::Asterisk)
405/// .from(Alias::new("cte_traversal"))
406/// .to_owned();
407///
408/// let with_clause = WithClause::new()
409/// .recursive(true)
410/// .cte(common_table_expression)
411/// .cycle(Cycle::new_from_expr_set_using(SimpleExpr::Column(ColumnRef::Column(Alias::new("id").into_iden())), Alias::new("looped"), Alias::new("traversal_path")))
412/// .to_owned();
413///
414/// let query = select.with(with_clause).to_owned();
415///
416/// assert_eq!(
417/// query.to_string(MysqlQueryBuilder),
418/// r#"WITH RECURSIVE `cte_traversal` (`id`, `depth`, `next`, `value`) AS (SELECT `id`, 1, `next`, `value` FROM `table` UNION ALL (SELECT `id`, `depth` + 1, `next`, `value` FROM `table` INNER JOIN `cte_traversal` ON `cte_traversal`.`next` = `table`.`id`)) SELECT * FROM `cte_traversal`"#
419/// );
420/// assert_eq!(
421/// query.to_string(PostgresQueryBuilder),
422/// r#"WITH RECURSIVE "cte_traversal" ("id", "depth", "next", "value") AS (SELECT "id", 1, "next", "value" FROM "table" UNION ALL (SELECT "id", "depth" + 1, "next", "value" FROM "table" INNER JOIN "cte_traversal" ON "cte_traversal"."next" = "table"."id")) CYCLE "id" SET "looped" USING "traversal_path" SELECT * FROM "cte_traversal""#
423/// );
424/// assert_eq!(
425/// query.to_string(SqliteQueryBuilder),
426/// r#"WITH RECURSIVE "cte_traversal" ("id", "depth", "next", "value") AS (SELECT "id", 1, "next", "value" FROM "table" UNION ALL SELECT "id", "depth" + 1, "next", "value" FROM "table" INNER JOIN "cte_traversal" ON "cte_traversal"."next" = "table"."id") SELECT * FROM "cte_traversal""#
427/// );
428/// ```
429#[derive(Debug, Clone, Default, PartialEq)]
430pub struct WithClause {
431 pub(crate) recursive: bool,
432 pub(crate) search: Option<Search>,
433 pub(crate) cycle: Option<Cycle>,
434 pub(crate) cte_expressions: Vec<CommonTableExpression>,
435}
436
437impl WithClause {
438 /// Constructs a new [WithClause].
439 pub fn new() -> Self {
440 Self::default()
441 }
442
443 /// Sets whether this clause is a recursive with clause of not.
444 /// If set to true it will generate a 'WITH RECURSIVE' query.
445 ///
446 /// You can only specify a single [CommonTableExpression] containing a union query
447 /// if this is set to true.
448 pub fn recursive(&mut self, recursive: bool) -> &mut Self {
449 self.recursive = recursive;
450 self
451 }
452
453 /// For recursive WITH queries you can specify the [Search] clause.
454 ///
455 /// This setting is not meaningful if the query is not recursive.
456 ///
457 /// Some databases don't support this clause. In that case this option will be silently ignored.
458 pub fn search(&mut self, search: Search) -> &mut Self {
459 self.search = Some(search);
460 self
461 }
462
463 /// For recursive WITH queries you can specify the [Cycle] clause.
464 ///
465 /// This setting is not meaningful if the query is not recursive.
466 ///
467 /// Some databases don't support this clause. In that case this option will be silently ignored.
468 pub fn cycle(&mut self, cycle: Cycle) -> &mut Self {
469 self.cycle = Some(cycle);
470 self
471 }
472
473 /// Add a [CommonTableExpression] to this with clause.
474 pub fn cte(&mut self, cte: CommonTableExpression) -> &mut Self {
475 self.cte_expressions.push(cte);
476 self
477 }
478
479 /// You can turn this into a [WithQuery] using this function. The resulting WITH query will
480 /// execute the argument query with this WITH clause.
481 pub fn query<T>(self, query: T) -> WithQuery
482 where
483 T: QueryStatementBuilder + 'static,
484 {
485 WithQuery::new().with_clause(self).query(query).to_owned()
486 }
487}
488
489impl From<CommonTableExpression> for WithClause {
490 fn from(cte: CommonTableExpression) -> WithClause {
491 WithClause::new().cte(cte).to_owned()
492 }
493}
494
495/// A WITH query. A simple SQL query that has a WITH clause ([WithClause]).
496///
497/// The [WithClause] can contain one or multiple common table expressions ([CommonTableExpression]).
498///
499/// These named queries can act as a "query local table" that are materialized during execution and
500/// then can be used by the query prefixed with the WITH clause.
501///
502/// A WITH clause can contain multiple of these [CommonTableExpression]. (Except in the case of
503/// recursive WITH query which can only contain one [CommonTableExpression]).
504///
505/// A [CommonTableExpression] is a name, column names and a query returning data for those columns.
506///
507/// Some databases (like sqlite) restrict the acceptable kinds of queries inside of the WITH clause
508/// common table expressions. These databases only allow [SelectStatement]s to form a common table
509/// expression.
510///
511/// Other databases like postgres allow modification queries (UPDATE, DELETE) inside of the WITH
512/// clause but they have to return a table. (They must have a RETURNING clause).
513///
514/// sea-query doesn't check this or restrict the kind of [CommonTableExpression] that you can create
515/// in rust. This means that you can put an UPDATE or DELETE queries into WITH clause and sea-query
516/// will succeed in generating that kind of sql query but the execution inside the database will
517/// fail because they are invalid.
518///
519/// It is your responsibility to ensure that the kind of WITH clause that you put together makes
520/// sense and valid for that database that you are using.
521///
522/// NOTE that for recursive WITH queries (in sql: "WITH RECURSIVE") you can only have a
523/// single [CommonTableExpression] inside of the WITH clause. That query must match certain
524/// requirements:
525/// * It is a query of UNION or UNION ALL of two queries.
526/// * The first part of the query (the left side of the UNION) must be executable first in itself.
527/// It must be non-recursive. (Cannot contain self reference)
528/// * The self reference must appear in the right hand side of the UNION.
529/// * The query can only have a single self-reference.
530/// * Recursive data-modifying statements are not supported, but you can use the results of a
531/// recursive SELECT query in a data-modifying statement. (like so: WITH RECURSIVE
532/// cte_name(a,b,c,d) AS (SELECT ... UNION SELECT ... FROM ... JOIN cte_name ON ... WHERE ...)
533/// DELETE FROM table WHERE table.a = cte_name.a)
534///
535/// It is mandatory to set the [Self::cte] and the [Self::query].
536#[derive(Debug, Clone, Default, PartialEq)]
537pub struct WithQuery {
538 pub(crate) with_clause: WithClause,
539 pub(crate) query: Option<Box<SubQueryStatement>>,
540}
541
542impl WithQuery {
543 /// Constructs a new empty [WithQuery].
544 pub fn new() -> Self {
545 Self::default()
546 }
547
548 /// Set the whole [WithClause].
549 pub fn with_clause(&mut self, with_clause: WithClause) -> &mut Self {
550 self.with_clause = with_clause;
551 self
552 }
553
554 /// Set the [WithClause::recursive]. See that method for more information.
555 pub fn recursive(&mut self, recursive: bool) -> &mut Self {
556 self.with_clause.recursive = recursive;
557 self
558 }
559
560 /// Add the [WithClause::search]. See that method for more information.
561 pub fn search(&mut self, search: Search) -> &mut Self {
562 self.with_clause.search = Some(search);
563 self
564 }
565
566 /// Set the [WithClause::cycle]. See that method for more information.
567 pub fn cycle(&mut self, cycle: Cycle) -> &mut Self {
568 self.with_clause.cycle = Some(cycle);
569 self
570 }
571
572 /// Add a [CommonTableExpression] to the with clause. See [WithClause::cte].
573 pub fn cte(&mut self, cte: CommonTableExpression) -> &mut Self {
574 self.with_clause.cte_expressions.push(cte);
575 self
576 }
577
578 /// Set the query that you execute with the [WithClause].
579 pub fn query<T>(&mut self, query: T) -> &mut Self
580 where
581 T: QueryStatementBuilder,
582 {
583 self.query = Some(Box::new(query.into_sub_query_statement()));
584 self
585 }
586}
587
588impl QueryStatementBuilder for WithQuery {
589 fn build_collect_any_into(&self, query_builder: &dyn QueryBuilder, sql: &mut dyn SqlWriter) {
590 query_builder.prepare_with_query(self, sql);
591 }
592
593 fn into_sub_query_statement(self) -> SubQueryStatement {
594 SubQueryStatement::WithStatement(self)
595 }
596}
597
598#[inherent]
599impl QueryStatementWriter for WithQuery {
600 pub fn build_collect_into<T: QueryBuilder>(&self, query_builder: T, sql: &mut dyn SqlWriter) {
601 query_builder.prepare_with_query(self, sql);
602 }
603
604 pub fn build_collect<T: QueryBuilder>(
605 &self,
606 query_builder: T,
607 sql: &mut dyn SqlWriter,
608 ) -> String;
609 pub fn build<T: QueryBuilder>(&self, query_builder: T) -> (String, Values);
610 pub fn to_string<T: QueryBuilder>(&self, query_builder: T) -> String;
611}