From 837d077f984d290d098e4da6b056b8ddbe3d5d5a Mon Sep 17 00:00:00 2001 From: Ariel Mashraki <7413593+a8m@users.noreply.github.com> Date: Thu, 29 Sep 2022 17:42:22 +0300 Subject: [PATCH] doc: add Append to crud page (#2976) --- doc/md/code-gen.md | 2 +- doc/md/{crud.md => crud.mdx} | 142 +++++++++++------- doc/md/features.md | 12 +- ...getting-started.md => getting-started.mdx} | 81 +++++----- doc/md/hooks.md | 2 +- 5 files changed, 137 insertions(+), 102 deletions(-) rename doc/md/{crud.md => crud.mdx} (86%) rename doc/md/{getting-started.md => getting-started.mdx} (91%) diff --git a/doc/md/code-gen.md b/doc/md/code-gen.md index 8400b3f01..f87d5967f 100755 --- a/doc/md/code-gen.md +++ b/doc/md/code-gen.md @@ -38,7 +38,7 @@ go generate ./ent The `generate` command generates the following assets for the schemas: - `Client` and `Tx` objects used for interacting with the graph. -- CRUD builders for each schema type. See [CRUD](crud.md) for more info. +- CRUD builders for each schema type. See [CRUD](crud.mdx) for more info. - Entity object (Go struct) for each of the schema types. - Package containing constants and predicates used for interacting with the builders. - A `migrate` package for SQL dialects. See [Migration](migrate.md) for more info. diff --git a/doc/md/crud.md b/doc/md/crud.mdx similarity index 86% rename from doc/md/crud.md rename to doc/md/crud.mdx index 1e5f93715..a1982c9d7 100755 --- a/doc/md/crud.md +++ b/doc/md/crud.mdx @@ -3,70 +3,38 @@ id: crud title: CRUD API --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + As mentioned in the [introduction](code-gen.md) section, running `ent` on the schemas, will generate the following assets: - `Client` and `Tx` objects used for interacting with the graph. -- CRUD builders for each schema type. See [CRUD](crud.md) for more info. +- CRUD builders for each schema type. - Entity object (Go struct) for each of the schema type. - Package containing constants and predicates used for interacting with the builders. - A `migrate` package for SQL dialects. See [Migration](migrate.md) for more info. ## Create A New Client -**MySQL** + + ```go package main import ( + "context" "log" - "/ent" - - _ "github.com/go-sql-driver/mysql" -) - -func main() { - client, err := ent.Open("mysql", ":@tcp(:)/?parseTime=True") - if err != nil { - log.Fatal(err) - } - defer client.Close() -} -``` - -**PostgreSQL** - -```go -package main - -import ( - "log" - - "/ent" - - _ "github.com/lib/pq" -) - -func main() { - client, err := ent.Open("postgres","host= port= user= dbname= password=") - if err != nil { - log.Fatal(err) - } - defer client.Close() -} -``` - -**SQLite** - -```go -package main - -import ( - "log" - - "/ent" + "entdemo/ent" _ "github.com/mattn/go-sqlite3" ) @@ -74,14 +42,75 @@ import ( func main() { client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") if err != nil { - log.Fatal(err) + log.Fatalf("failed opening connection to sqlite: %v", err) } defer client.Close() + // Run the auto migration tool. + if err := client.Schema.Create(context.Background()); err != nil { + log.Fatalf("failed creating schema resources: %v", err) + } } ``` + + -**Gremlin (AWS Neptune)** +```go +package main + +import ( + "context" + "log" + + "entdemo/ent" + + _ "github.com/lib/pq" +) + +func main() { + client, err := ent.Open("postgres","host= port= user= dbname= password=") + if err != nil { + log.Fatalf("failed opening connection to postgres: %v", err) + } + defer client.Close() + // Run the auto migration tool. + if err := client.Schema.Create(context.Background()); err != nil { + log.Fatalf("failed creating schema resources: %v", err) + } +} +``` + + + + +```go +package main + +import ( + "context" + "log" + + "entdemo/ent" + + _ "github.com/go-sql-driver/mysql" +) + +func main() { + client, err := ent.Open("mysql", ":@tcp(:)/?parseTime=True") + if err != nil { + log.Fatalf("failed opening connection to mysql: %v", err) + } + defer client.Close() + // Run the auto migration tool. + if err := client.Schema.Create(context.Background()); err != nil { + log.Fatalf("failed creating schema resources: %v", err) + } +} +``` + + + + ```go package main @@ -89,7 +118,7 @@ package main import ( "log" - "/ent" + "entdemo/ent" ) func main() { @@ -100,6 +129,9 @@ func main() { } ``` + + + ## Create An Entity **Save** a user. @@ -143,9 +175,11 @@ Update an entity that was returned from the database. ```go a8m, err = a8m.Update(). // User update builder. - RemoveGroup(g2). // Remove specific edge. - ClearCard(). // Clear unique edge. - SetAge(30). // Set field value + RemoveGroup(g2). // Remove a specific edge. + ClearCard(). // Clear a unique edge. + SetAge(30). // Set a field value. + AddRank(10). // Increment a field value. + AppendInts([]int{1}). // Append values to a JSON array. Save(ctx) // Save and return. ``` @@ -447,7 +481,7 @@ _, err := client.File. ## Mutation -Each generated node type has its own type of mutation. For example, all [`User` builders](crud.md#create-an-entity), share +Each generated node type has its own type of mutation. For example, all [`User` builders](crud.mdx#create-an-entity), share the same generated `UserMutation` object. However, all builder types implement the generic `ent.Mutation` interface. diff --git a/doc/md/features.md b/doc/md/features.md index db4e56fdc..5a8cdc114 100644 --- a/doc/md/features.md +++ b/doc/md/features.md @@ -290,12 +290,12 @@ UPDATE `users` SET `id` = `id` + 1 ORDER BY `id` DESC #### Modify Example 7 -Append a list of values to a JSON column: +Append elements to the `values` array in a JSON column: ```go client.User.Update(). Modify(func(u *sql.UpdateBuilder) { - sqljson.Append(u, user.FieldTags, []string{"tag1", "tag2"}) + sqljson.Append(u, user.FieldTags, []string{"tag1", "tag2"}, sqljson.Path("values")) }). ExecX(ctx) ``` @@ -304,9 +304,9 @@ The above code will produce the following SQL query: ```sql UPDATE `users` SET `tags` = CASE - WHEN (JSON_TYPE(JSON_EXTRACT(`tags`, '$')) IS NULL OR JSON_TYPE(JSON_EXTRACT(`tags`, '$')) = 'NULL') - THEN JSON_ARRAY(?, ?) - ELSE JSON_ARRAY_APPEND(`tags`, '$', ?, '$', ?) END + WHEN (JSON_TYPE(JSON_EXTRACT(`tags`, '$.values')) IS NULL OR JSON_TYPE(JSON_EXTRACT(`tags`, '$.values')) = 'NULL') + THEN JSON_SET(`tags`, '$.values', JSON_ARRAY(?, ?)) + ELSE JSON_ARRAY_APPEND(`tags`, '$.values', ?, '$.values', ?) END WHERE `id` = ? ``` @@ -344,7 +344,7 @@ application such as hooks, privacy (authorization), and validators. ### Upsert The `sql/upsert` option lets configure upsert and bulk-upsert logic using the SQL `ON CONFLICT` / `ON DUPLICATE KEY` -syntax. For full documentation, go to the [Upsert API](crud.md#upsert-one). +syntax. For full documentation, go to the [Upsert API](crud.mdx#upsert-one). This option can be added to a project using the `--feature sql/upsert` flag. diff --git a/doc/md/getting-started.md b/doc/md/getting-started.mdx similarity index 91% rename from doc/md/getting-started.md rename to doc/md/getting-started.mdx index 4058ee8f9..a47be7fb4 100755 --- a/doc/md/getting-started.md +++ b/doc/md/getting-started.mdx @@ -24,7 +24,7 @@ If your project directory is outside [GOPATH](https://github.com/golang/go/wiki/ GOPATH, setup a [Go module](https://github.com/golang/go/wiki/Modules#quick-start) project as follows: ```console -go mod init +go mod init entdemo ``` ## Create Your First Schema @@ -35,9 +35,9 @@ Go to the root directory of your project, and run: go run -mod=mod entgo.io/ent/cmd/ent init User ``` -The command above will generate the schema for `User` under `/ent/schema/` directory: +The command above will generate the schema for `User` under `entdemo/ent/schema/` directory: -```go title="/ent/schema/user.go" +```go title="entdemo/ent/schema/user.go" package schema @@ -62,7 +62,7 @@ func (User) Edges() []ent.Edge { Add 2 fields to the `User` schema: -```go title="/ent/schema/user.go" +```go title="entdemo/ent/schema/user.go" package schema @@ -125,14 +125,14 @@ values={[ ]}> -```go title="/start/start.go" +```go title="entdemo/start.go" package main import ( "context" "log" - "/ent" + "entdemo/ent" _ "github.com/mattn/go-sqlite3" ) @@ -153,14 +153,14 @@ func main() { -```go title="/start/start.go" +```go title="entdemo/start.go" package main import ( "context" "log" - "/ent" + "entdemo/ent" _ "github.com/lib/pq" ) @@ -181,14 +181,14 @@ func main() { -```go title="/start/start.go" +```go title="entdemo/start/start.go" package main import ( "context" "log" - "/ent" + "entdemo/ent" _ "github.com/go-sql-driver/mysql" ) @@ -211,7 +211,7 @@ func main() { Now, we're ready to create our user. Let's call this function `CreateUser` for the sake of example: -```go title="/start/start.go" +```go title="entdemo/start.go" func CreateUser(ctx context.Context, client *ent.Client) (*ent.User, error) { u, err := client.User. Create(). @@ -231,14 +231,14 @@ func CreateUser(ctx context.Context, client *ent.Client) (*ent.User, error) { `ent` generates a package for each entity schema that contains its predicates, default values, validators and additional information about storage elements (column names, primary keys, etc). -```go title="/start/start.go" +```go title="entdemo/start.go" package main import ( "log" - "/ent" - "/ent/user" + "entdemo/ent" + "entdemo/ent/user" ) func QueryUser(ctx context.Context, client *ent.Client) (*ent.User, error) { @@ -258,6 +258,7 @@ func QueryUser(ctx context.Context, client *ent.Client) (*ent.User, error) { ## Add Your First Edge (Relation) + In this part of the tutorial, we want to declare an edge (relation) to another entity in the schema. Let's create 2 additional entities named `Car` and `Group` with a few fields. We use `ent` CLI to generate the initial schemas: @@ -268,7 +269,7 @@ go run -mod=mod entgo.io/ent/cmd/ent init Car Group And then we add the rest of the fields manually: -```go title="/ent/schema/car.go" +```go title="entdemo/ent/schema/car.go" // Fields of the Car. func (Car) Fields() []ent.Field { return []ent.Field{ @@ -278,7 +279,7 @@ func (Car) Fields() []ent.Field { } ``` -```go title="/ent/schema/group.go" +```go title="entdemo/ent/schema/group.go" // Fields of the Group. func (Group) Fields() []ent.Field { return []ent.Field{ @@ -296,7 +297,7 @@ can **have 1 or more** cars, but a car **has only one** owner (one-to-many relat Let's add the `"cars"` edge to the `User` schema, and run `go generate ./ent`: -```go title="/ent/schema/user.go" +```go title="entdemo/ent/schema/user.go" // Edges of the User. func (User) Edges() []ent.Edge { @@ -308,12 +309,12 @@ func (User) Edges() []ent.Edge { We continue our example by creating 2 cars and adding them to a user. -```go title="/start/start.go" +```go title="entdemo/start.go" import ( - "/ent" - "/ent/car" - "/ent/user" + "entdemo/ent" + "entdemo/ent/car" + "entdemo/ent/user" ) func CreateCars(ctx context.Context, client *ent.Client) (*ent.User, error) { @@ -356,12 +357,12 @@ func CreateCars(ctx context.Context, client *ent.Client) (*ent.User, error) { ``` But what about querying the `cars` edge (relation)? Here's how we do it: -```go title="/start/start.go" +```go title="entdemo/start.go" import ( "log" - "/ent" - "/ent/car" + "entdemo/ent" + "entdemo/ent/car" ) func QueryCars(ctx context.Context, a8m *ent.User) error { @@ -396,7 +397,7 @@ edge in the database. It's just a back-reference to the real edge (relation). Let's add an inverse edge named `owner` to the `Car` schema, reference it to the `cars` edge in the `User` schema, and run `go generate ./ent`. -```go title="/ent/schema/car.go" +```go title="entdemo/ent/schema/car.go" // Edges of the Car. func (Car) Edges() []ent.Edge { return []ent.Edge{ @@ -413,13 +414,13 @@ func (Car) Edges() []ent.Edge { ``` We'll continue the user/cars example above by querying the inverse edge. -```go title="/start/start.go" +```go title="entdemo/start.go" import ( "fmt" "log" - "/ent" - "/ent/user" + "entdemo/ent" + "entdemo/ent/user" ) func QueryCarUsers(ctx context.Context, a8m *ent.User) error { @@ -450,7 +451,7 @@ a simple "many-to-many" relationship. In the above illustration, the `Group` sch of the `users` edge (relation), and the `User` entity has a back-reference/inverse edge to this relationship named `groups`. Let's define this relationship in our schemas: -```go title="/ent/schema/group.go" +```go title="entdemo/ent/schema/group.go" // Edges of the Group. func (Group) Edges() []ent.Edge { return []ent.Edge{ @@ -459,7 +460,7 @@ func (Group) Edges() []ent.Edge { } ``` -```go title="/ent/schema/user.go" +```go title="entdemo/ent/schema/user.go" // Edges of the User. func (User) Edges() []ent.Edge { return []ent.Edge{ @@ -486,7 +487,7 @@ entities and relations). Let's create the following graph using the framework: ![re-graph](https://entgo.io/images/assets/re_graph_getting_started.png) -```go title="/start/start.go" +```go title="entdemo/start.go" func CreateGraph(ctx context.Context, client *ent.Client) error { // First, create the users. a8m, err := client.User. @@ -562,12 +563,12 @@ Now when we have a graph with data, we can run a few queries on it: 1. Get all user's cars within the group named "GitHub": - ```go title="/start/start.go" + ```go title="entdemo/start.go" import ( "log" - "/ent" - "/ent/group" + "entdemo/ent" + "entdemo/ent/group" ) func QueryGithub(ctx context.Context, client *ent.Client) error { @@ -588,12 +589,12 @@ Now when we have a graph with data, we can run a few queries on it: 2. Change the query above, so that the source of the traversal is the user *Ariel*: - ```go title="/start/start.go" + ```go title="entdemo/start.go" import ( "log" - "/ent" - "/ent/car" + "entdemo/ent" + "entdemo/ent/car" ) func QueryArielCars(ctx context.Context, client *ent.Client) error { @@ -626,12 +627,12 @@ Now when we have a graph with data, we can run a few queries on it: 3. Get all groups that have users (query with a look-aside predicate): - ```go title="/start/start.go" + ```go title="entdemo/start.go" import ( "log" - "/ent" - "/ent/group" + "entdemo/ent" + "entdemo/ent/group" ) func QueryGroupWithUsers(ctx context.Context, client *ent.Client) error { diff --git a/doc/md/hooks.md b/doc/md/hooks.md index 14bc36750..9b02c404d 100755 --- a/doc/md/hooks.md +++ b/doc/md/hooks.md @@ -17,7 +17,7 @@ There are 5 types of mutations: - `DeleteOne` - Delete a node from the graph. - `Delete` - Delete all nodes that match a predicate. -Each generated node type has its own type of mutation. For example, all [`User` builders](crud.md#create-an-entity), share +Each generated node type has its own type of mutation. For example, all [`User` builders](crud.mdx#create-an-entity), share the same generated `UserMutation` object. However, all builder types implement the generic `ent.Mutation` interface.