From 6262a1cadca05da98c405f4fc2e24a1498abbc80 Mon Sep 17 00:00:00 2001 From: Ariel Mashraki Date: Sun, 18 Jul 2021 16:08:05 +0300 Subject: [PATCH] examples/fs: document example and add readme --- examples/fs/README.md | 44 +++++++++++++++++++++++++++++++++++++ examples/fs/example_test.go | 8 ++++++- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 examples/fs/README.md diff --git a/examples/fs/README.md b/examples/fs/README.md new file mode 100644 index 000000000..381fae5c4 --- /dev/null +++ b/examples/fs/README.md @@ -0,0 +1,44 @@ +# Recursive Traversal Using [CTE](https://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL#Common_table_expression) + +In this example, we create a file system with a tree structure, and want to query all "undeleted" files. +A file is considered as "deleted", if it's marked as "deleted" (a bool field), or any of its parents is +marked as "deleted". + +Given the following tree structure: + +```console +a/ +├─ b/ +│ ├─ ba +│ ├─ bb +│ └─ bc (deleted) +├─ c/ (deleted) +│ ├─ ca +│ └─ cb +└─ d (deleted) +``` + +Query "undeleted" files should return the following structure: + +```console +a/ +└─ b/ + ├─ ba + └─ bb +``` + +As you can see, in order to check if "cb" (or "ca") is "deleted", we need to "look behind" recursively +until we find a "deleted" parent, or reach the root ("a"). + + +### Generate Assets + +```console +go generate ./... +``` + +### Run Example + +```console +go test +``` diff --git a/examples/fs/example_test.go b/examples/fs/example_test.go index 9660b3d83..1d056121f 100644 --- a/examples/fs/example_test.go +++ b/examples/fs/example_test.go @@ -28,7 +28,7 @@ func Example_RecursiveTraversal() { log.Fatalf("failed creating schema resources: %v", err) } - // Add multiple files in the following ree structure: + // Add multiple files in the following tree structure: // // a/ // ├─ b/ @@ -62,6 +62,8 @@ func Example_RecursiveTraversal() { t1, t2 := sql.Table(file.Table), sql.Table(file.Table) with := sql.WithRecursive("undeleted", file.FieldID, file.FieldParentID) with.As( + // The initial `SELECT` statement executed once at the start, + // and produces the initial row or rows for the recursion. sql.Select(t1.Columns(file.FieldID, file.FieldParentID)...). From(t1). Where( @@ -70,7 +72,10 @@ func Example_RecursiveTraversal() { sql.EQ(t1.C(file.FieldDeleted), false), ), ). + // Merge the `SELECT` statement above with the following: UnionAll( + // A `SELECT` statement that produces additional rows and recurses by referring + // to the CTE name (e.g. "undeleted"), and ends when there are no more new rows. sql.Select(t2.Columns(file.FieldID, file.FieldParentID)...). From(t2). Join(with). @@ -80,6 +85,7 @@ func Example_RecursiveTraversal() { ), ), ) + // Join the root `SELECT` query with the CTE result (`WITH` clause). s.Prefix(with).Join(with).On(s.C(file.FieldID), with.C(file.FieldID)) }). Select(file.FieldName).