with recursive test and bugfixes
Matt S Trout [Tue, 16 Apr 2019 02:10:00 +0000 (02:10 +0000)]
lib/SQL/Abstract/Clauses.pm
lib/SQL/Abstract/ExtraClauses.pm
xt/clauses.t

index fd98e73..18626c2 100644 (file)
@@ -128,6 +128,10 @@ sub _expand_delete_clause_returning {
 sub _expand_statement {
   my ($self, $type, $args) = @_;
   my $ec = $self->{expand_clause};
+  if ($args->{_}) {
+    $args = { %$args };
+    $args->{$type} = delete $args->{_}
+  }
   return +{ "-${type}" => +{
     map {
       my $val = $args->{$_};
index e29aea3..90716df 100644 (file)
@@ -138,10 +138,10 @@ sub register_defaults {
   $self->clause_expander('select.with_recursive' => sub {
     my ($self, $with) = @_;
     my $exp = $self->$with_expander($with);
-    return +{
+    return +(with => +{
       %$exp,
       type => 'recursive'
-    };
+    });
   });
   $self->clause_renderer('select.with' => sub {
     my ($self, $with) = @_;
@@ -280,4 +280,9 @@ sub _render_alias {
   );
 }
 
+sub _expand_update_clause_target {
+  my ($self, $target) = @_;
+  +(target => $self->_expand_from_list(undef, $target));
+}
+
 1;
index df6f2bf..758a2ea 100644 (file)
@@ -197,4 +197,71 @@ is_same_sql(
   q{WITH (foo AS (SELECT 1)) SELECT * FROM foo},
 );
 
+$sql = $sqlac->update({
+  _ => [ 'tree_table', -join => {
+      to => { -select => {
+        with_recursive => [
+          [ tree_with_path => qw(id parent_id path) ],
+          { -select => {
+              _ => [
+                qw(id parent_id),
+                { -as => [
+                  { -cast => { -as => [ id => char => 255 ] } },
+                  'path'
+                ] },
+              ],
+              from => 'tree_table',
+              where => { parent_id => undef },
+              union_all => {
+                -select => {
+                  _ => [ qw(t.id t.parent_id),
+                         { -as => [
+                             { -concat => [ 'r.path', \q{'/'}, 't.id' ] },
+                             'path',
+                         ] },
+                       ],
+                  from => [
+                    tree_table => -as => t =>
+                    -join => {
+                      to => 'tree_with_path',
+                      as => 'r',
+                      on => { 't.parent_id' => 'r.id' },
+                    },
+                  ],
+               } },
+          } },
+        ],
+        select => '*',
+        from => 'tree_with_path'
+      } },
+      as => 'tree',
+      on => { 'tree.id' => 'tree_with_path.id' },
+  } ],
+  set => { path => { -ident => [ qw(tree path) ] } },
+});
+
+is_same_sql(
+  $sql,
+  q{
+    UPDATE tree_table JOIN (
+      WITH RECURSIVE (tree_with_path(id, parent_id, path) AS (
+        (
+          SELECT id, parent_id, CAST(id AS char(255)) AS path
+          FROM tree_table
+          WHERE parent_id IS NULL
+        )
+        UNION ALL
+        (
+           SELECT t.id, t.parent_id, CONCAT(r.path, '/', t.id) AS path
+           FROM tree_table AS t
+           JOIN tree_with_path AS r ON t.parent_id = r.id
+        )
+      ))
+      SELECT * FROM tree_with_path
+    ) AS tree
+    ON tree.id = tree_with_path.id
+    SET path = tree.path
+  },
+);
+
 done_testing;