Server IP : 85.214.239.14 / Your IP : 18.220.130.220 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /proc/2/task/2/cwd/proc/2/cwd/proc/3/root/proc/self/root/usr/share/perl5/SQL/Abstract/ |
Upload File : |
package SQL::Abstract::Reference; 1; __END__ =head1 NAME SQL::Abstract::Reference - Reference documentation for L<SQL::Abstract> =head1 TERMS =head2 Expression (expr) The DWIM structure that's passed to most methods by default is referred to as expression syntax. If you see a variable with C<expr> in the name, or a comment before a code block saying C<# expr>, this is what's being described. =head2 Abstract Query Tree (aqt) The explicit structure that an expression is converted into before it's rendered into SQL is referred to as an abstract query tree. If you see a variable with C<aqt> in the name, or a comment before a code block saying C<# aqt>, this is what's being described. =head2 SQL and Bind Values (query) The final result of L<SQL::Abstract> rendering is generally an SQL statement plus bind values for passing to DBI, ala: my ($sql, @bind) = $sqla->some_method(@args); my @hashes = @{$dbh->do($sql, { Slice => {} }, @bind)}; If you see a comment before a code block saying C<# query>, the SQL + bind array is what's being described. =head2 Expander An expander subroutine is written as: sub { my ($sqla, $name, $value, $k) = @_; ... return $aqt; } $name is the expr node type for node expanders, the op name for op expanders, and the clause name for clause expanders. $value is the body of the thing being expanded If an op expander is being called as the binary operator in a L</hashtriple> expression, $k will be the hash key to be used as the left hand side identifier. This can trivially be converted to an C<ident> type AQT node with: my $ident = $sqla->expand_expr({ -ident => $k }); =head2 Renderer A renderer subroutine looks like: sub { my ($sqla, $type, $value) = @_; ... $sqla->join_query_parts($join, @parts); } and can be registered on a per-type, per-op or per-clause basis. =head1 AQT node types An AQT node consists of a hashref with a single key, whose name is C<-type> where 'type' is the node type, and whose value is the data for the node. The following is an explanation of the built-in AQT type renderers; additional renderers can be registered as part of the extension system. =head2 literal # expr { -literal => [ 'SPANG(?, ?)', 1, 27 ] } # query SPANG(?, ?) [ 1, 27 ] =head2 ident # expr { -ident => 'foo' } # query foo [] # expr { -ident => [ 'foo', 'bar' ] } # query foo.bar [] =head2 bind # expr { -bind => [ 'colname', 'value' ] } # query ? [ 'value' ] =head2 row # expr { -row => [ { -bind => [ 'r', 1 ] }, { -ident => [ 'clown', 'car' ] } ] } # query (?, clown.car) [ 1 ] =head2 func # expr { -func => [ 'foo', { -ident => [ 'bar' ] }, { -bind => [ undef, 7 ] } ] } # query FOO(bar, ?) [ 7 ] =head2 op Standard binop: # expr { -op => [ '=', { -ident => [ 'bomb', 'status' ] }, { -value => 'unexploded' }, ] } # query bomb.status = ? [ 'unexploded' ] Prefix unop: # expr { -op => [ '-', { -ident => 'foo' } ] } # query - foo [] Not as special case parenthesised unop: # expr { -op => [ 'not', { -ident => 'explosive' } ] } # query (NOT explosive) [] Postfix unop: (is_null, is_not_null, asc, desc) # expr { -op => [ 'is_null', { -ident => [ 'bobby' ] } ] } # query bobby IS NULL [] AND and OR: # expr { -op => [ 'and', { -ident => 'x' }, { -ident => 'y' }, { -ident => 'z' } ] } # query ( x AND y AND z ) [] IN (and NOT IN): # expr { -op => [ 'in', { -ident => 'card' }, { -bind => [ 'card', 3 ] }, { -bind => [ 'card', 'J' ] }, ] } # query card IN ( ?, ? ) [ 3, 'J' ] BETWEEN (and NOT BETWEEN): # expr { -op => [ 'between', { -ident => 'pints' }, { -bind => [ 'pints', 2 ] }, { -bind => [ 'pints', 4 ] }, ] } # query ( pints BETWEEN ? AND ? ) [ 2, 4 ] Comma (use -row for parens): # expr { -op => [ ',', { -literal => [ 1 ] }, { -literal => [ 2 ] } ] } # query 1, 2 [] =head2 values # expr { -values => { -row => [ { -bind => [ undef, 1 ] }, { -bind => [ undef, 2 ] } ] } } # query VALUES (?, ?) [ 1, 2 ] # expr { -values => [ { -row => [ { -literal => [ 1 ] }, { -literal => [ 2 ] } ] }, { -row => [ { -literal => [ 3 ] }, { -literal => [ 4 ] } ] }, ] } # query VALUES (1, 2), (3, 4) [] =head2 keyword # expr { -keyword => 'insert_into' } # query INSERT INTO [] =head2 statement types AQT node types are also provided for C<select>, C<insert>, C<update> and C<delete>. These types are handled by the clauses system as discussed later. =head1 Expressions =head2 node expr The simplest expression is just an AQT node: # expr { -ident => [ 'foo', 'bar' ] } # aqt { -ident => [ 'foo', 'bar' ] } # query foo.bar [] However, even in the case of an AQT node, the node value will be expanded if an expander has been registered for that node type: # expr { -ident => 'foo.bar' } # aqt { -ident => [ 'foo', 'bar' ] } # query foo.bar [] =head2 identifier hashpair types =head3 hashtriple # expr { id => { op => 'value' } } # aqt { -op => [ 'op', { -ident => [ 'id' ] }, { -bind => [ 'id', 'value' ] } ] } # query id OP ? [ 'value' ] If the value is undef, attempts to convert equality and like ops to IS NULL, and inequality and not like to IS NOT NULL: # expr { id => { '!=' => undef } } # aqt { -op => [ 'is_not_null', { -ident => [ 'id' ] } ] } # query id IS NOT NULL [] =head3 identifier hashpair w/simple value Equivalent to a hashtriple with an op of '='. # expr { id => 'value' } # aqt { -op => [ '=', { -ident => [ 'id' ] }, { -bind => [ 'id', 'value' ] } ] } # query id = ? [ 'value' ] (an object value will also follow this code path) =head3 identifier hashpair w/undef RHS Converted to IS NULL : # expr { id => undef } # aqt { -op => [ 'is_null', { -ident => [ 'id' ] } ] } # query id IS NULL [] (equivalent to the -is operator) : # expr { id => { -is => undef } } # aqt { -op => [ 'is_null', { -ident => [ 'id' ] } ] } # query id IS NULL [] =head3 identifier hashpair w/literal RHS Directly appended to the key, remember you need to provide an operator: # expr { id => \"= dont_try_this_at_home" } # aqt { -literal => [ 'id = dont_try_this_at_home' ] } # query id = dont_try_this_at_home [] # expr { id => \[ "= seriously(?, ?, ?, ?)", "use", "-ident", "and", "-func", ] } # aqt { -literal => [ 'id = seriously(?, ?, ?, ?)', 'use', -ident => 'and', '-func' ] } # query id = seriously(?, ?, ?, ?) [ 'use', -ident => 'and', '-func' ] (you may absolutely use this when there's no built-in expression type for what you need and registering a custom one would be more hassle than it's worth, but, y'know, do try and avoid it) =head3 identifier hashpair w/arrayref value Becomes equivalent to a -or over an arrayref of hashrefs with the identifier as key and the member of the original arrayref as the value: # expr { id => [ 3, 4, { '>' => 12 } ] } # aqt { -op => [ 'or', { -op => [ '=', { -ident => [ 'id' ] }, { -bind => [ 'id', 3 ] } ] }, { -op => [ '=', { -ident => [ 'id' ] }, { -bind => [ 'id', 4 ] } ] }, { -op => [ '>', { -ident => [ 'id' ] }, { -bind => [ 'id', 12 ] } ] }, ] } # query ( id = ? OR id = ? OR id > ? ) [ 3, 4, 12 ] # expr { -or => [ { id => 3 }, { id => 4 }, { id => { '>' => 12 } } ] } # aqt { -op => [ 'or', { -op => [ '=', { -ident => [ 'id' ] }, { -bind => [ 'id', 3 ] } ] }, { -op => [ '=', { -ident => [ 'id' ] }, { -bind => [ 'id', 4 ] } ] }, { -op => [ '>', { -ident => [ 'id' ] }, { -bind => [ 'id', 12 ] } ] }, ] } # query ( id = ? OR id = ? OR id > ? ) [ 3, 4, 12 ] Special Case: If the first element of the arrayref is -or or -and, that's used as the top level logic op: # expr { id => [ -and => { '>' => 3 }, { '<' => 6 } ] } # aqt { -op => [ 'and', { -op => [ '>', { -ident => [ 'id' ] }, { -bind => [ 'id', 3 ] } ] }, { -op => [ '<', { -ident => [ 'id' ] }, { -bind => [ 'id', 6 ] } ] }, ] } # query ( id > ? AND id < ? ) [ 3, 6 ] =head3 identifier hashpair w/hashref value Becomes equivalent to a -and over an arrayref of hashtriples constructed with the identifier as the key and each key/value pair of the original hashref as the value: # expr { id => { '<' => 4, '>' => 3 } } # aqt { -op => [ 'and', { -op => [ '<', { -ident => [ 'id' ] }, { -bind => [ 'id', 4 ] } ] }, { -op => [ '>', { -ident => [ 'id' ] }, { -bind => [ 'id', 3 ] } ] }, ] } # query ( id < ? AND id > ? ) [ 4, 3 ] is sugar for: # expr { -and => [ { id => { '<' => 4 } }, { id => { '>' => 3 } } ] } # aqt { -op => [ 'and', { -op => [ '<', { -ident => [ 'id' ] }, { -bind => [ 'id', 4 ] } ] }, { -op => [ '>', { -ident => [ 'id' ] }, { -bind => [ 'id', 3 ] } ] }, ] } # query ( id < ? AND id > ? ) [ 4, 3 ] =head2 operator hashpair types A hashpair whose key begins with a -, or whose key consists entirely of nonword characters (thereby covering '=', '>', pg json ops, etc.) is processed as an operator hashpair. =head3 operator hashpair w/node type If a node type expander is registered for the key, the hashpair is treated as a L</node expr>. =head3 operator hashpair w/registered op If an expander is registered for the op name, that's run and the result returned: # expr { -in => [ 'foo', 1, 2, 3 ] } # aqt { -op => [ 'in', { -ident => [ 'foo' ] }, { -bind => [ undef, 1 ] }, { -bind => [ undef, 2 ] }, { -bind => [ undef, 3 ] }, ] } # query foo IN ( ?, ?, ? ) [ 1, 2, 3 ] =head3 operator hashpair w/not prefix If the op name starts -not_ this is stripped and turned into a -not wrapper around the result: # expr { -not_ident => 'foo' } # aqt { -op => [ 'not', { -ident => [ 'foo' ] } ] } # query (NOT foo) [] is equivalent to: # expr { -not => { -ident => 'foo' } } # aqt { -op => [ 'not', { -ident => [ 'foo' ] } ] } # query (NOT foo) [] =head3 operator hashpair with unknown op If the C<unknown_unop_always_func> option is set (which is recommended but defaults to off for backwards compatibility reasons), an unknown op expands into a C<-func> node: # expr { -count => { -ident => '*' } } # aqt { -func => [ 'count', { -ident => [ '*' ] } ] } # query COUNT(*) [] If not, an unknown op will expand into a C<-op> node. =head2 hashref expr A hashref with more than one pair becomes a C<-and> over its hashpairs, i.e. # expr { x => 1, y => 2 } # aqt { -op => [ 'and', { -op => [ '=', { -ident => [ 'x' ] }, { -bind => [ 'x', 1 ] } ] }, { -op => [ '=', { -ident => [ 'y' ] }, { -bind => [ 'y', 2 ] } ] }, ] } # query ( x = ? AND y = ? ) [ 1, 2 ] is short hand for: # expr { -and => [ { x => 1 }, { y => 2 } ] } # aqt { -op => [ 'and', { -op => [ '=', { -ident => [ 'x' ] }, { -bind => [ 'x', 1 ] } ] }, { -op => [ '=', { -ident => [ 'y' ] }, { -bind => [ 'y', 2 ] } ] }, ] } # query ( x = ? AND y = ? ) [ 1, 2 ] =head2 arrayref expr An arrayref becomes a C<-or> over its contents. Arrayrefs, hashrefs and literals are all expanded and added to the clauses of the C<-or>. If the arrayref contains a scalar it's treated as the key of a hashpair and the next element as the value. # expr [ { x => 1 }, [ { y => 2 }, { z => 3 } ], 'key', 'value', \"lit()" ] # aqt { -op => [ 'or', { -op => [ '=', { -ident => [ 'x' ] }, { -bind => [ 'x', 1 ] } ] }, { -op => [ 'or', { -op => [ '=', { -ident => [ 'y' ] }, { -bind => [ 'y', 2 ] } ] }, { -op => [ '=', { -ident => [ 'z' ] }, { -bind => [ 'z', 3 ] } ] }, ] }, { -op => [ '=', { -ident => [ 'key' ] }, { -bind => [ 'key', 'value' ] }, ] }, { -literal => [ 'lit()' ] }, ] } # query ( x = ? OR ( y = ? OR z = ? ) OR key = ? OR lit() ) [ 1, 2, 3, 'value' ] =head1 Default Expanders =head2 bool Turns the old -bool syntax into the value expression, i.e. # expr { -bool => { -ident => 'foo' } } # aqt { -ident => [ 'foo' ] } # query foo [] behaves the same way as the now-directly-supported # expr { -ident => 'foo' } # aqt { -ident => [ 'foo' ] } # query foo [] =head2 row Expands the elements of the value arrayref: # expr { -row => [ 1, { -ident => 'foo' }, 2, 3 ] } # aqt { -row => [ { -bind => [ undef, 1 ] }, { -ident => [ 'foo' ] }, { -bind => [ undef, 2 ] }, { -bind => [ undef, 3 ] }, ] } # query (?, foo, ?, ?) [ 1, 2, 3 ] =head2 op If an expander is registered for the op name, delegates to the expander; if not, expands the argument values: # expr { -op => [ 'ident', 'foo.bar' ] } # aqt { -ident => [ 'foo', 'bar' ] } # query foo.bar [] # expr { -op => [ '=', { -ident => 'foo' }, 3 ] } # aqt { -op => [ '=', { -ident => [ 'foo' ] }, { -bind => [ undef, 3 ] } ] } # query foo = ? [ 3 ] =head2 func Expands the argument values: # expr { -func => [ 'coalesce', { -ident => 'thing' }, 'fallback' ] } # aqt { -func => [ 'coalesce', { -ident => [ 'thing' ] }, { -bind => [ undef, 'fallback' ] }, ] } # query COALESCE(thing, ?) [ 'fallback' ] =head2 values A hashref value is expanded as an expression: # expr { -values => { -row => [ 1, 2 ] } } # aqt { -values => [ { -row => [ { -bind => [ undef, 1 ] }, { -bind => [ undef, 2 ] } ] } ] } # query VALUES (?, ?) [ 1, 2 ] An arrayref value's elements are either expressions or arrayrefs to be treated as rows: # expr { -values => [ { -row => [ 1, 2 ] }, [ 3, 4 ] ] } # aqt { -values => [ { -row => [ { -bind => [ undef, 1 ] }, { -bind => [ undef, 2 ] } ] }, { -row => [ { -bind => [ undef, 3 ] }, { -bind => [ undef, 4 ] } ] }, ] } # query VALUES (?, ?), (?, ?) [ 1, 2, 3, 4 ] =head2 list Expects a value or an arrayref of values, expands them, and returns just the expanded aqt for a single entry or a comma operator for multiple: # expr { -list => [ { -ident => 'foo' } ] } # aqt { -op => [ ',', { -ident => [ 'foo' ] } ] } # query foo [] # expr { -list => [ { -ident => 'foo' }, { -ident => 'bar' } ] } # aqt { -op => [ ',', { -ident => [ 'foo' ] }, { -ident => [ 'bar' ] } ] } # query foo, bar [] =head2 between op The RHS of between must either be a pair of exprs/plain values, or a single literal expr: # expr { -between => [ 'size', 3, { -ident => 'max_size' } ] } # aqt { -op => [ 'between', { -ident => [ 'size' ] }, { -bind => [ undef, 3 ] }, { -ident => [ 'max_size' ] }, ] } # query ( size BETWEEN ? AND max_size ) [ 3 ] # expr { size => { -between => [ 3, { -ident => 'max_size' } ] } } # aqt { -op => [ 'between', { -ident => [ 'size' ] }, { -bind => [ 'size', 3 ] }, { -ident => [ 'max_size' ] }, ] } # query ( size BETWEEN ? AND max_size ) [ 3 ] # expr { size => { -between => \"3 AND 7" } } # aqt { -op => [ 'between', { -ident => [ 'size' ] }, { -literal => [ '3 AND 7' ] }, ] } # query ( size BETWEEN 3 AND 7 ) [] not_between is also expanded: # expr { size => { -not_between => [ 3, 7 ] } } # aqt { -op => [ 'not_between', { -ident => [ 'size' ] }, { -bind => [ 'size', 3 ] }, { -bind => [ 'size', 7 ] }, ] } # query ( size NOT BETWEEN ? AND ? ) [ 3, 7 ] =head2 in op The RHS of in/not_in is either an expr/value or an arrayref of exprs/values: # expr { foo => { -in => [ 1, 2 ] } } # aqt { -op => [ 'in', { -ident => [ 'foo' ] }, { -bind => [ 'foo', 1 ] }, { -bind => [ 'foo', 2 ] }, ] } # query foo IN ( ?, ? ) [ 1, 2 ] # expr { bar => { -not_in => \"(1, 2)" } } # aqt { -op => [ 'not_in', { -ident => [ 'bar' ] }, { -literal => [ '1, 2' ] } ] } # query bar NOT IN ( 1, 2 ) [] A non-trivial LHS is expanded with ident as the default rather than value: # expr { -in => [ { -row => [ 'x', 'y' ] }, { -row => [ 1, 2 ] }, { -row => [ 3, 4 ] }, ] } # aqt { -op => [ 'in', { -row => [ { -ident => [ 'x' ] }, { -ident => [ 'y' ] } ] }, { -row => [ { -bind => [ undef, 1 ] }, { -bind => [ undef, 2 ] } ] }, { -row => [ { -bind => [ undef, 3 ] }, { -bind => [ undef, 4 ] } ] }, ] } # query (x, y) IN ( (?, ?), (?, ?) ) [ 1, 2, 3, 4 ] =head2 and/or ops expands the same way as a plain arrayref/hashref expression but with the logic type set to the op name. =head2 is op Expands is and is_not to null checks, RHS value must be undef: # expr { -is => [ 'foo', undef ] } # aqt { -op => [ 'is_null', { -ident => [ 'foo' ] } ] } # query foo IS NULL [] # expr { bar => { -is_not => undef } } # aqt { -op => [ 'is_not_null', { -ident => [ 'bar' ] } ] } # query bar IS NOT NULL [] =head2 ident op Expands a string ident to an arrayref by splitting on the configured separator, almost always '.': # expr { -ident => 'foo.bar' } # aqt { -ident => [ 'foo', 'bar' ] } # query foo.bar [] =head2 value op Expands to a bind node with the currently applicable column name if known: # expr { foo => { '=' => { -value => 3 } } } # aqt { -op => [ '=', { -ident => [ 'foo' ] }, { -bind => [ 'foo', 3 ] } ] } # query foo = ? [ 3 ] =head1 Query Types =head2 select A select node accepts select, from, where and order_by clauses. The select clause is expanded as a list expression with a -ident default: # expr { -select => { _ => [ 'foo', 'bar', { -count => 'baz' } ] } } # aqt { -select => { select => { -op => [ ',', { -ident => [ 'foo' ] }, { -ident => [ 'bar' ] }, { -func => [ 'count', { -ident => [ 'baz' ] } ] }, ] } } } # query SELECT foo, bar, COUNT(baz) [] The from clause is expanded as a list expression with a -ident default: # expr { -select => { from => [ 'schema1.table1', { -ident => [ 'schema2', 'table2' ] } ] } } # aqt { -select => { from => { -from_list => [ { -ident => [ 'schema1', 'table1' ] }, { -ident => [ 'schema2', 'table2' ] }, ] } } } # query FROM schema1.table1, schema2.table2 [] The where clause is expanded as a plain expression: # expr { -select => { where => { foo => 3 } } } # aqt { -select => { where => { -op => [ '=', { -ident => [ 'foo' ] }, { -bind => [ 'foo', 3 ] } ] } } } # query WHERE foo = ? [ 3 ] The order_by clause expands as a list expression at top level, but a hashref element may be either an expr or a hashpair with key -asc or -desc to indicate an order by direction: # expr { -select => { order_by => [ 'foo', { -desc => 'bar' }, { -max => 'baz' } ] } } # aqt { -select => { order_by => { -op => [ ',', { -ident => [ 'foo' ] }, { -op => [ ',', { -op => [ 'desc', { -ident => [ 'bar' ] } ] } ] }, { -func => [ 'max', { -ident => [ 'baz' ] } ] }, ] } } } # query ORDER BY foo, bar DESC, MAX(baz) [] =head2 An insert node accepts an into/target clause, a fields clause, a values/from clause, and a returning clause. The target clause is expanded with an ident default. The fields clause is expanded as a list expression if an arrayref, and otherwise passed through. The from clause may either be an expr, a literal, an arrayref of column values, or a hashref mapping colum names to values. The returning clause is expanded as a list expr with an ident default. # expr { -insert => { into => 'foo', returning => 'id', values => { bar => 'yay', baz => 'argh' }, } } # aqt { -insert => { fields => { -row => [ { -ident => [ 'bar' ] }, { -ident => [ 'baz' ] } ] }, from => { -values => [ { -row => [ { -bind => [ 'bar', 'yay' ] }, { -bind => [ 'baz', 'argh' ] }, ] } ] }, returning => { -op => [ ',', { -ident => [ 'id' ] } ] }, target => { -ident => [ 'foo' ] }, } } # query INSERT INTO foo (bar, baz) VALUES (?, ?) RETURNING id [ 'yay', 'argh' ] # expr { -insert => { fields => [ 'bar', 'baz' ], from => { -select => { _ => [ 'bar', 'baz' ], from => 'other' } }, into => 'foo', } } # aqt { -insert => { fields => { -row => [ { -op => [ ',', { -ident => [ 'bar' ] }, { -ident => [ 'baz' ] } ] } ] }, from => { -select => { from => { -ident => [ 'other' ] }, select => { -op => [ ',', { -ident => [ 'bar' ] }, { -ident => [ 'baz' ] } ] }, } }, target => { -ident => [ 'foo' ] }, } } # query INSERT INTO foo (bar, baz) SELECT bar, baz FROM other [] =head2 update An update node accepts update/target (either may be used at expansion time), set, where, and returning clauses. The target clause is expanded with an ident default. The set clause (if not already a list expr) is expanded as a hashref where the keys are identifiers to be set and the values are exprs/values. The where clauses is expanded as a normal expr. The returning clause is expanded as a list expr with an ident default. # expr { -update => { _ => 'foo', returning => [ 'id', 'baz' ], set => { bar => 3, baz => { baz => { '+' => 1 } } }, where => { -not => { -ident => 'quux' } }, } } # aqt { -update => { returning => { -op => [ ',', { -ident => [ 'id' ] }, { -ident => [ 'baz' ] } ] }, set => { -op => [ ',', { -op => [ '=', { -ident => [ 'bar' ] }, { -bind => [ 'bar', 3 ] } ] }, { -op => [ '=', { -ident => [ 'baz' ] }, { -op => [ '+', { -ident => [ 'baz' ] }, { -bind => [ 'baz', 1 ] }, ] }, ] }, ] }, target => { -ident => [ 'foo' ] }, where => { -op => [ 'not', { -ident => [ 'quux' ] } ] }, } } # query UPDATE foo SET bar = ?, baz = baz + ? WHERE (NOT quux) RETURNING id, baz [ 3, 1 ] =head2 delete delete accepts from/target, where, and returning clauses. The target clause is expanded with an ident default. The where clauses is expanded as a normal expr. The returning clause is expanded as a list expr with an ident default. # expr { -delete => { from => 'foo', returning => 'id', where => { bar => { '<' => 10 } }, } } # aqt { -delete => { returning => { -op => [ ',', { -ident => [ 'id' ] } ] }, target => { -op => [ ',', { -ident => [ 'foo' ] } ] }, where => { -op => [ '<', { -ident => [ 'bar' ] }, { -bind => [ 'bar', 10 ] } ] }, } } # query DELETE FROM foo WHERE bar < ? RETURNING id [ 10 ] =cut