├── .github ├── CHANGELOG.md ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── testing.yaml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── _examples ├── basic │ └── ent │ │ ├── auditing.go │ │ ├── character.go │ │ ├── character │ │ ├── character.go │ │ └── where.go │ │ ├── character_create.go │ │ ├── character_delete.go │ │ ├── character_query.go │ │ ├── character_update.go │ │ ├── characterhistory.go │ │ ├── characterhistory │ │ ├── characterhistory.go │ │ └── where.go │ │ ├── characterhistory_create.go │ │ ├── characterhistory_delete.go │ │ ├── characterhistory_query.go │ │ ├── characterhistory_update.go │ │ ├── client.go │ │ ├── ent.go │ │ ├── entc.go │ │ ├── enttest │ │ └── enttest.go │ │ ├── friendship.go │ │ ├── friendship │ │ ├── friendship.go │ │ └── where.go │ │ ├── friendship_create.go │ │ ├── friendship_delete.go │ │ ├── friendship_query.go │ │ ├── friendship_update.go │ │ ├── friendshiphistory.go │ │ ├── friendshiphistory │ │ ├── friendshiphistory.go │ │ └── where.go │ │ ├── friendshiphistory_create.go │ │ ├── friendshiphistory_delete.go │ │ ├── friendshiphistory_query.go │ │ ├── friendshiphistory_update.go │ │ ├── generate.go │ │ ├── history_from_mutation.go │ │ ├── history_query.go │ │ ├── hook │ │ └── hook.go │ │ ├── internal │ │ └── schema.go │ │ ├── migrate │ │ ├── migrate.go │ │ └── schema.go │ │ ├── mutation.go │ │ ├── predicate │ │ └── predicate.go │ │ ├── residence.go │ │ ├── residence │ │ ├── residence.go │ │ └── where.go │ │ ├── residence_create.go │ │ ├── residence_delete.go │ │ ├── residence_query.go │ │ ├── residence_update.go │ │ ├── residencehistory.go │ │ ├── residencehistory │ │ ├── residencehistory.go │ │ └── where.go │ │ ├── residencehistory_create.go │ │ ├── residencehistory_delete.go │ │ ├── residencehistory_query.go │ │ ├── residencehistory_update.go │ │ ├── runtime.go │ │ ├── runtime │ │ └── runtime.go │ │ ├── schema │ │ ├── character.go │ │ ├── character_history.go │ │ ├── friendship.go │ │ ├── friendship_history.go │ │ ├── mixins │ │ │ └── timemixin.go │ │ ├── models │ │ │ └── models.go │ │ ├── residence.go │ │ └── residence_history.go │ │ └── tx.go ├── custompaths │ ├── ent │ │ ├── entc.go │ │ ├── generate.go │ │ └── some │ │ │ └── otherschema │ │ │ ├── character.go │ │ │ ├── character_history.go │ │ │ ├── friendship.go │ │ │ └── friendship_history.go │ └── internal │ │ └── ent │ │ ├── character.go │ │ ├── character │ │ ├── character.go │ │ └── where.go │ │ ├── character_create.go │ │ ├── character_delete.go │ │ ├── character_query.go │ │ ├── character_update.go │ │ ├── characterhistory.go │ │ ├── characterhistory │ │ ├── characterhistory.go │ │ └── where.go │ │ ├── characterhistory_create.go │ │ ├── characterhistory_delete.go │ │ ├── characterhistory_query.go │ │ ├── characterhistory_update.go │ │ ├── client.go │ │ ├── ent.go │ │ ├── enttest │ │ └── enttest.go │ │ ├── friendship.go │ │ ├── friendship │ │ ├── friendship.go │ │ └── where.go │ │ ├── friendship_create.go │ │ ├── friendship_delete.go │ │ ├── friendship_query.go │ │ ├── friendship_update.go │ │ ├── friendshiphistory.go │ │ ├── friendshiphistory │ │ ├── friendshiphistory.go │ │ └── where.go │ │ ├── friendshiphistory_create.go │ │ ├── friendshiphistory_delete.go │ │ ├── friendshiphistory_query.go │ │ ├── friendshiphistory_update.go │ │ ├── history_from_mutation.go │ │ ├── history_query.go │ │ ├── hook │ │ └── hook.go │ │ ├── migrate │ │ ├── migrate.go │ │ └── schema.go │ │ ├── mutation.go │ │ ├── predicate │ │ └── predicate.go │ │ ├── runtime.go │ │ ├── runtime │ │ └── runtime.go │ │ └── tx.go ├── enthistory_basic_test.go ├── enthistory_updateby_uuid_test.go ├── enthistory_without_updatedby_test.go ├── go.mod ├── go.sum ├── graphql │ ├── README.md │ ├── ent │ │ ├── client.go │ │ ├── ent.go │ │ ├── entc.go │ │ ├── entql.go │ │ ├── enttest │ │ │ └── enttest.go │ │ ├── gql_collection.go │ │ ├── gql_edge.go │ │ ├── gql_mutation_input.go │ │ ├── gql_node.go │ │ ├── gql_pagination.go │ │ ├── gql_transaction.go │ │ ├── gql_where_input.go │ │ ├── history_from_mutation.go │ │ ├── history_query.go │ │ ├── hook │ │ │ └── hook.go │ │ ├── internal │ │ │ └── schema.go │ │ ├── migrate │ │ │ ├── migrate.go │ │ │ └── schema.go │ │ ├── mutation.go │ │ ├── predicate │ │ │ └── predicate.go │ │ ├── privacy │ │ │ └── privacy.go │ │ ├── runtime.go │ │ ├── runtime │ │ │ └── runtime.go │ │ ├── schema │ │ │ ├── testexclude.go │ │ │ ├── testskip.go │ │ │ ├── testskip_history.go │ │ │ ├── todo.go │ │ │ ├── todo_history.go │ │ │ └── uuidgql │ │ │ │ └── uuidgql.go │ │ ├── testexclude.go │ │ ├── testexclude │ │ │ ├── testexclude.go │ │ │ └── where.go │ │ ├── testexclude_create.go │ │ ├── testexclude_delete.go │ │ ├── testexclude_query.go │ │ ├── testexclude_update.go │ │ ├── testskip.go │ │ ├── testskip │ │ │ ├── testskip.go │ │ │ └── where.go │ │ ├── testskip_create.go │ │ ├── testskip_delete.go │ │ ├── testskip_query.go │ │ ├── testskip_update.go │ │ ├── testskiphistory.go │ │ ├── testskiphistory │ │ │ ├── testskiphistory.go │ │ │ └── where.go │ │ ├── testskiphistory_create.go │ │ ├── testskiphistory_delete.go │ │ ├── testskiphistory_query.go │ │ ├── testskiphistory_update.go │ │ ├── todo.go │ │ ├── todo │ │ │ ├── todo.go │ │ │ └── where.go │ │ ├── todo_create.go │ │ ├── todo_delete.go │ │ ├── todo_query.go │ │ ├── todo_update.go │ │ ├── todohistory.go │ │ ├── todohistory │ │ │ ├── todohistory.go │ │ │ └── where.go │ │ ├── todohistory_create.go │ │ ├── todohistory_delete.go │ │ ├── todohistory_query.go │ │ ├── todohistory_update.go │ │ └── tx.go │ ├── generate.go │ ├── gqlgen.yml │ └── graphql │ │ ├── query.graphql │ │ └── resolver │ │ ├── generated.go │ │ ├── query.resolvers.go │ │ └── resolver.go ├── testdata │ └── debug │ │ ├── entc.go │ │ ├── internal │ │ └── ent │ │ │ ├── auditing.go │ │ │ ├── character.go │ │ │ ├── character │ │ │ ├── character.go │ │ │ └── where.go │ │ │ ├── character_create.go │ │ │ ├── character_delete.go │ │ │ ├── character_query.go │ │ │ ├── character_update.go │ │ │ ├── characterhistory.go │ │ │ ├── characterhistory │ │ │ ├── characterhistory.go │ │ │ └── where.go │ │ │ ├── characterhistory_create.go │ │ │ ├── characterhistory_delete.go │ │ │ ├── characterhistory_query.go │ │ │ ├── characterhistory_update.go │ │ │ ├── client.go │ │ │ ├── ent.go │ │ │ ├── enttest │ │ │ └── enttest.go │ │ │ ├── friendship.go │ │ │ ├── friendship │ │ │ ├── friendship.go │ │ │ └── where.go │ │ │ ├── friendship_create.go │ │ │ ├── friendship_delete.go │ │ │ ├── friendship_query.go │ │ │ ├── friendship_update.go │ │ │ ├── friendshiphistory.go │ │ │ ├── friendshiphistory │ │ │ ├── friendshiphistory.go │ │ │ └── where.go │ │ │ ├── friendshiphistory_create.go │ │ │ ├── friendshiphistory_delete.go │ │ │ ├── friendshiphistory_query.go │ │ │ ├── friendshiphistory_update.go │ │ │ ├── history_from_mutation.go │ │ │ ├── history_query.go │ │ │ ├── hook │ │ │ └── hook.go │ │ │ ├── migrate │ │ │ ├── migrate.go │ │ │ └── schema.go │ │ │ ├── mutation.go │ │ │ ├── predicate │ │ │ └── predicate.go │ │ │ ├── runtime.go │ │ │ ├── runtime │ │ │ └── runtime.go │ │ │ └── tx.go │ │ ├── models │ │ └── models.go │ │ └── schema │ │ ├── character.go │ │ ├── character_history.go │ │ ├── friendship.go │ │ ├── friendship_history.go │ │ ├── mixins │ │ └── timemixin.go │ │ └── othermixin.go ├── updateby_uuid │ └── ent │ │ ├── auditing.go │ │ ├── client.go │ │ ├── ent.go │ │ ├── entc.go │ │ ├── enttest │ │ └── enttest.go │ │ ├── generate.go │ │ ├── history_from_mutation.go │ │ ├── history_query.go │ │ ├── hook │ │ └── hook.go │ │ ├── migrate │ │ ├── migrate.go │ │ └── schema.go │ │ ├── mutation.go │ │ ├── organization.go │ │ ├── organization │ │ ├── organization.go │ │ └── where.go │ │ ├── organization_create.go │ │ ├── organization_delete.go │ │ ├── organization_query.go │ │ ├── organization_update.go │ │ ├── organizationhistory.go │ │ ├── organizationhistory │ │ ├── organizationhistory.go │ │ └── where.go │ │ ├── organizationhistory_create.go │ │ ├── organizationhistory_delete.go │ │ ├── organizationhistory_query.go │ │ ├── organizationhistory_update.go │ │ ├── predicate │ │ └── predicate.go │ │ ├── runtime.go │ │ ├── runtime │ │ └── runtime.go │ │ ├── schema │ │ ├── mixins │ │ │ └── timemixin.go │ │ ├── organization.go │ │ ├── organization_history.go │ │ ├── store.go │ │ └── store_history.go │ │ ├── store.go │ │ ├── store │ │ ├── store.go │ │ └── where.go │ │ ├── store_create.go │ │ ├── store_delete.go │ │ ├── store_query.go │ │ ├── store_update.go │ │ ├── storehistory.go │ │ ├── storehistory │ │ ├── storehistory.go │ │ └── where.go │ │ ├── storehistory_create.go │ │ ├── storehistory_delete.go │ │ ├── storehistory_query.go │ │ ├── storehistory_update.go │ │ └── tx.go ├── uuidmixinid │ └── ent │ │ ├── auditing.go │ │ ├── client.go │ │ ├── ent.go │ │ ├── entc.go │ │ ├── enttest │ │ └── enttest.go │ │ ├── generate.go │ │ ├── history_from_mutation.go │ │ ├── history_query.go │ │ ├── hook │ │ └── hook.go │ │ ├── internal │ │ └── schema.go │ │ ├── menuitem.go │ │ ├── menuitem │ │ ├── menuitem.go │ │ └── where.go │ │ ├── menuitem_create.go │ │ ├── menuitem_delete.go │ │ ├── menuitem_query.go │ │ ├── menuitem_update.go │ │ ├── menuitemhistory.go │ │ ├── menuitemhistory │ │ ├── menuitemhistory.go │ │ └── where.go │ │ ├── menuitemhistory_create.go │ │ ├── menuitemhistory_delete.go │ │ ├── menuitemhistory_query.go │ │ ├── menuitemhistory_update.go │ │ ├── migrate │ │ ├── migrate.go │ │ └── schema.go │ │ ├── mutation.go │ │ ├── predicate │ │ └── predicate.go │ │ ├── runtime.go │ │ ├── runtime │ │ └── runtime.go │ │ ├── schema │ │ ├── menu_item.go │ │ ├── menu_item_history.go │ │ └── mixins │ │ │ ├── idmixin.go │ │ │ └── timemixin.go │ │ └── tx.go └── without_updatedby │ └── ent │ ├── auditing.go │ ├── character.go │ ├── character │ ├── character.go │ └── where.go │ ├── character_create.go │ ├── character_delete.go │ ├── character_query.go │ ├── character_update.go │ ├── characterhistory.go │ ├── characterhistory │ ├── characterhistory.go │ └── where.go │ ├── characterhistory_create.go │ ├── characterhistory_delete.go │ ├── characterhistory_query.go │ ├── characterhistory_update.go │ ├── client.go │ ├── ent.go │ ├── entc.go │ ├── enttest │ └── enttest.go │ ├── friendship.go │ ├── friendship │ ├── friendship.go │ └── where.go │ ├── friendship_create.go │ ├── friendship_delete.go │ ├── friendship_query.go │ ├── friendship_update.go │ ├── friendshiphistory.go │ ├── friendshiphistory │ ├── friendshiphistory.go │ └── where.go │ ├── friendshiphistory_create.go │ ├── friendshiphistory_delete.go │ ├── friendshiphistory_query.go │ ├── friendshiphistory_update.go │ ├── generate.go │ ├── history_from_mutation.go │ ├── history_query.go │ ├── hook │ └── hook.go │ ├── internal │ └── schema.go │ ├── migrate │ ├── migrate.go │ └── schema.go │ ├── mutation.go │ ├── predicate │ └── predicate.go │ ├── residence.go │ ├── residence │ ├── residence.go │ └── where.go │ ├── residence_create.go │ ├── residence_delete.go │ ├── residence_query.go │ ├── residence_update.go │ ├── residencehistory.go │ ├── residencehistory │ ├── residencehistory.go │ └── where.go │ ├── residencehistory_create.go │ ├── residencehistory_delete.go │ ├── residencehistory_query.go │ ├── residencehistory_update.go │ ├── runtime.go │ ├── runtime │ └── runtime.go │ ├── schema │ ├── character.go │ ├── character_history.go │ ├── friendship.go │ ├── friendship_history.go │ ├── mixins │ │ └── timemixin.go │ ├── residence.go │ └── residence_history.go │ └── tx.go ├── annotations.go ├── extension.go ├── generate.go ├── go.mod ├── go.sum ├── go.work ├── go.work.sum ├── hook.go ├── internal └── schemast │ ├── LICENSE │ ├── README.md │ ├── annotation.go │ ├── annotation_test.go │ ├── astutil.go │ ├── edge.go │ ├── field.go │ ├── index.go │ ├── kind.go │ ├── load.go │ ├── mixin.go │ ├── mutate.go │ ├── print.go │ └── type.go ├── opType.go ├── scripts └── tag.sh ├── template.go ├── templates ├── auditing.tmpl ├── client.tmpl ├── historyFromMutation.tmpl └── historyQuery.tmpl └── utils.go /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence. They will be requested for 3 | # review when someone opens a pull request. 4 | * @caseyh @tomfleming @nnnflume @eouw0o83hf @frisbm 5 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Issues 4 | 5 | Issues are very valuable to this project. 6 | 7 | - Ideas are a valuable source of contributions others can make 8 | - Problems show where this project is lacking 9 | - With a question you show where contributors can improve the user 10 | experience 11 | 12 | Thank you for creating them. 13 | 14 | ## Pull Requests 15 | 16 | Pull requests are, a great way to get your ideas into this repository. 17 | 18 | When deciding if I merge in a pull request I look at the following 19 | things: 20 | 21 | ### Does it state intent 22 | 23 | You should be clear which problem you're trying to solve with your 24 | contribution. 25 | 26 | For example: 27 | 28 | > Add link to code of conduct in README.md 29 | 30 | Doesn't tell me anything about why you're doing that 31 | 32 | > Add link to code of conduct in README.md because users don't always 33 | > look in the CONTRIBUTING.md 34 | 35 | Tells me the problem that you have found, and the pull request shows me 36 | the action you have taken to solve it. 37 | 38 | ### Is it of good quality 39 | 40 | - There are no spelling mistakes 41 | - It reads well 42 | 43 | ### Does it move this repository closer to my vision for the repository 44 | 45 | The aim of this repository is: 46 | 47 | - To provide a README.md and assorted documents anyone can copy and 48 | paste, into their project 49 | - The content is usable by someone who hasn't written something like 50 | this before 51 | - Foster a culture of respect and gratitude in the open source 52 | community. 53 | 54 | ### Does it follow the contributor covenant 55 | 56 | This repository has a [code of conduct](CODE_OF_CONDUCT.md), I will 57 | remove things that do not respect it. 58 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Expected Behavior 4 | 5 | 6 | 7 | ## Current Behavior 8 | 9 | 10 | 11 | ## Possible Solution 12 | 13 | 14 | 15 | ## Steps to Reproduce (for bugs) 16 | 17 | 18 | 1. 19 | 2. 20 | 3. 21 | 4. 22 | 23 | ## Context 24 | 25 | 26 | 27 | ## Your Environment 28 | 29 | * Version used: 30 | * Environment name and version (e.g. PHP 5.4 on nginx 1.9.1): 31 | * Server type and version: 32 | * Operating System and version: 33 | * Link to your project: 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Example code/repo reproducing the issue 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Additional context** 23 | Add any other context about the problem here. 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Motivation and Context 7 | 8 | 9 | 10 | ## How Has This Been Tested? 11 | 12 | 13 | 14 | 15 | ## Screenshots (if appropriate): 16 | 17 | ## Types of changes 18 | 19 | - [ ] Bug fix (non-breaking change which fixes an issue) 20 | - [ ] New feature (non-breaking change which adds functionality) 21 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 22 | - [ ] Documentation (update or addition to documentation for this project) 23 | 24 | ## Checklist: 25 | 26 | 27 | - [ ] My code follows the code style of this project. 28 | - [ ] I have updated the documentation accordingly. 29 | - [ ] I have added tests to cover my changes. 30 | - [ ] All new and existing tests passed. 31 | -------------------------------------------------------------------------------- /.github/workflows/testing.yaml: -------------------------------------------------------------------------------- 1 | name: Testing 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "**" # Run on all branches 7 | 8 | jobs: 9 | testing: 10 | name: Testing 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | 16 | - name: Setup Go 17 | uses: actions/setup-go@v5 18 | with: 19 | cache: true 20 | cache-dependency-path: go.mod 21 | go-version: "1.24" 22 | 23 | - name: Test 24 | run: go test ./_examples/. 25 | 26 | linting: 27 | name: Linting 28 | runs-on: ubuntu-latest 29 | steps: 30 | - name: Checkout 31 | uses: actions/checkout@v4 32 | 33 | - name: Setup Go 34 | uses: actions/setup-go@v5 35 | with: 36 | cache: true 37 | cache-dependency-path: go.mod 38 | go-version: "1.24" 39 | 40 | - name: GoLang CI Lint 41 | uses: golangci/golangci-lint-action@v6 42 | with: 43 | version: v1.64 44 | args: --timeout 10m0s 45 | skip-cache: true 46 | 47 | formatting: 48 | name: Formatting 49 | runs-on: ubuntu-latest 50 | steps: 51 | - name: Checkout 52 | uses: actions/checkout@v4 53 | 54 | - name: Setup Go 55 | uses: actions/setup-go@v5 56 | with: 57 | cache: true 58 | cache-dependency-path: go.mod 59 | go-version: "1.24" 60 | 61 | - name: Format 62 | run: | 63 | go install golang.org/x/tools/cmd/goimports@v0.30.0 64 | UNFORMATTED_CODE_GOFMT=$(goimports -local github.com/flume -d ./) 65 | if [ -n "$UNFORMATTED_CODE_GOFMT" ]; then 66 | echo "Code is not formatted. Please run 'make fmt' to fix it." 67 | echo "$UNFORMATTED_CODE_GOFMT" 68 | exit 1 69 | fi 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | .DS_STORE 17 | .idea 18 | entdb 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Flume Health 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help 2 | # help: 3 | # Print this help message 4 | help: 5 | @grep -o '^\#.*' Makefile | cut -d" " -f2- 6 | 7 | .PHONY: fmt 8 | # fmt: 9 | # Format go code 10 | fmt: 11 | goimports -local github.com/flume -w ./ 12 | 13 | .PHONY: lint 14 | # lint: 15 | # lint the code 16 | lint: 17 | golangci-lint run 18 | golangci-lint run ./_examples/. 19 | 20 | .PHONY: generate 21 | # generate: 22 | # Generate the examples code 23 | generate: 24 | (cd _examples && go generate ./... ) 25 | $(MAKE) fmt 26 | 27 | .PHONY: upgrade-deps 28 | # upgrade-deps: 29 | # Upgrade the dependencies 30 | upgrade-deps: 31 | (cd _examples && go get -u -t ./... && go mod tidy) 32 | (go get -u -t ./... && go mod tidy) 33 | go work sync ./... 34 | 35 | .PHONY: test 36 | # test: 37 | # Run the tests 38 | test: 39 | (cd ./_examples && go test ./.) 40 | 41 | tag: 42 | @echo "creating tag" 43 | bash ./scripts/tag.sh 44 | -------------------------------------------------------------------------------- /_examples/basic/ent/character_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/basic/ent/character" 7 | "_examples/basic/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // CharacterDelete is the builder for deleting a Character entity. 16 | type CharacterDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *CharacterMutation 20 | } 21 | 22 | // Where appends a list predicates to the CharacterDelete builder. 23 | func (cd *CharacterDelete) Where(ps ...predicate.Character) *CharacterDelete { 24 | cd.mutation.Where(ps...) 25 | return cd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (cd *CharacterDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, cd.sqlExec, cd.mutation, cd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (cd *CharacterDelete) ExecX(ctx context.Context) int { 35 | n, err := cd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (cd *CharacterDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(character.Table, sqlgraph.NewFieldSpec(character.FieldID, field.TypeInt)) 44 | if ps := cd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, cd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | cd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // CharacterDeleteOne is the builder for deleting a single Character entity. 60 | type CharacterDeleteOne struct { 61 | cd *CharacterDelete 62 | } 63 | 64 | // Where appends a list predicates to the CharacterDelete builder. 65 | func (cdo *CharacterDeleteOne) Where(ps ...predicate.Character) *CharacterDeleteOne { 66 | cdo.cd.mutation.Where(ps...) 67 | return cdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (cdo *CharacterDeleteOne) Exec(ctx context.Context) error { 72 | n, err := cdo.cd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{character.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (cdo *CharacterDeleteOne) ExecX(ctx context.Context) { 85 | if err := cdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/basic/ent/characterhistory_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/basic/ent/characterhistory" 7 | "_examples/basic/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // CharacterHistoryDelete is the builder for deleting a CharacterHistory entity. 16 | type CharacterHistoryDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *CharacterHistoryMutation 20 | } 21 | 22 | // Where appends a list predicates to the CharacterHistoryDelete builder. 23 | func (chd *CharacterHistoryDelete) Where(ps ...predicate.CharacterHistory) *CharacterHistoryDelete { 24 | chd.mutation.Where(ps...) 25 | return chd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (chd *CharacterHistoryDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, chd.sqlExec, chd.mutation, chd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (chd *CharacterHistoryDelete) ExecX(ctx context.Context) int { 35 | n, err := chd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (chd *CharacterHistoryDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(characterhistory.Table, sqlgraph.NewFieldSpec(characterhistory.FieldID, field.TypeInt)) 44 | if ps := chd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, chd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | chd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // CharacterHistoryDeleteOne is the builder for deleting a single CharacterHistory entity. 60 | type CharacterHistoryDeleteOne struct { 61 | chd *CharacterHistoryDelete 62 | } 63 | 64 | // Where appends a list predicates to the CharacterHistoryDelete builder. 65 | func (chdo *CharacterHistoryDeleteOne) Where(ps ...predicate.CharacterHistory) *CharacterHistoryDeleteOne { 66 | chdo.chd.mutation.Where(ps...) 67 | return chdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (chdo *CharacterHistoryDeleteOne) Exec(ctx context.Context) error { 72 | n, err := chdo.chd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{characterhistory.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (chdo *CharacterHistoryDeleteOne) ExecX(ctx context.Context) { 85 | if err := chdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/basic/ent/entc.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "_examples/basic/ent/schema" 7 | "fmt" 8 | "log" 9 | 10 | "entgo.io/ent" 11 | 12 | "entgo.io/ent/entc/gen" 13 | 14 | "github.com/flume/enthistory" 15 | 16 | "entgo.io/ent/entc" 17 | ) 18 | 19 | func main() { 20 | if err := enthistory.Generate("./schema", []ent.Interface{ 21 | &schema.Character{}, 22 | &schema.Friendship{}, 23 | &schema.Residence{}, 24 | }, 25 | enthistory.WithUpdatedBy("userId", enthistory.ValueTypeInt), 26 | enthistory.WithHistoryTimeIndex(), 27 | enthistory.WithImmutableFields(), 28 | ); err != nil { 29 | log.Fatal(fmt.Sprintf("running enthistory codegen: %v", err)) 30 | } 31 | 32 | if err := entc.Generate("./schema", 33 | &gen.Config{ 34 | Features: []gen.Feature{gen.FeatureSnapshot}, 35 | }, 36 | entc.Extensions( 37 | enthistory.NewHistoryExtension(enthistory.WithAuditing()), 38 | ), 39 | ); err != nil { 40 | log.Fatal("running ent codegen:", err) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /_examples/basic/ent/enttest/enttest.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package enttest 4 | 5 | import ( 6 | "context" 7 | 8 | "_examples/basic/ent" 9 | // required by schema hooks. 10 | _ "_examples/basic/ent/runtime" 11 | 12 | "_examples/basic/ent/migrate" 13 | 14 | "entgo.io/ent/dialect/sql/schema" 15 | ) 16 | 17 | type ( 18 | // TestingT is the interface that is shared between 19 | // testing.T and testing.B and used by enttest. 20 | TestingT interface { 21 | FailNow() 22 | Error(...any) 23 | } 24 | 25 | // Option configures client creation. 26 | Option func(*options) 27 | 28 | options struct { 29 | opts []ent.Option 30 | migrateOpts []schema.MigrateOption 31 | } 32 | ) 33 | 34 | // WithOptions forwards options to client creation. 35 | func WithOptions(opts ...ent.Option) Option { 36 | return func(o *options) { 37 | o.opts = append(o.opts, opts...) 38 | } 39 | } 40 | 41 | // WithMigrateOptions forwards options to auto migration. 42 | func WithMigrateOptions(opts ...schema.MigrateOption) Option { 43 | return func(o *options) { 44 | o.migrateOpts = append(o.migrateOpts, opts...) 45 | } 46 | } 47 | 48 | func newOptions(opts []Option) *options { 49 | o := &options{} 50 | for _, opt := range opts { 51 | opt(o) 52 | } 53 | return o 54 | } 55 | 56 | // Open calls ent.Open and auto-run migration. 57 | func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { 58 | o := newOptions(opts) 59 | c, err := ent.Open(driverName, dataSourceName, o.opts...) 60 | if err != nil { 61 | t.Error(err) 62 | t.FailNow() 63 | } 64 | migrateSchema(t, c, o) 65 | return c 66 | } 67 | 68 | // NewClient calls ent.NewClient and auto-run migration. 69 | func NewClient(t TestingT, opts ...Option) *ent.Client { 70 | o := newOptions(opts) 71 | c := ent.NewClient(o.opts...) 72 | migrateSchema(t, c, o) 73 | return c 74 | } 75 | func migrateSchema(t TestingT, c *ent.Client, o *options) { 76 | tables, err := schema.CopyTables(migrate.Tables) 77 | if err != nil { 78 | t.Error(err) 79 | t.FailNow() 80 | } 81 | if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { 82 | t.Error(err) 83 | t.FailNow() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /_examples/basic/ent/friendship_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/basic/ent/friendship" 7 | "_examples/basic/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // FriendshipDelete is the builder for deleting a Friendship entity. 16 | type FriendshipDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *FriendshipMutation 20 | } 21 | 22 | // Where appends a list predicates to the FriendshipDelete builder. 23 | func (fd *FriendshipDelete) Where(ps ...predicate.Friendship) *FriendshipDelete { 24 | fd.mutation.Where(ps...) 25 | return fd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (fd *FriendshipDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, fd.sqlExec, fd.mutation, fd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (fd *FriendshipDelete) ExecX(ctx context.Context) int { 35 | n, err := fd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (fd *FriendshipDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(friendship.Table, sqlgraph.NewFieldSpec(friendship.FieldID, field.TypeString)) 44 | if ps := fd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, fd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | fd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // FriendshipDeleteOne is the builder for deleting a single Friendship entity. 60 | type FriendshipDeleteOne struct { 61 | fd *FriendshipDelete 62 | } 63 | 64 | // Where appends a list predicates to the FriendshipDelete builder. 65 | func (fdo *FriendshipDeleteOne) Where(ps ...predicate.Friendship) *FriendshipDeleteOne { 66 | fdo.fd.mutation.Where(ps...) 67 | return fdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (fdo *FriendshipDeleteOne) Exec(ctx context.Context) error { 72 | n, err := fdo.fd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{friendship.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (fdo *FriendshipDeleteOne) ExecX(ctx context.Context) { 85 | if err := fdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/basic/ent/friendshiphistory_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/basic/ent/friendshiphistory" 7 | "_examples/basic/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // FriendshipHistoryDelete is the builder for deleting a FriendshipHistory entity. 16 | type FriendshipHistoryDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *FriendshipHistoryMutation 20 | } 21 | 22 | // Where appends a list predicates to the FriendshipHistoryDelete builder. 23 | func (fhd *FriendshipHistoryDelete) Where(ps ...predicate.FriendshipHistory) *FriendshipHistoryDelete { 24 | fhd.mutation.Where(ps...) 25 | return fhd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (fhd *FriendshipHistoryDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, fhd.sqlExec, fhd.mutation, fhd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (fhd *FriendshipHistoryDelete) ExecX(ctx context.Context) int { 35 | n, err := fhd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (fhd *FriendshipHistoryDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(friendshiphistory.Table, sqlgraph.NewFieldSpec(friendshiphistory.FieldID, field.TypeInt)) 44 | if ps := fhd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, fhd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | fhd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // FriendshipHistoryDeleteOne is the builder for deleting a single FriendshipHistory entity. 60 | type FriendshipHistoryDeleteOne struct { 61 | fhd *FriendshipHistoryDelete 62 | } 63 | 64 | // Where appends a list predicates to the FriendshipHistoryDelete builder. 65 | func (fhdo *FriendshipHistoryDeleteOne) Where(ps ...predicate.FriendshipHistory) *FriendshipHistoryDeleteOne { 66 | fhdo.fhd.mutation.Where(ps...) 67 | return fhdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (fhdo *FriendshipHistoryDeleteOne) Exec(ctx context.Context) error { 72 | n, err := fhdo.fhd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{friendshiphistory.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (fhdo *FriendshipHistoryDeleteOne) ExecX(ctx context.Context) { 85 | if err := fhdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/basic/ent/generate.go: -------------------------------------------------------------------------------- 1 | package ent 2 | 3 | //go:generate go run entc.go 4 | -------------------------------------------------------------------------------- /_examples/basic/ent/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io" 9 | 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | var ( 15 | // WithGlobalUniqueID sets the universal ids options to the migration. 16 | // If this option is enabled, ent migration will allocate a 1<<32 range 17 | // for the ids of each entity (table). 18 | // Note that this option cannot be applied on tables that already exist. 19 | WithGlobalUniqueID = schema.WithGlobalUniqueID 20 | // WithDropColumn sets the drop column option to the migration. 21 | // If this option is enabled, ent migration will drop old columns 22 | // that were used for both fields and edges. This defaults to false. 23 | WithDropColumn = schema.WithDropColumn 24 | // WithDropIndex sets the drop index option to the migration. 25 | // If this option is enabled, ent migration will drop old indexes 26 | // that were defined in the schema. This defaults to false. 27 | // Note that unique constraints are defined using `UNIQUE INDEX`, 28 | // and therefore, it's recommended to enable this option to get more 29 | // flexibility in the schema changes. 30 | WithDropIndex = schema.WithDropIndex 31 | // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. 32 | WithForeignKeys = schema.WithForeignKeys 33 | ) 34 | 35 | // Schema is the API for creating, migrating and dropping a schema. 36 | type Schema struct { 37 | drv dialect.Driver 38 | } 39 | 40 | // NewSchema creates a new schema client. 41 | func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } 42 | 43 | // Create creates all schema resources. 44 | func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { 45 | return Create(ctx, s, Tables, opts...) 46 | } 47 | 48 | // Create creates all table resources using the given schema driver. 49 | func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error { 50 | migrate, err := schema.NewMigrate(s.drv, opts...) 51 | if err != nil { 52 | return fmt.Errorf("ent/migrate: %w", err) 53 | } 54 | return migrate.Create(ctx, tables...) 55 | } 56 | 57 | // WriteTo writes the schema changes to w instead of running them against the database. 58 | // 59 | // if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { 60 | // log.Fatal(err) 61 | // } 62 | func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { 63 | return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...) 64 | } 65 | -------------------------------------------------------------------------------- /_examples/basic/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // Character is the predicate function for character builders. 10 | type Character func(*sql.Selector) 11 | 12 | // CharacterHistory is the predicate function for characterhistory builders. 13 | type CharacterHistory func(*sql.Selector) 14 | 15 | // Friendship is the predicate function for friendship builders. 16 | type Friendship func(*sql.Selector) 17 | 18 | // FriendshipHistory is the predicate function for friendshiphistory builders. 19 | type FriendshipHistory func(*sql.Selector) 20 | 21 | // Residence is the predicate function for residence builders. 22 | type Residence func(*sql.Selector) 23 | 24 | // ResidenceHistory is the predicate function for residencehistory builders. 25 | type ResidenceHistory func(*sql.Selector) 26 | -------------------------------------------------------------------------------- /_examples/basic/ent/residence_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/basic/ent/predicate" 7 | "_examples/basic/ent/residence" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // ResidenceDelete is the builder for deleting a Residence entity. 16 | type ResidenceDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *ResidenceMutation 20 | } 21 | 22 | // Where appends a list predicates to the ResidenceDelete builder. 23 | func (rd *ResidenceDelete) Where(ps ...predicate.Residence) *ResidenceDelete { 24 | rd.mutation.Where(ps...) 25 | return rd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (rd *ResidenceDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, rd.sqlExec, rd.mutation, rd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (rd *ResidenceDelete) ExecX(ctx context.Context) int { 35 | n, err := rd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (rd *ResidenceDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(residence.Table, sqlgraph.NewFieldSpec(residence.FieldID, field.TypeUUID)) 44 | if ps := rd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, rd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | rd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // ResidenceDeleteOne is the builder for deleting a single Residence entity. 60 | type ResidenceDeleteOne struct { 61 | rd *ResidenceDelete 62 | } 63 | 64 | // Where appends a list predicates to the ResidenceDelete builder. 65 | func (rdo *ResidenceDeleteOne) Where(ps ...predicate.Residence) *ResidenceDeleteOne { 66 | rdo.rd.mutation.Where(ps...) 67 | return rdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (rdo *ResidenceDeleteOne) Exec(ctx context.Context) error { 72 | n, err := rdo.rd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{residence.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (rdo *ResidenceDeleteOne) ExecX(ctx context.Context) { 85 | if err := rdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/basic/ent/residencehistory_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/basic/ent/predicate" 7 | "_examples/basic/ent/residencehistory" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // ResidenceHistoryDelete is the builder for deleting a ResidenceHistory entity. 16 | type ResidenceHistoryDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *ResidenceHistoryMutation 20 | } 21 | 22 | // Where appends a list predicates to the ResidenceHistoryDelete builder. 23 | func (rhd *ResidenceHistoryDelete) Where(ps ...predicate.ResidenceHistory) *ResidenceHistoryDelete { 24 | rhd.mutation.Where(ps...) 25 | return rhd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (rhd *ResidenceHistoryDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, rhd.sqlExec, rhd.mutation, rhd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (rhd *ResidenceHistoryDelete) ExecX(ctx context.Context) int { 35 | n, err := rhd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (rhd *ResidenceHistoryDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(residencehistory.Table, sqlgraph.NewFieldSpec(residencehistory.FieldID, field.TypeInt)) 44 | if ps := rhd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, rhd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | rhd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // ResidenceHistoryDeleteOne is the builder for deleting a single ResidenceHistory entity. 60 | type ResidenceHistoryDeleteOne struct { 61 | rhd *ResidenceHistoryDelete 62 | } 63 | 64 | // Where appends a list predicates to the ResidenceHistoryDelete builder. 65 | func (rhdo *ResidenceHistoryDeleteOne) Where(ps ...predicate.ResidenceHistory) *ResidenceHistoryDeleteOne { 66 | rhdo.rhd.mutation.Where(ps...) 67 | return rhdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (rhdo *ResidenceHistoryDeleteOne) Exec(ctx context.Context) error { 72 | n, err := rhdo.rhd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{residencehistory.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (rhdo *ResidenceHistoryDeleteOne) ExecX(ctx context.Context) { 85 | if err := rhdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/basic/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in _examples/basic/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.14.4" // Version of ent codegen. 9 | Sum = "h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /_examples/basic/ent/schema/character.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "_examples/basic/ent/schema/models" 5 | 6 | "entgo.io/ent" 7 | "entgo.io/ent/dialect/entsql" 8 | "entgo.io/ent/schema" 9 | "entgo.io/ent/schema/edge" 10 | "entgo.io/ent/schema/field" 11 | 12 | "_examples/basic/ent/schema/mixins" 13 | ) 14 | 15 | // Character holds the schema definition for the Character entity. 16 | type Character struct { 17 | ent.Schema 18 | } 19 | 20 | // Annotations of the Character. 21 | func (Character) Annotations() []schema.Annotation { 22 | return []schema.Annotation{ 23 | entsql.Annotation{ 24 | Table: "character", 25 | }, 26 | } 27 | } 28 | 29 | // Fields of the Character. 30 | func (Character) Fields() []ent.Field { 31 | return []ent.Field{ 32 | field.Int("age"). 33 | Positive(), 34 | field.Uint64("typed_age"). 35 | Positive(). 36 | GoType(models.Uint64(0)). 37 | DefaultFunc(models.DefaultUint64), 38 | field.String("name"), 39 | field.JSON("nicknames", []string{}). 40 | Optional(), 41 | field.JSON("info", map[string]any{}). 42 | Optional(), 43 | field.JSON("info_struct", models.InfoStruct{}). 44 | Optional(). 45 | Default(models.DefaultInfoStruct), 46 | field.Int("level"). 47 | Optional(). 48 | Nillable(), 49 | field.String("species"). 50 | Optional(). 51 | GoType(models.SpeciesType("")). 52 | DefaultFunc(models.DefaultSpeciesType), 53 | } 54 | } 55 | 56 | // Edges of the Character. 57 | func (Character) Edges() []ent.Edge { 58 | return []ent.Edge{ 59 | edge.To("friends", Character.Type). 60 | Through("friendships", Friendship.Type), 61 | edge.From("residence", Residence.Type). 62 | Ref("occupants"). 63 | Unique(), 64 | } 65 | } 66 | 67 | // Mixin of the Character. 68 | func (Character) Mixin() []ent.Mixin { 69 | return []ent.Mixin{ 70 | mixins.TimeMixin{}, 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /_examples/basic/ent/schema/character_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "_examples/basic/ent/schema/mixins" 7 | "_examples/basic/ent/schema/models" 8 | "time" 9 | 10 | "entgo.io/ent" 11 | "entgo.io/ent/dialect/entsql" 12 | "entgo.io/ent/schema" 13 | "entgo.io/ent/schema/field" 14 | "entgo.io/ent/schema/index" 15 | 16 | "github.com/flume/enthistory" 17 | ) 18 | 19 | type CharacterHistory struct { 20 | ent.Schema 21 | } 22 | 23 | func (CharacterHistory) Fields() []ent.Field { 24 | return []ent.Field{ 25 | field.Time("history_time"). 26 | Immutable(). 27 | Default(time.Now), 28 | field.Enum("operation"). 29 | Immutable(). 30 | GoType(enthistory.OpType("")), 31 | field.Int("ref"). 32 | Optional(). 33 | Immutable(), 34 | field.Int("updated_by"). 35 | Nillable(). 36 | Optional(). 37 | Immutable(), 38 | field.Int("age"). 39 | Immutable(), 40 | field.Uint64("typed_age"). 41 | GoType(models.Uint64(0)). 42 | Immutable(). 43 | DefaultFunc(models.DefaultUint64), 44 | field.String("name"). 45 | Immutable(), 46 | field.JSON("nicknames", []string{}). 47 | Optional(). 48 | Immutable(), 49 | field.JSON("info", map[string]any{}). 50 | Optional(). 51 | Immutable(), 52 | field.JSON("info_struct", models. 53 | InfoStruct{}). 54 | Optional(). 55 | Immutable(). 56 | Default(models.DefaultInfoStruct), 57 | field.Int("level"). 58 | Nillable(). 59 | Optional(). 60 | Immutable(), 61 | field.String("species"). 62 | GoType(models.SpeciesType("")). 63 | Optional(). 64 | Immutable(). 65 | DefaultFunc(models.DefaultSpeciesType)} 66 | 67 | } 68 | func (CharacterHistory) Edges() []ent.Edge { 69 | return nil 70 | } 71 | func (CharacterHistory) Annotations() []schema.Annotation { 72 | return []schema.Annotation{entsql.Annotation{Table: "character_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 73 | } 74 | func (CharacterHistory) Mixin() []ent.Mixin { 75 | return []ent.Mixin{mixins.TimeMixin{}} 76 | } 77 | func (CharacterHistory) Indexes() []ent.Index { 78 | return []ent.Index{index.Fields("history_time")} 79 | } 80 | -------------------------------------------------------------------------------- /_examples/basic/ent/schema/friendship.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/edge" 8 | "entgo.io/ent/schema/field" 9 | 10 | "_examples/basic/ent/schema/mixins" 11 | ) 12 | 13 | // Friendship holds the schema definition for the Friendship entity. 14 | type Friendship struct { 15 | ent.Schema 16 | } 17 | 18 | // Annotations of the Friendship. 19 | func (Friendship) Annotations() []schema.Annotation { 20 | return []schema.Annotation{ 21 | entsql.Annotation{ 22 | Table: "friendship", 23 | }, 24 | } 25 | } 26 | 27 | // Fields of the Friendship. 28 | func (Friendship) Fields() []ent.Field { 29 | return []ent.Field{ 30 | field.String("id"), 31 | field.Int("character_id"), 32 | field.Int("friend_id"), 33 | } 34 | } 35 | 36 | // Edges of the Friendship. 37 | func (Friendship) Edges() []ent.Edge { 38 | return []ent.Edge{ 39 | edge.To("character", Character.Type). 40 | Required(). 41 | Unique(). 42 | Field("character_id"), 43 | edge.To("friend", Character.Type). 44 | Required(). 45 | Unique(). 46 | Field("friend_id"), 47 | } 48 | } 49 | 50 | // Mixin of the Friendship. 51 | func (Friendship) Mixin() []ent.Mixin { 52 | return []ent.Mixin{ 53 | mixins.TimeMixin{}, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /_examples/basic/ent/schema/friendship_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "_examples/basic/ent/schema/mixins" 7 | "time" 8 | 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect/entsql" 11 | "entgo.io/ent/schema" 12 | "entgo.io/ent/schema/field" 13 | "entgo.io/ent/schema/index" 14 | 15 | "github.com/flume/enthistory" 16 | ) 17 | 18 | type FriendshipHistory struct { 19 | ent.Schema 20 | } 21 | 22 | func (FriendshipHistory) Fields() []ent.Field { 23 | return []ent.Field{ 24 | field.Int("id"). 25 | Immutable(), 26 | field.Time("history_time"). 27 | Immutable(). 28 | Default(time.Now), 29 | field.Enum("operation"). 30 | Immutable(). 31 | GoType(enthistory.OpType("")), 32 | field.String("ref"). 33 | Optional(). 34 | Immutable(), 35 | field.Int("updated_by"). 36 | Nillable(). 37 | Optional(). 38 | Immutable(), 39 | field.Int("character_id"). 40 | Immutable(), 41 | field.Int("friend_id"). 42 | Immutable()} 43 | } 44 | func (FriendshipHistory) Edges() []ent.Edge { 45 | return nil 46 | } 47 | func (FriendshipHistory) Annotations() []schema.Annotation { 48 | return []schema.Annotation{entsql.Annotation{Table: "friendship_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 49 | } 50 | func (FriendshipHistory) Mixin() []ent.Mixin { 51 | return []ent.Mixin{mixins.TimeMixin{}} 52 | } 53 | func (FriendshipHistory) Indexes() []ent.Index { 54 | return []ent.Index{index.Fields("history_time")} 55 | } 56 | -------------------------------------------------------------------------------- /_examples/basic/ent/schema/mixins/timemixin.go: -------------------------------------------------------------------------------- 1 | package mixins 2 | 3 | import ( 4 | "time" 5 | 6 | "entgo.io/ent" 7 | "entgo.io/ent/schema/field" 8 | "entgo.io/ent/schema/mixin" 9 | ) 10 | 11 | type TimeMixin struct { 12 | mixin.Schema 13 | } 14 | 15 | func (TimeMixin) Fields() []ent.Field { 16 | return []ent.Field{ 17 | field.Time("created_at"). 18 | Immutable(). 19 | Default(time.Now), 20 | field.Time("updated_at"). 21 | Default(time.Now). 22 | UpdateDefault(time.Now), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /_examples/basic/ent/schema/models/models.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Uint64 uint64 4 | 5 | func DefaultUint64() Uint64 { 6 | return 0 7 | } 8 | 9 | type InfoStruct struct { 10 | FirstAppearance string `json:"firstAppearance"` 11 | LastAppearance string `json:"lastAppearance"` 12 | } 13 | 14 | func DefaultInfoStruct() InfoStruct { 15 | return InfoStruct{ 16 | FirstAppearance: "UNKNOWN", 17 | LastAppearance: "UNKNOWN", 18 | } 19 | } 20 | 21 | type SpeciesType string 22 | 23 | const ( 24 | SpeciesTypeHuman SpeciesType = "HUMAN" 25 | SpeciesTypeDog SpeciesType = "DOG" 26 | SpeciesTypePenguin SpeciesType = "PENGUIN" 27 | SpeciesTypeVampire SpeciesType = "VAMPIRE" 28 | SpeciesTypeUnknown SpeciesType = "UNKNOWN" 29 | ) 30 | 31 | func (e SpeciesType) String() string { 32 | return string(e) 33 | } 34 | 35 | func DefaultSpeciesType() SpeciesType { 36 | return SpeciesTypeUnknown 37 | } 38 | -------------------------------------------------------------------------------- /_examples/basic/ent/schema/residence.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/edge" 8 | "entgo.io/ent/schema/field" 9 | "github.com/google/uuid" 10 | 11 | "_examples/basic/ent/schema/mixins" 12 | ) 13 | 14 | // Residence holds the schema definition for the Residence entity. 15 | type Residence struct { 16 | ent.Schema 17 | } 18 | 19 | // Annotations of the Residence. 20 | func (Residence) Annotations() []schema.Annotation { 21 | return []schema.Annotation{ 22 | entsql.Annotation{ 23 | Table: "residence", 24 | }, 25 | } 26 | } 27 | 28 | // Fields of the Residence. 29 | func (Residence) Fields() []ent.Field { 30 | return []ent.Field{ 31 | field.UUID("id", uuid.UUID{}). 32 | Default(uuid.New), 33 | field.String("name"), 34 | } 35 | } 36 | 37 | // Edges of the Residence. 38 | func (Residence) Edges() []ent.Edge { 39 | return []ent.Edge{ 40 | edge.To("occupants", Character.Type), 41 | } 42 | } 43 | 44 | // Mixin of the Residence. 45 | func (Residence) Mixin() []ent.Mixin { 46 | return []ent.Mixin{ 47 | mixins.TimeMixin{}, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /_examples/basic/ent/schema/residence_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "_examples/basic/ent/schema/mixins" 7 | "time" 8 | 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect/entsql" 11 | "entgo.io/ent/schema" 12 | "entgo.io/ent/schema/field" 13 | "entgo.io/ent/schema/index" 14 | "github.com/google/uuid" 15 | 16 | "github.com/flume/enthistory" 17 | ) 18 | 19 | type ResidenceHistory struct { 20 | ent.Schema 21 | } 22 | 23 | func (ResidenceHistory) Fields() []ent.Field { 24 | return []ent.Field{ 25 | field.Int("id"). 26 | Immutable(), 27 | field.Time("history_time"). 28 | Immutable(). 29 | Default(time.Now), 30 | field.Enum("operation"). 31 | Immutable(). 32 | GoType(enthistory.OpType("")), 33 | field.UUID("ref", uuid.UUID{}). 34 | Optional(). 35 | Immutable(), 36 | field.Int("updated_by"). 37 | Nillable(). 38 | Optional(). 39 | Immutable(), 40 | field.String("name"). 41 | Immutable()} 42 | } 43 | func (ResidenceHistory) Edges() []ent.Edge { 44 | return nil 45 | } 46 | func (ResidenceHistory) Annotations() []schema.Annotation { 47 | return []schema.Annotation{entsql.Annotation{Table: "residence_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 48 | } 49 | func (ResidenceHistory) Mixin() []ent.Mixin { 50 | return []ent.Mixin{mixins.TimeMixin{}} 51 | } 52 | func (ResidenceHistory) Indexes() []ent.Index { 53 | return []ent.Index{index.Fields("history_time")} 54 | } 55 | -------------------------------------------------------------------------------- /_examples/custompaths/ent/entc.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "_examples/custompaths/ent/some/otherschema" 7 | "fmt" 8 | "log" 9 | 10 | "entgo.io/ent" 11 | 12 | "entgo.io/ent/entc/gen" 13 | 14 | "github.com/flume/enthistory" 15 | 16 | "entgo.io/ent/entc" 17 | ) 18 | 19 | const ( 20 | schemaPath = "./some/otherschema" 21 | ) 22 | 23 | func main() { 24 | if err := enthistory.Generate(schemaPath, []ent.Interface{ 25 | &otherschema.Character{}, 26 | &otherschema.Friendship{}, 27 | }); err != nil { 28 | log.Fatal(fmt.Sprintf("running enthistory codegen: %v", err)) 29 | } 30 | if err := entc.Generate(schemaPath, 31 | &gen.Config{ 32 | Target: "../internal/ent", 33 | Schema: "_examples/custompaths/ent/some/path", 34 | Package: "_examples/custompaths/internal/ent", 35 | }, 36 | entc.Extensions( 37 | enthistory.NewHistoryExtension(), 38 | ), 39 | ); err != nil { 40 | log.Fatal("running ent codegen:", err) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /_examples/custompaths/ent/generate.go: -------------------------------------------------------------------------------- 1 | package ent 2 | 3 | //go:generate go run entc.go 4 | -------------------------------------------------------------------------------- /_examples/custompaths/ent/some/otherschema/character.go: -------------------------------------------------------------------------------- 1 | package otherschema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/edge" 8 | "entgo.io/ent/schema/field" 9 | "github.com/google/uuid" 10 | ) 11 | 12 | // Character holds the schema definition for the Character entity. 13 | type Character struct { 14 | ent.Schema 15 | } 16 | 17 | // Annotations of the Character. 18 | func (Character) Annotations() []schema.Annotation { 19 | return []schema.Annotation{ 20 | entsql.Annotation{ 21 | Table: "character", 22 | }, 23 | } 24 | } 25 | 26 | // Fields of the Character. 27 | func (Character) Fields() []ent.Field { 28 | return []ent.Field{ 29 | field.UUID("id", uuid.New()).Default(uuid.New), 30 | field.Int("age"). 31 | Positive(), 32 | field.String("name"), 33 | } 34 | } 35 | 36 | // Edges of the Character. 37 | func (Character) Edges() []ent.Edge { 38 | return []ent.Edge{ 39 | edge.To("friends", Character.Type). 40 | Through("friendships", Friendship.Type), 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /_examples/custompaths/ent/some/otherschema/character_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package otherschema 4 | 5 | import ( 6 | "time" 7 | 8 | "entgo.io/ent" 9 | "entgo.io/ent/dialect/entsql" 10 | "entgo.io/ent/schema" 11 | "entgo.io/ent/schema/field" 12 | "github.com/google/uuid" 13 | 14 | "github.com/flume/enthistory" 15 | ) 16 | 17 | type CharacterHistory struct { 18 | ent.Schema 19 | } 20 | 21 | func (CharacterHistory) Fields() []ent.Field { 22 | return []ent.Field{ 23 | field.Int("id"). 24 | Immutable(), 25 | field.Time("history_time"). 26 | Immutable(). 27 | Default(time.Now), 28 | field.Enum("operation"). 29 | Immutable(). 30 | GoType(enthistory.OpType("")), 31 | field.UUID("ref", uuid.UUID{}). 32 | Optional(). 33 | Immutable(), 34 | field.Int("age"), 35 | field.String("name")} 36 | } 37 | func (CharacterHistory) Edges() []ent.Edge { 38 | return nil 39 | } 40 | func (CharacterHistory) Annotations() []schema.Annotation { 41 | return []schema.Annotation{entsql.Annotation{Table: "character_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 42 | } 43 | -------------------------------------------------------------------------------- /_examples/custompaths/ent/some/otherschema/friendship.go: -------------------------------------------------------------------------------- 1 | package otherschema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/edge" 8 | "entgo.io/ent/schema/field" 9 | "github.com/google/uuid" 10 | ) 11 | 12 | // Friendship holds the schema definition for the Friendship entity. 13 | type Friendship struct { 14 | ent.Schema 15 | } 16 | 17 | // Annotations of the Friendship. 18 | func (Friendship) Annotations() []schema.Annotation { 19 | return []schema.Annotation{ 20 | entsql.Annotation{ 21 | Table: "friendship", 22 | }, 23 | } 24 | } 25 | 26 | // Fields of the Friendship. 27 | func (Friendship) Fields() []ent.Field { 28 | return []ent.Field{ 29 | field.UUID("id", uuid.New()).Default(uuid.New), 30 | field.UUID("character_id", uuid.New()), 31 | field.UUID("friend_id", uuid.New()), 32 | } 33 | } 34 | 35 | // Edges of the Friendship. 36 | func (Friendship) Edges() []ent.Edge { 37 | return []ent.Edge{ 38 | edge.To("character", Character.Type). 39 | Required(). 40 | Unique(). 41 | Field("character_id"), 42 | edge.To("friend", Character.Type). 43 | Required(). 44 | Unique(). 45 | Field("friend_id"), 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /_examples/custompaths/ent/some/otherschema/friendship_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package otherschema 4 | 5 | import ( 6 | "time" 7 | 8 | "entgo.io/ent" 9 | "entgo.io/ent/dialect/entsql" 10 | "entgo.io/ent/schema" 11 | "entgo.io/ent/schema/field" 12 | "github.com/google/uuid" 13 | 14 | "github.com/flume/enthistory" 15 | ) 16 | 17 | type FriendshipHistory struct { 18 | ent.Schema 19 | } 20 | 21 | func (FriendshipHistory) Fields() []ent.Field { 22 | return []ent.Field{ 23 | field.Int("id"). 24 | Immutable(), 25 | field.Time("history_time"). 26 | Immutable(). 27 | Default(time.Now), 28 | field.Enum("operation"). 29 | Immutable(). 30 | GoType(enthistory.OpType("")), 31 | field.UUID("ref", uuid.UUID{}). 32 | Optional(). 33 | Immutable(), 34 | field.UUID("character_id", uuid.UUID{}), 35 | field.UUID("friend_id", uuid.UUID{})} 36 | } 37 | func (FriendshipHistory) Edges() []ent.Edge { 38 | return nil 39 | } 40 | func (FriendshipHistory) Annotations() []schema.Annotation { 41 | return []schema.Annotation{entsql.Annotation{Table: "friendship_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 42 | } 43 | -------------------------------------------------------------------------------- /_examples/custompaths/internal/ent/character_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/custompaths/internal/ent/character" 7 | "_examples/custompaths/internal/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // CharacterDelete is the builder for deleting a Character entity. 16 | type CharacterDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *CharacterMutation 20 | } 21 | 22 | // Where appends a list predicates to the CharacterDelete builder. 23 | func (cd *CharacterDelete) Where(ps ...predicate.Character) *CharacterDelete { 24 | cd.mutation.Where(ps...) 25 | return cd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (cd *CharacterDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, cd.sqlExec, cd.mutation, cd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (cd *CharacterDelete) ExecX(ctx context.Context) int { 35 | n, err := cd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (cd *CharacterDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(character.Table, sqlgraph.NewFieldSpec(character.FieldID, field.TypeUUID)) 44 | if ps := cd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, cd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | cd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // CharacterDeleteOne is the builder for deleting a single Character entity. 60 | type CharacterDeleteOne struct { 61 | cd *CharacterDelete 62 | } 63 | 64 | // Where appends a list predicates to the CharacterDelete builder. 65 | func (cdo *CharacterDeleteOne) Where(ps ...predicate.Character) *CharacterDeleteOne { 66 | cdo.cd.mutation.Where(ps...) 67 | return cdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (cdo *CharacterDeleteOne) Exec(ctx context.Context) error { 72 | n, err := cdo.cd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{character.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (cdo *CharacterDeleteOne) ExecX(ctx context.Context) { 85 | if err := cdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/custompaths/internal/ent/enttest/enttest.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package enttest 4 | 5 | import ( 6 | "context" 7 | 8 | "_examples/custompaths/internal/ent" 9 | // required by schema hooks. 10 | _ "_examples/custompaths/internal/ent/runtime" 11 | 12 | "_examples/custompaths/internal/ent/migrate" 13 | 14 | "entgo.io/ent/dialect/sql/schema" 15 | ) 16 | 17 | type ( 18 | // TestingT is the interface that is shared between 19 | // testing.T and testing.B and used by enttest. 20 | TestingT interface { 21 | FailNow() 22 | Error(...any) 23 | } 24 | 25 | // Option configures client creation. 26 | Option func(*options) 27 | 28 | options struct { 29 | opts []ent.Option 30 | migrateOpts []schema.MigrateOption 31 | } 32 | ) 33 | 34 | // WithOptions forwards options to client creation. 35 | func WithOptions(opts ...ent.Option) Option { 36 | return func(o *options) { 37 | o.opts = append(o.opts, opts...) 38 | } 39 | } 40 | 41 | // WithMigrateOptions forwards options to auto migration. 42 | func WithMigrateOptions(opts ...schema.MigrateOption) Option { 43 | return func(o *options) { 44 | o.migrateOpts = append(o.migrateOpts, opts...) 45 | } 46 | } 47 | 48 | func newOptions(opts []Option) *options { 49 | o := &options{} 50 | for _, opt := range opts { 51 | opt(o) 52 | } 53 | return o 54 | } 55 | 56 | // Open calls ent.Open and auto-run migration. 57 | func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { 58 | o := newOptions(opts) 59 | c, err := ent.Open(driverName, dataSourceName, o.opts...) 60 | if err != nil { 61 | t.Error(err) 62 | t.FailNow() 63 | } 64 | migrateSchema(t, c, o) 65 | return c 66 | } 67 | 68 | // NewClient calls ent.NewClient and auto-run migration. 69 | func NewClient(t TestingT, opts ...Option) *ent.Client { 70 | o := newOptions(opts) 71 | c := ent.NewClient(o.opts...) 72 | migrateSchema(t, c, o) 73 | return c 74 | } 75 | func migrateSchema(t TestingT, c *ent.Client, o *options) { 76 | tables, err := schema.CopyTables(migrate.Tables) 77 | if err != nil { 78 | t.Error(err) 79 | t.FailNow() 80 | } 81 | if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { 82 | t.Error(err) 83 | t.FailNow() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /_examples/custompaths/internal/ent/friendship_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/custompaths/internal/ent/friendship" 7 | "_examples/custompaths/internal/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // FriendshipDelete is the builder for deleting a Friendship entity. 16 | type FriendshipDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *FriendshipMutation 20 | } 21 | 22 | // Where appends a list predicates to the FriendshipDelete builder. 23 | func (fd *FriendshipDelete) Where(ps ...predicate.Friendship) *FriendshipDelete { 24 | fd.mutation.Where(ps...) 25 | return fd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (fd *FriendshipDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, fd.sqlExec, fd.mutation, fd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (fd *FriendshipDelete) ExecX(ctx context.Context) int { 35 | n, err := fd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (fd *FriendshipDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(friendship.Table, sqlgraph.NewFieldSpec(friendship.FieldID, field.TypeUUID)) 44 | if ps := fd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, fd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | fd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // FriendshipDeleteOne is the builder for deleting a single Friendship entity. 60 | type FriendshipDeleteOne struct { 61 | fd *FriendshipDelete 62 | } 63 | 64 | // Where appends a list predicates to the FriendshipDelete builder. 65 | func (fdo *FriendshipDeleteOne) Where(ps ...predicate.Friendship) *FriendshipDeleteOne { 66 | fdo.fd.mutation.Where(ps...) 67 | return fdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (fdo *FriendshipDeleteOne) Exec(ctx context.Context) error { 72 | n, err := fdo.fd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{friendship.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (fdo *FriendshipDeleteOne) ExecX(ctx context.Context) { 85 | if err := fdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/custompaths/internal/ent/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io" 9 | 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | var ( 15 | // WithGlobalUniqueID sets the universal ids options to the migration. 16 | // If this option is enabled, ent migration will allocate a 1<<32 range 17 | // for the ids of each entity (table). 18 | // Note that this option cannot be applied on tables that already exist. 19 | WithGlobalUniqueID = schema.WithGlobalUniqueID 20 | // WithDropColumn sets the drop column option to the migration. 21 | // If this option is enabled, ent migration will drop old columns 22 | // that were used for both fields and edges. This defaults to false. 23 | WithDropColumn = schema.WithDropColumn 24 | // WithDropIndex sets the drop index option to the migration. 25 | // If this option is enabled, ent migration will drop old indexes 26 | // that were defined in the schema. This defaults to false. 27 | // Note that unique constraints are defined using `UNIQUE INDEX`, 28 | // and therefore, it's recommended to enable this option to get more 29 | // flexibility in the schema changes. 30 | WithDropIndex = schema.WithDropIndex 31 | // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. 32 | WithForeignKeys = schema.WithForeignKeys 33 | ) 34 | 35 | // Schema is the API for creating, migrating and dropping a schema. 36 | type Schema struct { 37 | drv dialect.Driver 38 | } 39 | 40 | // NewSchema creates a new schema client. 41 | func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } 42 | 43 | // Create creates all schema resources. 44 | func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { 45 | return Create(ctx, s, Tables, opts...) 46 | } 47 | 48 | // Create creates all table resources using the given schema driver. 49 | func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error { 50 | migrate, err := schema.NewMigrate(s.drv, opts...) 51 | if err != nil { 52 | return fmt.Errorf("ent/migrate: %w", err) 53 | } 54 | return migrate.Create(ctx, tables...) 55 | } 56 | 57 | // WriteTo writes the schema changes to w instead of running them against the database. 58 | // 59 | // if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { 60 | // log.Fatal(err) 61 | // } 62 | func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { 63 | return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...) 64 | } 65 | -------------------------------------------------------------------------------- /_examples/custompaths/internal/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // Character is the predicate function for character builders. 10 | type Character func(*sql.Selector) 11 | 12 | // CharacterHistory is the predicate function for characterhistory builders. 13 | type CharacterHistory func(*sql.Selector) 14 | 15 | // Friendship is the predicate function for friendship builders. 16 | type Friendship func(*sql.Selector) 17 | 18 | // FriendshipHistory is the predicate function for friendshiphistory builders. 19 | type FriendshipHistory func(*sql.Selector) 20 | -------------------------------------------------------------------------------- /_examples/custompaths/internal/ent/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/custompaths/ent/some/otherschema" 7 | "_examples/custompaths/internal/ent/character" 8 | "_examples/custompaths/internal/ent/characterhistory" 9 | "_examples/custompaths/internal/ent/friendship" 10 | "_examples/custompaths/internal/ent/friendshiphistory" 11 | "time" 12 | 13 | "github.com/google/uuid" 14 | ) 15 | 16 | // The init function reads all schema descriptors with runtime code 17 | // (default values, validators, hooks and policies) and stitches it 18 | // to their package variables. 19 | func init() { 20 | characterFields := otherschema.Character{}.Fields() 21 | _ = characterFields 22 | // characterDescAge is the schema descriptor for age field. 23 | characterDescAge := characterFields[1].Descriptor() 24 | // character.AgeValidator is a validator for the "age" field. It is called by the builders before save. 25 | character.AgeValidator = characterDescAge.Validators[0].(func(int) error) 26 | // characterDescID is the schema descriptor for id field. 27 | characterDescID := characterFields[0].Descriptor() 28 | // character.DefaultID holds the default value on creation for the id field. 29 | character.DefaultID = characterDescID.Default.(func() uuid.UUID) 30 | characterhistoryFields := otherschema.CharacterHistory{}.Fields() 31 | _ = characterhistoryFields 32 | // characterhistoryDescHistoryTime is the schema descriptor for history_time field. 33 | characterhistoryDescHistoryTime := characterhistoryFields[1].Descriptor() 34 | // characterhistory.DefaultHistoryTime holds the default value on creation for the history_time field. 35 | characterhistory.DefaultHistoryTime = characterhistoryDescHistoryTime.Default.(func() time.Time) 36 | friendshipFields := otherschema.Friendship{}.Fields() 37 | _ = friendshipFields 38 | // friendshipDescID is the schema descriptor for id field. 39 | friendshipDescID := friendshipFields[0].Descriptor() 40 | // friendship.DefaultID holds the default value on creation for the id field. 41 | friendship.DefaultID = friendshipDescID.Default.(func() uuid.UUID) 42 | friendshiphistoryFields := otherschema.FriendshipHistory{}.Fields() 43 | _ = friendshiphistoryFields 44 | // friendshiphistoryDescHistoryTime is the schema descriptor for history_time field. 45 | friendshiphistoryDescHistoryTime := friendshiphistoryFields[1].Descriptor() 46 | // friendshiphistory.DefaultHistoryTime holds the default value on creation for the history_time field. 47 | friendshiphistory.DefaultHistoryTime = friendshiphistoryDescHistoryTime.Default.(func() time.Time) 48 | } 49 | -------------------------------------------------------------------------------- /_examples/custompaths/internal/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in _examples/custompaths/internal/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.14.4" // Version of ent codegen. 9 | Sum = "h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /_examples/go.mod: -------------------------------------------------------------------------------- 1 | module _examples 2 | 3 | go 1.24.2 4 | 5 | require ( 6 | entgo.io/contrib v0.6.0 7 | entgo.io/ent v0.14.4 8 | github.com/99designs/gqlgen v0.17.70 9 | github.com/flume/enthistory v0.16.2 10 | github.com/google/uuid v1.6.0 11 | github.com/hashicorp/go-multierror v1.1.1 12 | github.com/mattn/go-sqlite3 v1.14.27 13 | github.com/stretchr/testify v1.10.0 14 | github.com/vektah/gqlparser/v2 v2.5.24 15 | ) 16 | 17 | require ( 18 | ariga.io/atlas v0.32.0 // indirect 19 | github.com/agext/levenshtein v1.2.3 // indirect 20 | github.com/agnivade/levenshtein v1.2.1 // indirect 21 | github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect 22 | github.com/bmatcuk/doublestar v1.3.4 // indirect 23 | github.com/bufbuild/protocompile v0.14.1 // indirect 24 | github.com/davecgh/go-spew v1.1.1 // indirect 25 | github.com/go-openapi/inflect v0.21.2 // indirect 26 | github.com/golang/protobuf v1.5.4 // indirect 27 | github.com/google/go-cmp v0.7.0 // indirect 28 | github.com/hashicorp/errwrap v1.1.0 // indirect 29 | github.com/hashicorp/hcl/v2 v2.23.0 // indirect 30 | github.com/jhump/protoreflect v1.17.0 // indirect 31 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 32 | github.com/mitchellh/mapstructure v1.5.0 // indirect 33 | github.com/pmezard/go-difflib v1.0.0 // indirect 34 | github.com/sosodev/duration v1.3.1 // indirect 35 | github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 36 | github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 37 | github.com/zclconf/go-cty v1.16.2 // indirect 38 | github.com/zclconf/go-cty-yaml v1.1.0 // indirect 39 | go.uber.org/multierr v1.11.0 // indirect 40 | golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect 41 | golang.org/x/mod v0.24.0 // indirect 42 | golang.org/x/sync v0.13.0 // indirect 43 | golang.org/x/text v0.24.0 // indirect 44 | golang.org/x/tools v0.32.0 // indirect 45 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect 46 | google.golang.org/protobuf v1.36.6 // indirect 47 | gopkg.in/yaml.v3 v3.0.1 // indirect 48 | ) 49 | 50 | replace github.com/flume/enthistory => ../. 51 | -------------------------------------------------------------------------------- /_examples/graphql/README.md: -------------------------------------------------------------------------------- 1 | # GraphQL Ent Codegen Test Project 2 | 3 | Thank you to [@nixxxon](https://github.com/nixxxon) and their [demo project](https://github.com/nixxxon/entdemo) 4 | -------------------------------------------------------------------------------- /_examples/graphql/ent/entc.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "_examples/graphql/ent/schema" 7 | "log" 8 | 9 | "entgo.io/ent" 10 | 11 | "entgo.io/contrib/entgql" 12 | "entgo.io/ent/entc/gen" 13 | 14 | "github.com/flume/enthistory" 15 | 16 | "entgo.io/ent/entc" 17 | ) 18 | 19 | func main() { 20 | err := enthistory.Generate("./ent/schema", []ent.Interface{ 21 | schema.TestSkip{}, 22 | schema.Todo{}, 23 | }, 24 | enthistory.WithUpdatedBy("userId", enthistory.ValueTypeUUID), 25 | enthistory.WithInheritIdType(), 26 | ) 27 | if err != nil { 28 | log.Fatalf("failed to run enthistory codegen: %v", err) 29 | } 30 | 31 | gqlExtension, err := entgql.NewExtension( 32 | // Generate a GraphQL schema for the Ent schema 33 | // and save it as "query.graphql". 34 | entgql.WithSchemaGenerator(), 35 | entgql.WithWhereInputs(true), 36 | entgql.WithSchemaPath("graphql/query.graphql"), 37 | entgql.WithConfigPath("gqlgen.yml"), 38 | ) 39 | if err != nil { 40 | log.Fatalf("failed to create entgql extension: %v", err) 41 | } 42 | 43 | historyExtension := enthistory.NewHistoryExtension() 44 | 45 | opts := []entc.Option{ 46 | entc.Extensions(gqlExtension, historyExtension), 47 | } 48 | 49 | if err = entc.Generate("./ent/schema", &gen.Config{ 50 | Target: "ent", 51 | Package: "_examples/graphql/ent", 52 | Features: []gen.Feature{ 53 | gen.FeatureEntQL, 54 | gen.FeaturePrivacy, 55 | gen.FeatureSnapshot, 56 | }, 57 | }, opts...); err != nil { 58 | log.Fatalf("failed to run ent codegen: %v", err) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /_examples/graphql/ent/enttest/enttest.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package enttest 4 | 5 | import ( 6 | "context" 7 | 8 | "_examples/graphql/ent" 9 | // required by schema hooks. 10 | _ "_examples/graphql/ent/runtime" 11 | 12 | "_examples/graphql/ent/migrate" 13 | 14 | "entgo.io/ent/dialect/sql/schema" 15 | ) 16 | 17 | type ( 18 | // TestingT is the interface that is shared between 19 | // testing.T and testing.B and used by enttest. 20 | TestingT interface { 21 | FailNow() 22 | Error(...any) 23 | } 24 | 25 | // Option configures client creation. 26 | Option func(*options) 27 | 28 | options struct { 29 | opts []ent.Option 30 | migrateOpts []schema.MigrateOption 31 | } 32 | ) 33 | 34 | // WithOptions forwards options to client creation. 35 | func WithOptions(opts ...ent.Option) Option { 36 | return func(o *options) { 37 | o.opts = append(o.opts, opts...) 38 | } 39 | } 40 | 41 | // WithMigrateOptions forwards options to auto migration. 42 | func WithMigrateOptions(opts ...schema.MigrateOption) Option { 43 | return func(o *options) { 44 | o.migrateOpts = append(o.migrateOpts, opts...) 45 | } 46 | } 47 | 48 | func newOptions(opts []Option) *options { 49 | o := &options{} 50 | for _, opt := range opts { 51 | opt(o) 52 | } 53 | return o 54 | } 55 | 56 | // Open calls ent.Open and auto-run migration. 57 | func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { 58 | o := newOptions(opts) 59 | c, err := ent.Open(driverName, dataSourceName, o.opts...) 60 | if err != nil { 61 | t.Error(err) 62 | t.FailNow() 63 | } 64 | migrateSchema(t, c, o) 65 | return c 66 | } 67 | 68 | // NewClient calls ent.NewClient and auto-run migration. 69 | func NewClient(t TestingT, opts ...Option) *ent.Client { 70 | o := newOptions(opts) 71 | c := ent.NewClient(o.opts...) 72 | migrateSchema(t, c, o) 73 | return c 74 | } 75 | func migrateSchema(t TestingT, c *ent.Client, o *options) { 76 | tables, err := schema.CopyTables(migrate.Tables) 77 | if err != nil { 78 | t.Error(err) 79 | t.FailNow() 80 | } 81 | if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { 82 | t.Error(err) 83 | t.FailNow() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /_examples/graphql/ent/gql_edge.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | -------------------------------------------------------------------------------- /_examples/graphql/ent/gql_mutation_input.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "github.com/google/uuid" 7 | ) 8 | 9 | // CreateTodoInput represents a mutation input for creating todos. 10 | type CreateTodoInput struct { 11 | OtherID *uuid.UUID 12 | Name string 13 | } 14 | 15 | // Mutate applies the CreateTodoInput on the TodoMutation builder. 16 | func (i *CreateTodoInput) Mutate(m *TodoMutation) { 17 | if v := i.OtherID; v != nil { 18 | m.SetOtherID(*v) 19 | } 20 | m.SetName(i.Name) 21 | } 22 | 23 | // SetInput applies the change-set in the CreateTodoInput on the TodoCreate builder. 24 | func (c *TodoCreate) SetInput(i CreateTodoInput) *TodoCreate { 25 | i.Mutate(c.Mutation()) 26 | return c 27 | } 28 | 29 | // UpdateTodoInput represents a mutation input for updating todos. 30 | type UpdateTodoInput struct { 31 | ClearOtherID bool 32 | OtherID *uuid.UUID 33 | Name *string 34 | } 35 | 36 | // Mutate applies the UpdateTodoInput on the TodoMutation builder. 37 | func (i *UpdateTodoInput) Mutate(m *TodoMutation) { 38 | if i.ClearOtherID { 39 | m.ClearOtherID() 40 | } 41 | if v := i.OtherID; v != nil { 42 | m.SetOtherID(*v) 43 | } 44 | if v := i.Name; v != nil { 45 | m.SetName(*v) 46 | } 47 | } 48 | 49 | // SetInput applies the change-set in the UpdateTodoInput on the TodoUpdate builder. 50 | func (c *TodoUpdate) SetInput(i UpdateTodoInput) *TodoUpdate { 51 | i.Mutate(c.Mutation()) 52 | return c 53 | } 54 | 55 | // SetInput applies the change-set in the UpdateTodoInput on the TodoUpdateOne builder. 56 | func (c *TodoUpdateOne) SetInput(i UpdateTodoInput) *TodoUpdateOne { 57 | i.Mutate(c.Mutation()) 58 | return c 59 | } 60 | -------------------------------------------------------------------------------- /_examples/graphql/ent/gql_transaction.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "database/sql/driver" 8 | "errors" 9 | ) 10 | 11 | // OpenTx opens a transaction and returns a transactional 12 | // context along with the created transaction. 13 | func (c *Client) OpenTx(ctx context.Context) (context.Context, driver.Tx, error) { 14 | tx, err := c.Tx(ctx) 15 | if err != nil { 16 | return nil, nil, err 17 | } 18 | ctx = NewTxContext(ctx, tx) 19 | ctx = NewContext(ctx, tx.Client()) 20 | return ctx, tx, nil 21 | } 22 | 23 | // OpenTxFromContext open transactions from client stored in context. 24 | func OpenTxFromContext(ctx context.Context) (context.Context, driver.Tx, error) { 25 | client := FromContext(ctx) 26 | if client == nil { 27 | return nil, nil, errors.New("no client attached to context") 28 | } 29 | return client.OpenTx(ctx) 30 | } 31 | -------------------------------------------------------------------------------- /_examples/graphql/ent/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io" 9 | 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | var ( 15 | // WithGlobalUniqueID sets the universal ids options to the migration. 16 | // If this option is enabled, ent migration will allocate a 1<<32 range 17 | // for the ids of each entity (table). 18 | // Note that this option cannot be applied on tables that already exist. 19 | WithGlobalUniqueID = schema.WithGlobalUniqueID 20 | // WithDropColumn sets the drop column option to the migration. 21 | // If this option is enabled, ent migration will drop old columns 22 | // that were used for both fields and edges. This defaults to false. 23 | WithDropColumn = schema.WithDropColumn 24 | // WithDropIndex sets the drop index option to the migration. 25 | // If this option is enabled, ent migration will drop old indexes 26 | // that were defined in the schema. This defaults to false. 27 | // Note that unique constraints are defined using `UNIQUE INDEX`, 28 | // and therefore, it's recommended to enable this option to get more 29 | // flexibility in the schema changes. 30 | WithDropIndex = schema.WithDropIndex 31 | // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. 32 | WithForeignKeys = schema.WithForeignKeys 33 | ) 34 | 35 | // Schema is the API for creating, migrating and dropping a schema. 36 | type Schema struct { 37 | drv dialect.Driver 38 | } 39 | 40 | // NewSchema creates a new schema client. 41 | func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } 42 | 43 | // Create creates all schema resources. 44 | func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { 45 | return Create(ctx, s, Tables, opts...) 46 | } 47 | 48 | // Create creates all table resources using the given schema driver. 49 | func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error { 50 | migrate, err := schema.NewMigrate(s.drv, opts...) 51 | if err != nil { 52 | return fmt.Errorf("ent/migrate: %w", err) 53 | } 54 | return migrate.Create(ctx, tables...) 55 | } 56 | 57 | // WriteTo writes the schema changes to w instead of running them against the database. 58 | // 59 | // if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { 60 | // log.Fatal(err) 61 | // } 62 | func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { 63 | return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...) 64 | } 65 | -------------------------------------------------------------------------------- /_examples/graphql/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // TestExclude is the predicate function for testexclude builders. 10 | type TestExclude func(*sql.Selector) 11 | 12 | // TestSkip is the predicate function for testskip builders. 13 | type TestSkip func(*sql.Selector) 14 | 15 | // TestSkipHistory is the predicate function for testskiphistory builders. 16 | type TestSkipHistory func(*sql.Selector) 17 | 18 | // Todo is the predicate function for todo builders. 19 | type Todo func(*sql.Selector) 20 | 21 | // TodoHistory is the predicate function for todohistory builders. 22 | type TodoHistory func(*sql.Selector) 23 | -------------------------------------------------------------------------------- /_examples/graphql/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in _examples/graphql/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.14.4" // Version of ent codegen. 9 | Sum = "h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /_examples/graphql/ent/schema/testexclude.go: -------------------------------------------------------------------------------- 1 | // Test Schema courtesy of: github.com/nixxxon/entdemo 2 | 3 | package schema 4 | 5 | import ( 6 | "entgo.io/contrib/entgql" 7 | "entgo.io/ent" 8 | "entgo.io/ent/dialect/entsql" 9 | "entgo.io/ent/schema" 10 | "entgo.io/ent/schema/field" 11 | "github.com/google/uuid" 12 | ) 13 | 14 | // TestExclude holds the schema definition for the TestExclude entity. 15 | type TestExclude struct { 16 | ent.Schema 17 | } 18 | 19 | // Fields of the TestExclude. 20 | func (TestExclude) Fields() []ent.Field { 21 | return []ent.Field{ 22 | field.UUID("id", uuid.New()).Default(uuid.New), 23 | field.UUID("other_id", uuid.New()).Optional().Annotations( 24 | entgql.Annotation{ 25 | Type: "ID", 26 | }, 27 | ), 28 | field.String("name").NotEmpty().Annotations( 29 | entgql.OrderField("NAME"), 30 | ), 31 | } 32 | } 33 | 34 | func (TestExclude) Annotations() []schema.Annotation { 35 | return []schema.Annotation{ 36 | entsql.Annotation{ 37 | Table: "TestExclude", 38 | }, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /_examples/graphql/ent/schema/testskip.go: -------------------------------------------------------------------------------- 1 | // Test Schema courtesy of: github.com/nixxxon/entdemo 2 | 3 | package schema 4 | 5 | import ( 6 | "entgo.io/contrib/entgql" 7 | "entgo.io/ent" 8 | "entgo.io/ent/dialect/entsql" 9 | "entgo.io/ent/schema" 10 | "entgo.io/ent/schema/field" 11 | "github.com/google/uuid" 12 | ) 13 | 14 | // TestSkip holds the schema definition for the TestSkip entity. 15 | type TestSkip struct { 16 | ent.Schema 17 | } 18 | 19 | // Fields of the TestSkip. 20 | func (TestSkip) Fields() []ent.Field { 21 | return []ent.Field{ 22 | field.UUID("id", uuid.New()).Default(uuid.New), 23 | field.UUID("other_id", uuid.New()).Optional().Annotations( 24 | entgql.Annotation{ 25 | Type: "ID", 26 | }, 27 | ), 28 | field.String("name").NotEmpty().Annotations( 29 | entgql.OrderField("NAME"), 30 | ), 31 | } 32 | } 33 | 34 | func (TestSkip) Annotations() []schema.Annotation { 35 | return []schema.Annotation{ 36 | entgql.Skip(), 37 | entsql.Annotation{ 38 | Table: "testskip", 39 | }, 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /_examples/graphql/ent/schema/testskip_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "time" 7 | 8 | "entgo.io/contrib/entgql" 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect/entsql" 11 | "entgo.io/ent/schema" 12 | "entgo.io/ent/schema/field" 13 | "github.com/google/uuid" 14 | 15 | "github.com/flume/enthistory" 16 | ) 17 | 18 | type TestSkipHistory struct { 19 | ent.Schema 20 | } 21 | 22 | func (TestSkipHistory) Fields() []ent.Field { 23 | return []ent.Field{ 24 | field.UUID("id", uuid.UUID{}). 25 | Default(uuid.New), 26 | field.Time("history_time"). 27 | Immutable(). 28 | Default(time.Now), 29 | field.Enum("operation"). 30 | Immutable(). 31 | GoType(enthistory.OpType("")), 32 | field.UUID("ref", uuid.UUID{}). 33 | Optional(). 34 | Immutable(). 35 | Annotations(entgql.Annotation{Type: "ID"}), 36 | field.UUID("updated_by", uuid.UUID{}). 37 | Nillable(). 38 | Optional(). 39 | Immutable(). 40 | Annotations(entgql.Annotation{Type: "ID"}), 41 | field.UUID("other_id", uuid.UUID{}). 42 | Optional(). 43 | Annotations(entgql.Annotation{Type: "ID"}), 44 | field.String("name"). 45 | Annotations(entgql.Annotation{OrderField: "NAME"})} 46 | } 47 | func (TestSkipHistory) Edges() []ent.Edge { 48 | return nil 49 | } 50 | func (TestSkipHistory) Annotations() []schema.Annotation { 51 | return []schema.Annotation{entgql.Annotation{Skip: entgql.SkipAll}, entsql.Annotation{Table: "testskip_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 52 | } 53 | -------------------------------------------------------------------------------- /_examples/graphql/ent/schema/todo.go: -------------------------------------------------------------------------------- 1 | // Test Schema courtesy of: github.com/nixxxon/entdemo 2 | 3 | package schema 4 | 5 | import ( 6 | "entgo.io/contrib/entgql" 7 | "entgo.io/ent" 8 | "entgo.io/ent/dialect/entsql" 9 | "entgo.io/ent/schema" 10 | "entgo.io/ent/schema/field" 11 | "github.com/google/uuid" 12 | 13 | "github.com/flume/enthistory" 14 | ) 15 | 16 | // Todo holds the schema definition for the Todo entity. 17 | type Todo struct { 18 | ent.Schema 19 | } 20 | 21 | // Fields of the Todo. 22 | func (Todo) Fields() []ent.Field { 23 | return []ent.Field{ 24 | field.UUID("id", uuid.New()).Default(uuid.New).Annotations(entgql.Annotation{Type: "ID"}), 25 | field.UUID("other_id", uuid.New()).Optional().Annotations(entgql.Annotation{Type: "ID"}), 26 | field.String("name").NotEmpty().Annotations( 27 | entgql.OrderField("NAME"), 28 | ), 29 | } 30 | } 31 | 32 | func (Todo) Annotations() []schema.Annotation { 33 | return []schema.Annotation{ 34 | entgql.RelayConnection(), 35 | entgql.QueryField(), 36 | entgql.Mutations(entgql.MutationCreate(), entgql.MutationUpdate()), 37 | enthistory.Annotations{ 38 | Annotations: []schema.Annotation{ 39 | // no mutations on TodoHistory 40 | entgql.RelayConnection(), 41 | entgql.QueryField(), 42 | entsql.Annotation{Table: "todo_history"}, 43 | }, 44 | }, 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /_examples/graphql/ent/schema/todo_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "time" 7 | 8 | "entgo.io/contrib/entgql" 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect/entsql" 11 | "entgo.io/ent/schema" 12 | "entgo.io/ent/schema/field" 13 | "github.com/google/uuid" 14 | 15 | "github.com/flume/enthistory" 16 | ) 17 | 18 | type TodoHistory struct { 19 | ent.Schema 20 | } 21 | 22 | func (TodoHistory) Fields() []ent.Field { 23 | return []ent.Field{ 24 | field.UUID("id", uuid.UUID{}). 25 | Annotations(entgql.Annotation{Type: "ID"}). 26 | Default(uuid.New), 27 | field.Time("history_time"). 28 | Immutable(). 29 | Default(time.Now), 30 | field.Enum("operation"). 31 | Immutable(). 32 | GoType(enthistory.OpType("")), 33 | field.UUID("ref", uuid.UUID{}). 34 | Optional(). 35 | Immutable(). 36 | Annotations(entgql.Annotation{Type: "ID"}), 37 | field.UUID("updated_by", uuid.UUID{}). 38 | Nillable(). 39 | Optional(). 40 | Immutable(). 41 | Annotations(entgql.Annotation{Type: "ID"}), 42 | field.UUID("other_id", uuid.UUID{}). 43 | Optional(). 44 | Annotations(entgql.Annotation{Type: "ID"}), 45 | field.String("name"). 46 | Annotations(entgql.Annotation{OrderField: "NAME"})} 47 | } 48 | func (TodoHistory) Edges() []ent.Edge { 49 | return nil 50 | } 51 | func (TodoHistory) Annotations() []schema.Annotation { 52 | return []schema.Annotation{entgql.Annotation{RelayConnection: true, QueryField: &entgql.FieldConfig{}}, entsql.Annotation{Table: "todo_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 53 | } 54 | -------------------------------------------------------------------------------- /_examples/graphql/ent/schema/uuidgql/uuidgql.go: -------------------------------------------------------------------------------- 1 | package uuidgql 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "strconv" 7 | 8 | "github.com/99designs/gqlgen/graphql" 9 | "github.com/google/uuid" 10 | ) 11 | 12 | func MarshalUUID(u uuid.UUID) graphql.Marshaler { 13 | return graphql.WriterFunc(func(w io.Writer) { 14 | _, _ = io.WriteString(w, strconv.Quote(u.String())) 15 | }) 16 | } 17 | 18 | func UnmarshalUUID(v interface{}) (u uuid.UUID, err error) { 19 | s, ok := v.(string) 20 | if !ok { 21 | return u, fmt.Errorf("invalid type %T, expect string", v) 22 | } 23 | return uuid.Parse(s) 24 | } 25 | -------------------------------------------------------------------------------- /_examples/graphql/ent/testexclude/testexclude.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package testexclude 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | "github.com/google/uuid" 8 | ) 9 | 10 | const ( 11 | // Label holds the string label denoting the testexclude type in the database. 12 | Label = "test_exclude" 13 | // FieldID holds the string denoting the id field in the database. 14 | FieldID = "id" 15 | // FieldOtherID holds the string denoting the other_id field in the database. 16 | FieldOtherID = "other_id" 17 | // FieldName holds the string denoting the name field in the database. 18 | FieldName = "name" 19 | // Table holds the table name of the testexclude in the database. 20 | Table = "TestExclude" 21 | ) 22 | 23 | // Columns holds all SQL columns for testexclude fields. 24 | var Columns = []string{ 25 | FieldID, 26 | FieldOtherID, 27 | FieldName, 28 | } 29 | 30 | // ValidColumn reports if the column name is valid (part of the table columns). 31 | func ValidColumn(column string) bool { 32 | for i := range Columns { 33 | if column == Columns[i] { 34 | return true 35 | } 36 | } 37 | return false 38 | } 39 | 40 | var ( 41 | // NameValidator is a validator for the "name" field. It is called by the builders before save. 42 | NameValidator func(string) error 43 | // DefaultID holds the default value on creation for the "id" field. 44 | DefaultID func() uuid.UUID 45 | ) 46 | 47 | // OrderOption defines the ordering options for the TestExclude queries. 48 | type OrderOption func(*sql.Selector) 49 | 50 | // ByID orders the results by the id field. 51 | func ByID(opts ...sql.OrderTermOption) OrderOption { 52 | return sql.OrderByField(FieldID, opts...).ToFunc() 53 | } 54 | 55 | // ByOtherID orders the results by the other_id field. 56 | func ByOtherID(opts ...sql.OrderTermOption) OrderOption { 57 | return sql.OrderByField(FieldOtherID, opts...).ToFunc() 58 | } 59 | 60 | // ByName orders the results by the name field. 61 | func ByName(opts ...sql.OrderTermOption) OrderOption { 62 | return sql.OrderByField(FieldName, opts...).ToFunc() 63 | } 64 | -------------------------------------------------------------------------------- /_examples/graphql/ent/testexclude_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/graphql/ent/predicate" 7 | "_examples/graphql/ent/testexclude" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // TestExcludeDelete is the builder for deleting a TestExclude entity. 16 | type TestExcludeDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *TestExcludeMutation 20 | } 21 | 22 | // Where appends a list predicates to the TestExcludeDelete builder. 23 | func (ted *TestExcludeDelete) Where(ps ...predicate.TestExclude) *TestExcludeDelete { 24 | ted.mutation.Where(ps...) 25 | return ted 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (ted *TestExcludeDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, ted.sqlExec, ted.mutation, ted.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (ted *TestExcludeDelete) ExecX(ctx context.Context) int { 35 | n, err := ted.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (ted *TestExcludeDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(testexclude.Table, sqlgraph.NewFieldSpec(testexclude.FieldID, field.TypeUUID)) 44 | if ps := ted.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, ted.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | ted.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // TestExcludeDeleteOne is the builder for deleting a single TestExclude entity. 60 | type TestExcludeDeleteOne struct { 61 | ted *TestExcludeDelete 62 | } 63 | 64 | // Where appends a list predicates to the TestExcludeDelete builder. 65 | func (tedo *TestExcludeDeleteOne) Where(ps ...predicate.TestExclude) *TestExcludeDeleteOne { 66 | tedo.ted.mutation.Where(ps...) 67 | return tedo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (tedo *TestExcludeDeleteOne) Exec(ctx context.Context) error { 72 | n, err := tedo.ted.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{testexclude.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (tedo *TestExcludeDeleteOne) ExecX(ctx context.Context) { 85 | if err := tedo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/graphql/ent/testskip/testskip.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package testskip 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | "github.com/google/uuid" 8 | ) 9 | 10 | const ( 11 | // Label holds the string label denoting the testskip type in the database. 12 | Label = "test_skip" 13 | // FieldID holds the string denoting the id field in the database. 14 | FieldID = "id" 15 | // FieldOtherID holds the string denoting the other_id field in the database. 16 | FieldOtherID = "other_id" 17 | // FieldName holds the string denoting the name field in the database. 18 | FieldName = "name" 19 | // Table holds the table name of the testskip in the database. 20 | Table = "testskip" 21 | ) 22 | 23 | // Columns holds all SQL columns for testskip fields. 24 | var Columns = []string{ 25 | FieldID, 26 | FieldOtherID, 27 | FieldName, 28 | } 29 | 30 | // ValidColumn reports if the column name is valid (part of the table columns). 31 | func ValidColumn(column string) bool { 32 | for i := range Columns { 33 | if column == Columns[i] { 34 | return true 35 | } 36 | } 37 | return false 38 | } 39 | 40 | var ( 41 | // NameValidator is a validator for the "name" field. It is called by the builders before save. 42 | NameValidator func(string) error 43 | // DefaultID holds the default value on creation for the "id" field. 44 | DefaultID func() uuid.UUID 45 | ) 46 | 47 | // OrderOption defines the ordering options for the TestSkip queries. 48 | type OrderOption func(*sql.Selector) 49 | 50 | // ByID orders the results by the id field. 51 | func ByID(opts ...sql.OrderTermOption) OrderOption { 52 | return sql.OrderByField(FieldID, opts...).ToFunc() 53 | } 54 | 55 | // ByOtherID orders the results by the other_id field. 56 | func ByOtherID(opts ...sql.OrderTermOption) OrderOption { 57 | return sql.OrderByField(FieldOtherID, opts...).ToFunc() 58 | } 59 | 60 | // ByName orders the results by the name field. 61 | func ByName(opts ...sql.OrderTermOption) OrderOption { 62 | return sql.OrderByField(FieldName, opts...).ToFunc() 63 | } 64 | -------------------------------------------------------------------------------- /_examples/graphql/ent/testskip_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/graphql/ent/predicate" 7 | "_examples/graphql/ent/testskip" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // TestSkipDelete is the builder for deleting a TestSkip entity. 16 | type TestSkipDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *TestSkipMutation 20 | } 21 | 22 | // Where appends a list predicates to the TestSkipDelete builder. 23 | func (tsd *TestSkipDelete) Where(ps ...predicate.TestSkip) *TestSkipDelete { 24 | tsd.mutation.Where(ps...) 25 | return tsd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (tsd *TestSkipDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, tsd.sqlExec, tsd.mutation, tsd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (tsd *TestSkipDelete) ExecX(ctx context.Context) int { 35 | n, err := tsd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (tsd *TestSkipDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(testskip.Table, sqlgraph.NewFieldSpec(testskip.FieldID, field.TypeUUID)) 44 | if ps := tsd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, tsd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | tsd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // TestSkipDeleteOne is the builder for deleting a single TestSkip entity. 60 | type TestSkipDeleteOne struct { 61 | tsd *TestSkipDelete 62 | } 63 | 64 | // Where appends a list predicates to the TestSkipDelete builder. 65 | func (tsdo *TestSkipDeleteOne) Where(ps ...predicate.TestSkip) *TestSkipDeleteOne { 66 | tsdo.tsd.mutation.Where(ps...) 67 | return tsdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (tsdo *TestSkipDeleteOne) Exec(ctx context.Context) error { 72 | n, err := tsdo.tsd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{testskip.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (tsdo *TestSkipDeleteOne) ExecX(ctx context.Context) { 85 | if err := tsdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/graphql/ent/testskiphistory_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/graphql/ent/predicate" 7 | "_examples/graphql/ent/testskiphistory" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // TestSkipHistoryDelete is the builder for deleting a TestSkipHistory entity. 16 | type TestSkipHistoryDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *TestSkipHistoryMutation 20 | } 21 | 22 | // Where appends a list predicates to the TestSkipHistoryDelete builder. 23 | func (tshd *TestSkipHistoryDelete) Where(ps ...predicate.TestSkipHistory) *TestSkipHistoryDelete { 24 | tshd.mutation.Where(ps...) 25 | return tshd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (tshd *TestSkipHistoryDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, tshd.sqlExec, tshd.mutation, tshd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (tshd *TestSkipHistoryDelete) ExecX(ctx context.Context) int { 35 | n, err := tshd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (tshd *TestSkipHistoryDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(testskiphistory.Table, sqlgraph.NewFieldSpec(testskiphistory.FieldID, field.TypeUUID)) 44 | if ps := tshd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, tshd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | tshd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // TestSkipHistoryDeleteOne is the builder for deleting a single TestSkipHistory entity. 60 | type TestSkipHistoryDeleteOne struct { 61 | tshd *TestSkipHistoryDelete 62 | } 63 | 64 | // Where appends a list predicates to the TestSkipHistoryDelete builder. 65 | func (tshdo *TestSkipHistoryDeleteOne) Where(ps ...predicate.TestSkipHistory) *TestSkipHistoryDeleteOne { 66 | tshdo.tshd.mutation.Where(ps...) 67 | return tshdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (tshdo *TestSkipHistoryDeleteOne) Exec(ctx context.Context) error { 72 | n, err := tshdo.tshd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{testskiphistory.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (tshdo *TestSkipHistoryDeleteOne) ExecX(ctx context.Context) { 85 | if err := tshdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/graphql/ent/todo/todo.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package todo 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | "github.com/google/uuid" 8 | ) 9 | 10 | const ( 11 | // Label holds the string label denoting the todo type in the database. 12 | Label = "todo" 13 | // FieldID holds the string denoting the id field in the database. 14 | FieldID = "id" 15 | // FieldOtherID holds the string denoting the other_id field in the database. 16 | FieldOtherID = "other_id" 17 | // FieldName holds the string denoting the name field in the database. 18 | FieldName = "name" 19 | // Table holds the table name of the todo in the database. 20 | Table = "todos" 21 | ) 22 | 23 | // Columns holds all SQL columns for todo fields. 24 | var Columns = []string{ 25 | FieldID, 26 | FieldOtherID, 27 | FieldName, 28 | } 29 | 30 | // ValidColumn reports if the column name is valid (part of the table columns). 31 | func ValidColumn(column string) bool { 32 | for i := range Columns { 33 | if column == Columns[i] { 34 | return true 35 | } 36 | } 37 | return false 38 | } 39 | 40 | var ( 41 | // NameValidator is a validator for the "name" field. It is called by the builders before save. 42 | NameValidator func(string) error 43 | // DefaultID holds the default value on creation for the "id" field. 44 | DefaultID func() uuid.UUID 45 | ) 46 | 47 | // OrderOption defines the ordering options for the Todo queries. 48 | type OrderOption func(*sql.Selector) 49 | 50 | // ByID orders the results by the id field. 51 | func ByID(opts ...sql.OrderTermOption) OrderOption { 52 | return sql.OrderByField(FieldID, opts...).ToFunc() 53 | } 54 | 55 | // ByOtherID orders the results by the other_id field. 56 | func ByOtherID(opts ...sql.OrderTermOption) OrderOption { 57 | return sql.OrderByField(FieldOtherID, opts...).ToFunc() 58 | } 59 | 60 | // ByName orders the results by the name field. 61 | func ByName(opts ...sql.OrderTermOption) OrderOption { 62 | return sql.OrderByField(FieldName, opts...).ToFunc() 63 | } 64 | -------------------------------------------------------------------------------- /_examples/graphql/ent/todo_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/graphql/ent/predicate" 7 | "_examples/graphql/ent/todo" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // TodoDelete is the builder for deleting a Todo entity. 16 | type TodoDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *TodoMutation 20 | } 21 | 22 | // Where appends a list predicates to the TodoDelete builder. 23 | func (td *TodoDelete) Where(ps ...predicate.Todo) *TodoDelete { 24 | td.mutation.Where(ps...) 25 | return td 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (td *TodoDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, td.sqlExec, td.mutation, td.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (td *TodoDelete) ExecX(ctx context.Context) int { 35 | n, err := td.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (td *TodoDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(todo.Table, sqlgraph.NewFieldSpec(todo.FieldID, field.TypeUUID)) 44 | if ps := td.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, td.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | td.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // TodoDeleteOne is the builder for deleting a single Todo entity. 60 | type TodoDeleteOne struct { 61 | td *TodoDelete 62 | } 63 | 64 | // Where appends a list predicates to the TodoDelete builder. 65 | func (tdo *TodoDeleteOne) Where(ps ...predicate.Todo) *TodoDeleteOne { 66 | tdo.td.mutation.Where(ps...) 67 | return tdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (tdo *TodoDeleteOne) Exec(ctx context.Context) error { 72 | n, err := tdo.td.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{todo.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (tdo *TodoDeleteOne) ExecX(ctx context.Context) { 85 | if err := tdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/graphql/ent/todohistory_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/graphql/ent/predicate" 7 | "_examples/graphql/ent/todohistory" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // TodoHistoryDelete is the builder for deleting a TodoHistory entity. 16 | type TodoHistoryDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *TodoHistoryMutation 20 | } 21 | 22 | // Where appends a list predicates to the TodoHistoryDelete builder. 23 | func (thd *TodoHistoryDelete) Where(ps ...predicate.TodoHistory) *TodoHistoryDelete { 24 | thd.mutation.Where(ps...) 25 | return thd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (thd *TodoHistoryDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, thd.sqlExec, thd.mutation, thd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (thd *TodoHistoryDelete) ExecX(ctx context.Context) int { 35 | n, err := thd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (thd *TodoHistoryDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(todohistory.Table, sqlgraph.NewFieldSpec(todohistory.FieldID, field.TypeUUID)) 44 | if ps := thd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, thd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | thd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // TodoHistoryDeleteOne is the builder for deleting a single TodoHistory entity. 60 | type TodoHistoryDeleteOne struct { 61 | thd *TodoHistoryDelete 62 | } 63 | 64 | // Where appends a list predicates to the TodoHistoryDelete builder. 65 | func (thdo *TodoHistoryDeleteOne) Where(ps ...predicate.TodoHistory) *TodoHistoryDeleteOne { 66 | thdo.thd.mutation.Where(ps...) 67 | return thdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (thdo *TodoHistoryDeleteOne) Exec(ctx context.Context) error { 72 | n, err := thdo.thd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{todohistory.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (thdo *TodoHistoryDeleteOne) ExecX(ctx context.Context) { 85 | if err := thdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/graphql/generate.go: -------------------------------------------------------------------------------- 1 | package graphql 2 | 3 | //go:generate go run ./ent/entc.go 4 | //go:generate go run github.com/99designs/gqlgen 5 | -------------------------------------------------------------------------------- /_examples/graphql/gqlgen.yml: -------------------------------------------------------------------------------- 1 | # schema tells gqlgen where the GraphQL schema is located. 2 | schema: [graphql/query.graphql] 3 | # doing this to keep gqlgen happy with go workspaces 4 | skip_validation: true 5 | exec: 6 | filename: graphql/resolver/generated.go 7 | package: resolver 8 | # resolver reports where the resolver implementations go. 9 | resolver: 10 | layout: follow-schema 11 | dir: graphql/resolver 12 | # gqlgen will search for any type names in the schema in these go packages 13 | # if they match it will use them, otherwise it will generate them. 14 | # autobind tells gqngen to search for any type names in the GraphQL schema in the 15 | # provided package. If they match it will use them, otherwise it will generate new. 16 | model: 17 | filename: graphql/type_gen.go 18 | package: graphql 19 | autobind: 20 | - _examples/graphql/ent 21 | omit_getters: true 22 | # This section declares type mapping between the GraphQL and Go type systems. 23 | models: 24 | # Defines the ID field as Go 'int'. 25 | ID: 26 | model: [_examples/graphql/ent/schema/uuidgql.UUID] 27 | Node: 28 | model: [_examples/graphql/ent.Noder] 29 | -------------------------------------------------------------------------------- /_examples/graphql/graphql/resolver/query.resolvers.go: -------------------------------------------------------------------------------- 1 | package resolver 2 | 3 | // This file will be automatically regenerated based on the schema, any resolver implementations 4 | // will be copied through when generating and any unknown code will be moved to the end. 5 | // Code generated by github.com/99designs/gqlgen version v0.17.70 6 | 7 | import ( 8 | "_examples/graphql/ent" 9 | "context" 10 | "fmt" 11 | 12 | "entgo.io/contrib/entgql" 13 | "github.com/google/uuid" 14 | ) 15 | 16 | // Node is the resolver for the node field. 17 | func (r *queryResolver) Node(ctx context.Context, id uuid.UUID) (ent.Noder, error) { 18 | panic(fmt.Errorf("not implemented: Node - node")) 19 | } 20 | 21 | // Nodes is the resolver for the nodes field. 22 | func (r *queryResolver) Nodes(ctx context.Context, ids []uuid.UUID) ([]ent.Noder, error) { 23 | panic(fmt.Errorf("not implemented: Nodes - nodes")) 24 | } 25 | 26 | // Todos is the resolver for the todos field. 27 | func (r *queryResolver) Todos(ctx context.Context, after *entgql.Cursor[uuid.UUID], first *int, before *entgql.Cursor[uuid.UUID], last *int, orderBy *ent.TodoOrder, where *ent.TodoWhereInput) (*ent.TodoConnection, error) { 28 | panic(fmt.Errorf("not implemented: Todos - todos")) 29 | } 30 | 31 | // TodoHistories is the resolver for the todoHistories field. 32 | func (r *queryResolver) TodoHistories(ctx context.Context, after *entgql.Cursor[uuid.UUID], first *int, before *entgql.Cursor[uuid.UUID], last *int, orderBy *ent.TodoHistoryOrder, where *ent.TodoHistoryWhereInput) (*ent.TodoHistoryConnection, error) { 33 | panic(fmt.Errorf("not implemented: TodoHistories - todoHistories")) 34 | } 35 | 36 | // Query returns QueryResolver implementation. 37 | func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } 38 | 39 | type queryResolver struct{ *Resolver } 40 | -------------------------------------------------------------------------------- /_examples/graphql/graphql/resolver/resolver.go: -------------------------------------------------------------------------------- 1 | package resolver 2 | 3 | // This file will not be regenerated automatically. 4 | // 5 | // It serves as dependency injection for your app, add any dependencies you require here. 6 | 7 | type Resolver struct{} 8 | -------------------------------------------------------------------------------- /_examples/testdata/debug/entc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "_examples/testdata/debug/schema" 5 | "fmt" 6 | "log" 7 | 8 | "entgo.io/ent/entc" 9 | "entgo.io/ent/entc/gen" 10 | 11 | "entgo.io/ent" 12 | 13 | "github.com/flume/enthistory" 14 | ) 15 | 16 | const ( 17 | schemaPath = "./testdata/debug/schema" 18 | ) 19 | 20 | func main() { 21 | if err := enthistory.Generate(schemaPath, []ent.Interface{ 22 | &schema.Character{}, 23 | &schema.Friendship{}, 24 | }, 25 | enthistory.WithInheritIdType(), 26 | enthistory.WithHistoryTimeIndex(), 27 | enthistory.WithUpdatedBy("userid", enthistory.ValueTypeUUID), 28 | enthistory.WithImmutableFields(), 29 | enthistory.WithNillableFields(), 30 | enthistory.WithTriggers(enthistory.OpTypeInsert), 31 | ); err != nil { 32 | log.Fatal(fmt.Sprintf("running enthistory codegen: %v", err)) 33 | } 34 | 35 | if err := entc.Generate(schemaPath, 36 | &gen.Config{ 37 | Target: "./testdata/debug/internal/ent", 38 | Schema: "_examples/testdata/debug/schema", 39 | Package: "_examples/testdata/debug/internal/ent", 40 | }, 41 | entc.Extensions( 42 | enthistory.NewHistoryExtension(enthistory.WithAuditing()), 43 | ), 44 | ); err != nil { 45 | log.Fatal("running ent codegen:", err) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /_examples/testdata/debug/internal/ent/character_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/testdata/debug/internal/ent/character" 7 | "_examples/testdata/debug/internal/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // CharacterDelete is the builder for deleting a Character entity. 16 | type CharacterDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *CharacterMutation 20 | } 21 | 22 | // Where appends a list predicates to the CharacterDelete builder. 23 | func (cd *CharacterDelete) Where(ps ...predicate.Character) *CharacterDelete { 24 | cd.mutation.Where(ps...) 25 | return cd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (cd *CharacterDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, cd.sqlExec, cd.mutation, cd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (cd *CharacterDelete) ExecX(ctx context.Context) int { 35 | n, err := cd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (cd *CharacterDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(character.Table, sqlgraph.NewFieldSpec(character.FieldID, field.TypeUUID)) 44 | if ps := cd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, cd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | cd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // CharacterDeleteOne is the builder for deleting a single Character entity. 60 | type CharacterDeleteOne struct { 61 | cd *CharacterDelete 62 | } 63 | 64 | // Where appends a list predicates to the CharacterDelete builder. 65 | func (cdo *CharacterDeleteOne) Where(ps ...predicate.Character) *CharacterDeleteOne { 66 | cdo.cd.mutation.Where(ps...) 67 | return cdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (cdo *CharacterDeleteOne) Exec(ctx context.Context) error { 72 | n, err := cdo.cd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{character.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (cdo *CharacterDeleteOne) ExecX(ctx context.Context) { 85 | if err := cdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/testdata/debug/internal/ent/enttest/enttest.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package enttest 4 | 5 | import ( 6 | "context" 7 | 8 | "_examples/testdata/debug/internal/ent" 9 | // required by schema hooks. 10 | _ "_examples/testdata/debug/internal/ent/runtime" 11 | 12 | "_examples/testdata/debug/internal/ent/migrate" 13 | 14 | "entgo.io/ent/dialect/sql/schema" 15 | ) 16 | 17 | type ( 18 | // TestingT is the interface that is shared between 19 | // testing.T and testing.B and used by enttest. 20 | TestingT interface { 21 | FailNow() 22 | Error(...any) 23 | } 24 | 25 | // Option configures client creation. 26 | Option func(*options) 27 | 28 | options struct { 29 | opts []ent.Option 30 | migrateOpts []schema.MigrateOption 31 | } 32 | ) 33 | 34 | // WithOptions forwards options to client creation. 35 | func WithOptions(opts ...ent.Option) Option { 36 | return func(o *options) { 37 | o.opts = append(o.opts, opts...) 38 | } 39 | } 40 | 41 | // WithMigrateOptions forwards options to auto migration. 42 | func WithMigrateOptions(opts ...schema.MigrateOption) Option { 43 | return func(o *options) { 44 | o.migrateOpts = append(o.migrateOpts, opts...) 45 | } 46 | } 47 | 48 | func newOptions(opts []Option) *options { 49 | o := &options{} 50 | for _, opt := range opts { 51 | opt(o) 52 | } 53 | return o 54 | } 55 | 56 | // Open calls ent.Open and auto-run migration. 57 | func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { 58 | o := newOptions(opts) 59 | c, err := ent.Open(driverName, dataSourceName, o.opts...) 60 | if err != nil { 61 | t.Error(err) 62 | t.FailNow() 63 | } 64 | migrateSchema(t, c, o) 65 | return c 66 | } 67 | 68 | // NewClient calls ent.NewClient and auto-run migration. 69 | func NewClient(t TestingT, opts ...Option) *ent.Client { 70 | o := newOptions(opts) 71 | c := ent.NewClient(o.opts...) 72 | migrateSchema(t, c, o) 73 | return c 74 | } 75 | func migrateSchema(t TestingT, c *ent.Client, o *options) { 76 | tables, err := schema.CopyTables(migrate.Tables) 77 | if err != nil { 78 | t.Error(err) 79 | t.FailNow() 80 | } 81 | if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { 82 | t.Error(err) 83 | t.FailNow() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /_examples/testdata/debug/internal/ent/friendship_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/testdata/debug/internal/ent/friendship" 7 | "_examples/testdata/debug/internal/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // FriendshipDelete is the builder for deleting a Friendship entity. 16 | type FriendshipDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *FriendshipMutation 20 | } 21 | 22 | // Where appends a list predicates to the FriendshipDelete builder. 23 | func (fd *FriendshipDelete) Where(ps ...predicate.Friendship) *FriendshipDelete { 24 | fd.mutation.Where(ps...) 25 | return fd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (fd *FriendshipDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, fd.sqlExec, fd.mutation, fd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (fd *FriendshipDelete) ExecX(ctx context.Context) int { 35 | n, err := fd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (fd *FriendshipDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(friendship.Table, sqlgraph.NewFieldSpec(friendship.FieldID, field.TypeUUID)) 44 | if ps := fd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, fd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | fd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // FriendshipDeleteOne is the builder for deleting a single Friendship entity. 60 | type FriendshipDeleteOne struct { 61 | fd *FriendshipDelete 62 | } 63 | 64 | // Where appends a list predicates to the FriendshipDelete builder. 65 | func (fdo *FriendshipDeleteOne) Where(ps ...predicate.Friendship) *FriendshipDeleteOne { 66 | fdo.fd.mutation.Where(ps...) 67 | return fdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (fdo *FriendshipDeleteOne) Exec(ctx context.Context) error { 72 | n, err := fdo.fd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{friendship.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (fdo *FriendshipDeleteOne) ExecX(ctx context.Context) { 85 | if err := fdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/testdata/debug/internal/ent/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io" 9 | 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | var ( 15 | // WithGlobalUniqueID sets the universal ids options to the migration. 16 | // If this option is enabled, ent migration will allocate a 1<<32 range 17 | // for the ids of each entity (table). 18 | // Note that this option cannot be applied on tables that already exist. 19 | WithGlobalUniqueID = schema.WithGlobalUniqueID 20 | // WithDropColumn sets the drop column option to the migration. 21 | // If this option is enabled, ent migration will drop old columns 22 | // that were used for both fields and edges. This defaults to false. 23 | WithDropColumn = schema.WithDropColumn 24 | // WithDropIndex sets the drop index option to the migration. 25 | // If this option is enabled, ent migration will drop old indexes 26 | // that were defined in the schema. This defaults to false. 27 | // Note that unique constraints are defined using `UNIQUE INDEX`, 28 | // and therefore, it's recommended to enable this option to get more 29 | // flexibility in the schema changes. 30 | WithDropIndex = schema.WithDropIndex 31 | // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. 32 | WithForeignKeys = schema.WithForeignKeys 33 | ) 34 | 35 | // Schema is the API for creating, migrating and dropping a schema. 36 | type Schema struct { 37 | drv dialect.Driver 38 | } 39 | 40 | // NewSchema creates a new schema client. 41 | func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } 42 | 43 | // Create creates all schema resources. 44 | func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { 45 | return Create(ctx, s, Tables, opts...) 46 | } 47 | 48 | // Create creates all table resources using the given schema driver. 49 | func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error { 50 | migrate, err := schema.NewMigrate(s.drv, opts...) 51 | if err != nil { 52 | return fmt.Errorf("ent/migrate: %w", err) 53 | } 54 | return migrate.Create(ctx, tables...) 55 | } 56 | 57 | // WriteTo writes the schema changes to w instead of running them against the database. 58 | // 59 | // if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { 60 | // log.Fatal(err) 61 | // } 62 | func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { 63 | return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...) 64 | } 65 | -------------------------------------------------------------------------------- /_examples/testdata/debug/internal/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // Character is the predicate function for character builders. 10 | type Character func(*sql.Selector) 11 | 12 | // CharacterHistory is the predicate function for characterhistory builders. 13 | type CharacterHistory func(*sql.Selector) 14 | 15 | // Friendship is the predicate function for friendship builders. 16 | type Friendship func(*sql.Selector) 17 | 18 | // FriendshipHistory is the predicate function for friendshiphistory builders. 19 | type FriendshipHistory func(*sql.Selector) 20 | -------------------------------------------------------------------------------- /_examples/testdata/debug/internal/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in _examples/testdata/debug/internal/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.14.4" // Version of ent codegen. 9 | Sum = "h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /_examples/testdata/debug/models/models.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Uint64 uint64 4 | 5 | func DefaultUint64() Uint64 { 6 | return 0 7 | } 8 | 9 | type InfoStruct struct { 10 | FirstAppearance string `json:"firstAppearance"` 11 | LastAppearance string `json:"lastAppearance"` 12 | } 13 | 14 | func DefaultInfoStruct() InfoStruct { 15 | return InfoStruct{ 16 | FirstAppearance: "UNKNOWN", 17 | LastAppearance: "UNKNOWN", 18 | } 19 | } 20 | 21 | type SpeciesType string 22 | 23 | const ( 24 | SpeciesTypeHuman SpeciesType = "HUMAN" 25 | SpeciesTypeDog SpeciesType = "DOG" 26 | SpeciesTypePenguin SpeciesType = "PENGUIN" 27 | SpeciesTypeVampire SpeciesType = "VAMPIRE" 28 | SpeciesTypeUnknown SpeciesType = "UNKNOWN" 29 | ) 30 | 31 | func (e SpeciesType) String() string { 32 | return string(e) 33 | } 34 | 35 | func DefaultSpeciesType() SpeciesType { 36 | return SpeciesTypeUnknown 37 | } 38 | -------------------------------------------------------------------------------- /_examples/testdata/debug/schema/character.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "_examples/testdata/debug/models" 5 | "_examples/testdata/debug/schema/mixins" 6 | 7 | "github.com/flume/enthistory" 8 | 9 | "entgo.io/contrib/entgql" 10 | 11 | "entgo.io/ent" 12 | "entgo.io/ent/dialect/entsql" 13 | "entgo.io/ent/schema" 14 | "entgo.io/ent/schema/edge" 15 | "entgo.io/ent/schema/field" 16 | "github.com/google/uuid" 17 | ) 18 | 19 | // Character holds the schema definition for the Character entity. 20 | type Character struct { 21 | ent.Schema 22 | } 23 | 24 | // Annotations of the Character. 25 | func (Character) Annotations() []schema.Annotation { 26 | return []schema.Annotation{ 27 | entsql.Annotation{ 28 | Table: "character", 29 | }, 30 | enthistory.Annotations{ 31 | Mixins: []ent.Mixin{mixins.TimeMixin{}}, 32 | Annotations: []schema.Annotation{ 33 | entsql.Annotation{Table: "character_history"}, 34 | }, 35 | Triggers: []enthistory.OpType{enthistory.OpTypeUpdate}, 36 | }, 37 | } 38 | } 39 | 40 | // Fields of the Character. 41 | func (Character) Fields() []ent.Field { 42 | return []ent.Field{ 43 | field.UUID("id", uuid.New()).Default(uuid.New).Annotations(entgql.Annotation{Type: "ID"}), 44 | field.Int("age"). 45 | Positive(), 46 | field.Uint64("typed_age"). 47 | Positive(). 48 | GoType(models.Uint64(0)). 49 | DefaultFunc(models.DefaultUint64), 50 | field.String("name"), 51 | field.Strings("nicknames"). 52 | Optional(), 53 | field.JSON("info", map[string]any{}). 54 | Optional(), 55 | field.JSON("info_struct", models.InfoStruct{}). 56 | Optional(). 57 | Default(models.DefaultInfoStruct), 58 | field.String("species"). 59 | Optional(). 60 | GoType(models.SpeciesType("")). 61 | DefaultFunc(models.DefaultSpeciesType), 62 | } 63 | } 64 | 65 | // Edges of the Character. 66 | func (Character) Edges() []ent.Edge { 67 | return []ent.Edge{ 68 | edge.To("friends", Character.Type). 69 | Through("friendships", Friendship.Type), 70 | } 71 | } 72 | 73 | func (Character) Mixin() []ent.Mixin { 74 | return []ent.Mixin{ 75 | mixins.TimeMixin{}, 76 | OtherMixin{}, 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /_examples/testdata/debug/schema/character_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "_examples/testdata/debug/models" 7 | "_examples/testdata/debug/schema/mixins" 8 | "time" 9 | 10 | "entgo.io/contrib/entgql" 11 | "entgo.io/ent" 12 | "entgo.io/ent/dialect/entsql" 13 | "entgo.io/ent/schema" 14 | "entgo.io/ent/schema/field" 15 | "entgo.io/ent/schema/index" 16 | "github.com/google/uuid" 17 | 18 | "github.com/flume/enthistory" 19 | ) 20 | 21 | type CharacterHistory struct { 22 | ent.Schema 23 | } 24 | 25 | func (CharacterHistory) Fields() []ent.Field { 26 | return []ent.Field{ 27 | field.UUID("id", uuid.UUID{}). 28 | Annotations(entgql.Annotation{Type: "ID"}). 29 | Default(uuid.New), 30 | field.Time("history_time"). 31 | Immutable(). 32 | Default(time.Now), 33 | field.Enum("operation"). 34 | Immutable(). 35 | GoType(enthistory.OpType("")), 36 | field.UUID("ref", uuid.UUID{}). 37 | Optional(). 38 | Immutable(). 39 | Annotations(entgql.Annotation{Type: "ID"}), 40 | field.UUID("updated_by", uuid.UUID{}). 41 | Nillable(). 42 | Optional(). 43 | Immutable(). 44 | Annotations(entgql.Annotation{Type: "ID"}), 45 | field.Int("age"). 46 | Nillable(). 47 | Optional(). 48 | Immutable(), 49 | field.Uint64("typed_age"). 50 | GoType(models.Uint64(0)). 51 | Nillable(). 52 | Optional(). 53 | Immutable(). 54 | DefaultFunc(models.DefaultUint64), 55 | field.String("name"). 56 | Nillable(). 57 | Optional(). 58 | Immutable(), 59 | field.JSON("nicknames", []string{}). 60 | Optional(). 61 | Immutable(), 62 | field.JSON("info", map[string]any{}). 63 | Optional(). 64 | Immutable(), 65 | field.JSON("info_struct", models. 66 | InfoStruct{}). 67 | Optional(). 68 | Immutable(). 69 | Default(models.DefaultInfoStruct), 70 | field.String("species"). 71 | GoType(models.SpeciesType("")). 72 | Nillable(). 73 | Optional(). 74 | Immutable(). 75 | DefaultFunc(models.DefaultSpeciesType)} 76 | 77 | } 78 | func (CharacterHistory) Edges() []ent.Edge { 79 | return nil 80 | } 81 | func (CharacterHistory) Annotations() []schema.Annotation { 82 | return []schema.Annotation{entsql.Annotation{Table: "character_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeUpdate}}} 83 | } 84 | func (CharacterHistory) Mixin() []ent.Mixin { 85 | return []ent.Mixin{mixins.TimeMixin{}} 86 | } 87 | func (CharacterHistory) Indexes() []ent.Index { 88 | return []ent.Index{index.Fields("history_time")} 89 | } 90 | -------------------------------------------------------------------------------- /_examples/testdata/debug/schema/friendship.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/edge" 8 | "entgo.io/ent/schema/field" 9 | "github.com/google/uuid" 10 | ) 11 | 12 | // Friendship holds the schema definition for the Friendship entity. 13 | type Friendship struct { 14 | ent.Schema 15 | } 16 | 17 | // Annotations of the Friendship. 18 | func (Friendship) Annotations() []schema.Annotation { 19 | return []schema.Annotation{ 20 | entsql.Annotation{ 21 | Table: "friendship", 22 | }, 23 | } 24 | } 25 | 26 | // Fields of the Friendship. 27 | func (Friendship) Fields() []ent.Field { 28 | return []ent.Field{ 29 | field.UUID("id", uuid.New()).Default(uuid.New), 30 | field.UUID("character_id", uuid.New()), 31 | field.UUID("friend_id", uuid.New()), 32 | } 33 | } 34 | 35 | // Edges of the Friendship. 36 | func (Friendship) Edges() []ent.Edge { 37 | return []ent.Edge{ 38 | edge.To("character", Character.Type). 39 | Required(). 40 | Unique(). 41 | Field("character_id"), 42 | edge.To("friend", Character.Type). 43 | Required(). 44 | Unique(). 45 | Field("friend_id"), 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /_examples/testdata/debug/schema/friendship_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "time" 7 | 8 | "entgo.io/ent" 9 | "entgo.io/ent/dialect/entsql" 10 | "entgo.io/ent/schema" 11 | "entgo.io/ent/schema/field" 12 | "entgo.io/ent/schema/index" 13 | "github.com/google/uuid" 14 | 15 | "github.com/flume/enthistory" 16 | ) 17 | 18 | type FriendshipHistory struct { 19 | ent.Schema 20 | } 21 | 22 | func (FriendshipHistory) Fields() []ent.Field { 23 | return []ent.Field{ 24 | field.UUID("id", uuid.UUID{}). 25 | Default(uuid.New), 26 | field.Time("history_time"). 27 | Immutable(). 28 | Default(time.Now), 29 | field.Enum("operation"). 30 | Immutable(). 31 | GoType(enthistory.OpType("")), 32 | field.UUID("ref", uuid.UUID{}). 33 | Optional(). 34 | Immutable(), 35 | field.UUID("updated_by", uuid.UUID{}). 36 | Nillable(). 37 | Optional(). 38 | Immutable(), 39 | field.UUID("character_id", uuid.UUID{}). 40 | Nillable(). 41 | Optional(). 42 | Immutable(), 43 | field.UUID("friend_id", uuid.UUID{}). 44 | Nillable(). 45 | Optional(). 46 | Immutable()} 47 | } 48 | func (FriendshipHistory) Edges() []ent.Edge { 49 | return nil 50 | } 51 | func (FriendshipHistory) Annotations() []schema.Annotation { 52 | return []schema.Annotation{entsql.Annotation{Table: "friendship_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert}}} 53 | } 54 | func (FriendshipHistory) Indexes() []ent.Index { 55 | return []ent.Index{index.Fields("history_time")} 56 | } 57 | -------------------------------------------------------------------------------- /_examples/testdata/debug/schema/mixins/timemixin.go: -------------------------------------------------------------------------------- 1 | package mixins 2 | 3 | import ( 4 | "time" 5 | 6 | "entgo.io/ent" 7 | "entgo.io/ent/schema/field" 8 | "entgo.io/ent/schema/mixin" 9 | ) 10 | 11 | type TimeMixin struct { 12 | mixin.Schema 13 | } 14 | 15 | func (TimeMixin) Fields() []ent.Field { 16 | return []ent.Field{ 17 | field.Time("created_at"). 18 | Immutable(). 19 | Default(time.Now), 20 | field.Time("updated_at"). 21 | UpdateDefault(time.Now), 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /_examples/testdata/debug/schema/othermixin.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/schema/field" 6 | "entgo.io/ent/schema/mixin" 7 | ) 8 | 9 | type OtherMixin struct { 10 | mixin.Schema 11 | } 12 | 13 | func (OtherMixin) Fields() []ent.Field { 14 | return []ent.Field{ 15 | field.String("other"), 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/entc.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "_examples/updateby_uuid/ent/schema" 7 | "fmt" 8 | "log" 9 | 10 | "entgo.io/ent" 11 | 12 | "entgo.io/ent/entc/gen" 13 | 14 | "github.com/flume/enthistory" 15 | 16 | "entgo.io/ent/entc" 17 | ) 18 | 19 | func main() { 20 | if err := enthistory.Generate("./schema", []ent.Interface{ 21 | schema.Organization{}, 22 | schema.Store{}, 23 | }, 24 | enthistory.WithUpdatedBy("userId", enthistory.ValueTypeUUID), 25 | enthistory.WithHistoryTimeIndex(), 26 | ); err != nil { 27 | log.Fatal(fmt.Sprintf("running enthistory codegen: %v", err)) 28 | } 29 | 30 | if err := entc.Generate("./schema", 31 | &gen.Config{}, 32 | entc.Extensions( 33 | enthistory.NewHistoryExtension(enthistory.WithAuditing()), 34 | ), 35 | ); err != nil { 36 | log.Fatal("running ent codegen:", err) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/enttest/enttest.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package enttest 4 | 5 | import ( 6 | "context" 7 | 8 | "_examples/updateby_uuid/ent" 9 | // required by schema hooks. 10 | _ "_examples/updateby_uuid/ent/runtime" 11 | 12 | "_examples/updateby_uuid/ent/migrate" 13 | 14 | "entgo.io/ent/dialect/sql/schema" 15 | ) 16 | 17 | type ( 18 | // TestingT is the interface that is shared between 19 | // testing.T and testing.B and used by enttest. 20 | TestingT interface { 21 | FailNow() 22 | Error(...any) 23 | } 24 | 25 | // Option configures client creation. 26 | Option func(*options) 27 | 28 | options struct { 29 | opts []ent.Option 30 | migrateOpts []schema.MigrateOption 31 | } 32 | ) 33 | 34 | // WithOptions forwards options to client creation. 35 | func WithOptions(opts ...ent.Option) Option { 36 | return func(o *options) { 37 | o.opts = append(o.opts, opts...) 38 | } 39 | } 40 | 41 | // WithMigrateOptions forwards options to auto migration. 42 | func WithMigrateOptions(opts ...schema.MigrateOption) Option { 43 | return func(o *options) { 44 | o.migrateOpts = append(o.migrateOpts, opts...) 45 | } 46 | } 47 | 48 | func newOptions(opts []Option) *options { 49 | o := &options{} 50 | for _, opt := range opts { 51 | opt(o) 52 | } 53 | return o 54 | } 55 | 56 | // Open calls ent.Open and auto-run migration. 57 | func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { 58 | o := newOptions(opts) 59 | c, err := ent.Open(driverName, dataSourceName, o.opts...) 60 | if err != nil { 61 | t.Error(err) 62 | t.FailNow() 63 | } 64 | migrateSchema(t, c, o) 65 | return c 66 | } 67 | 68 | // NewClient calls ent.NewClient and auto-run migration. 69 | func NewClient(t TestingT, opts ...Option) *ent.Client { 70 | o := newOptions(opts) 71 | c := ent.NewClient(o.opts...) 72 | migrateSchema(t, c, o) 73 | return c 74 | } 75 | func migrateSchema(t TestingT, c *ent.Client, o *options) { 76 | tables, err := schema.CopyTables(migrate.Tables) 77 | if err != nil { 78 | t.Error(err) 79 | t.FailNow() 80 | } 81 | if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { 82 | t.Error(err) 83 | t.FailNow() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/generate.go: -------------------------------------------------------------------------------- 1 | package ent 2 | 3 | //go:generate go run entc.go 4 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io" 9 | 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | var ( 15 | // WithGlobalUniqueID sets the universal ids options to the migration. 16 | // If this option is enabled, ent migration will allocate a 1<<32 range 17 | // for the ids of each entity (table). 18 | // Note that this option cannot be applied on tables that already exist. 19 | WithGlobalUniqueID = schema.WithGlobalUniqueID 20 | // WithDropColumn sets the drop column option to the migration. 21 | // If this option is enabled, ent migration will drop old columns 22 | // that were used for both fields and edges. This defaults to false. 23 | WithDropColumn = schema.WithDropColumn 24 | // WithDropIndex sets the drop index option to the migration. 25 | // If this option is enabled, ent migration will drop old indexes 26 | // that were defined in the schema. This defaults to false. 27 | // Note that unique constraints are defined using `UNIQUE INDEX`, 28 | // and therefore, it's recommended to enable this option to get more 29 | // flexibility in the schema changes. 30 | WithDropIndex = schema.WithDropIndex 31 | // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. 32 | WithForeignKeys = schema.WithForeignKeys 33 | ) 34 | 35 | // Schema is the API for creating, migrating and dropping a schema. 36 | type Schema struct { 37 | drv dialect.Driver 38 | } 39 | 40 | // NewSchema creates a new schema client. 41 | func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } 42 | 43 | // Create creates all schema resources. 44 | func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { 45 | return Create(ctx, s, Tables, opts...) 46 | } 47 | 48 | // Create creates all table resources using the given schema driver. 49 | func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error { 50 | migrate, err := schema.NewMigrate(s.drv, opts...) 51 | if err != nil { 52 | return fmt.Errorf("ent/migrate: %w", err) 53 | } 54 | return migrate.Create(ctx, tables...) 55 | } 56 | 57 | // WriteTo writes the schema changes to w instead of running them against the database. 58 | // 59 | // if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { 60 | // log.Fatal(err) 61 | // } 62 | func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { 63 | return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...) 64 | } 65 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/organization_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/updateby_uuid/ent/organization" 7 | "_examples/updateby_uuid/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // OrganizationDelete is the builder for deleting a Organization entity. 16 | type OrganizationDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *OrganizationMutation 20 | } 21 | 22 | // Where appends a list predicates to the OrganizationDelete builder. 23 | func (od *OrganizationDelete) Where(ps ...predicate.Organization) *OrganizationDelete { 24 | od.mutation.Where(ps...) 25 | return od 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (od *OrganizationDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, od.sqlExec, od.mutation, od.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (od *OrganizationDelete) ExecX(ctx context.Context) int { 35 | n, err := od.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (od *OrganizationDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(organization.Table, sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID)) 44 | if ps := od.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, od.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | od.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // OrganizationDeleteOne is the builder for deleting a single Organization entity. 60 | type OrganizationDeleteOne struct { 61 | od *OrganizationDelete 62 | } 63 | 64 | // Where appends a list predicates to the OrganizationDelete builder. 65 | func (odo *OrganizationDeleteOne) Where(ps ...predicate.Organization) *OrganizationDeleteOne { 66 | odo.od.mutation.Where(ps...) 67 | return odo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (odo *OrganizationDeleteOne) Exec(ctx context.Context) error { 72 | n, err := odo.od.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{organization.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (odo *OrganizationDeleteOne) ExecX(ctx context.Context) { 85 | if err := odo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // Organization is the predicate function for organization builders. 10 | type Organization func(*sql.Selector) 11 | 12 | // OrganizationHistory is the predicate function for organizationhistory builders. 13 | type OrganizationHistory func(*sql.Selector) 14 | 15 | // Store is the predicate function for store builders. 16 | type Store func(*sql.Selector) 17 | 18 | // StoreHistory is the predicate function for storehistory builders. 19 | type StoreHistory func(*sql.Selector) 20 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in _examples/updateby_uuid/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.14.4" // Version of ent codegen. 9 | Sum = "h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/schema/mixins/timemixin.go: -------------------------------------------------------------------------------- 1 | package mixins 2 | 3 | import ( 4 | "time" 5 | 6 | "entgo.io/ent" 7 | "entgo.io/ent/schema/field" 8 | "entgo.io/ent/schema/mixin" 9 | ) 10 | 11 | type TimeMixin struct { 12 | mixin.Schema 13 | } 14 | 15 | func (TimeMixin) Fields() []ent.Field { 16 | return []ent.Field{ 17 | field.Time("created_at"). 18 | Immutable(). 19 | Default(time.Now), 20 | field.Time("updated_at"). 21 | Default(time.Now). 22 | UpdateDefault(time.Now), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/schema/organization.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/edge" 8 | "entgo.io/ent/schema/field" 9 | 10 | "github.com/google/uuid" 11 | 12 | "_examples/basic/ent/schema/mixins" 13 | ) 14 | 15 | // Organization holds the schema definition for the Organization entity. 16 | type Organization struct { 17 | ent.Schema 18 | } 19 | 20 | // Annotations of the Organization. 21 | func (Organization) Annotations() []schema.Annotation { 22 | return []schema.Annotation{ 23 | entsql.Annotation{ 24 | Table: "organization", 25 | }, 26 | } 27 | } 28 | 29 | // Fields of the Organization. 30 | func (Organization) Fields() []ent.Field { 31 | return []ent.Field{ 32 | field.UUID("id", uuid.UUID{}). 33 | Default(uuid.New), 34 | field.String("name"), 35 | field.JSON("info", map[string]any{}). 36 | Optional(), 37 | } 38 | } 39 | 40 | // Edges of the Organization. 41 | func (Organization) Edges() []ent.Edge { 42 | return []ent.Edge{ 43 | edge.To("organization_stores", Store.Type). 44 | Annotations(entsql.Annotation{ 45 | OnDelete: entsql.Cascade, 46 | }), 47 | } 48 | } 49 | 50 | // Mixin of the Organization. 51 | func (Organization) Mixin() []ent.Mixin { 52 | return []ent.Mixin{ 53 | mixins.TimeMixin{}, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/schema/organization_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "_examples/basic/ent/schema/mixins" 7 | "time" 8 | 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect/entsql" 11 | "entgo.io/ent/schema" 12 | "entgo.io/ent/schema/field" 13 | "entgo.io/ent/schema/index" 14 | "github.com/google/uuid" 15 | 16 | "github.com/flume/enthistory" 17 | ) 18 | 19 | type OrganizationHistory struct { 20 | ent.Schema 21 | } 22 | 23 | func (OrganizationHistory) Fields() []ent.Field { 24 | return []ent.Field{ 25 | field.Int("id"). 26 | Immutable(), 27 | field.Time("history_time"). 28 | Immutable(). 29 | Default(time.Now), 30 | field.Enum("operation"). 31 | Immutable(). 32 | GoType(enthistory.OpType("")), 33 | field.UUID("ref", uuid.UUID{}). 34 | Optional(). 35 | Immutable(), 36 | field.UUID("updated_by", uuid.UUID{}). 37 | Nillable(). 38 | Optional(). 39 | Immutable(), 40 | field.String("name"), 41 | field.JSON("info", map[string]any{}). 42 | Optional()} 43 | } 44 | func (OrganizationHistory) Edges() []ent.Edge { 45 | return nil 46 | } 47 | func (OrganizationHistory) Annotations() []schema.Annotation { 48 | return []schema.Annotation{entsql.Annotation{Table: "organization_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 49 | } 50 | func (OrganizationHistory) Mixin() []ent.Mixin { 51 | return []ent.Mixin{mixins.TimeMixin{}} 52 | } 53 | func (OrganizationHistory) Indexes() []ent.Index { 54 | return []ent.Index{index.Fields("history_time")} 55 | } 56 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/schema/store.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/edge" 8 | "entgo.io/ent/schema/field" 9 | "github.com/google/uuid" 10 | 11 | "_examples/basic/ent/schema/mixins" 12 | ) 13 | 14 | // Store holds the schema definition for the Store entity. 15 | type Store struct { 16 | ent.Schema 17 | } 18 | 19 | // Annotations of the Store. 20 | func (Store) Annotations() []schema.Annotation { 21 | return []schema.Annotation{ 22 | entsql.Annotation{ 23 | Table: "store", 24 | }, 25 | } 26 | } 27 | 28 | // Fields of the Store. 29 | func (Store) Fields() []ent.Field { 30 | return []ent.Field{ 31 | field.UUID("id", uuid.UUID{}). 32 | Default(uuid.New), 33 | field.String("name"), 34 | field.String("region"), 35 | // FK to `Organization` table 36 | field.UUID("organization_id", uuid.UUID{}), 37 | } 38 | } 39 | 40 | // Edges of the Store. 41 | func (Store) Edges() []ent.Edge { 42 | return []ent.Edge{ 43 | edge.From("organization", Organization.Type). 44 | Ref("organization_stores"). 45 | Unique(). 46 | Required(). 47 | Field("organization_id"), 48 | } 49 | } 50 | 51 | // Mixin of the Store. 52 | func (Store) Mixin() []ent.Mixin { 53 | return []ent.Mixin{ 54 | mixins.TimeMixin{}, 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/schema/store_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "_examples/basic/ent/schema/mixins" 7 | "time" 8 | 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect/entsql" 11 | "entgo.io/ent/schema" 12 | "entgo.io/ent/schema/field" 13 | "entgo.io/ent/schema/index" 14 | "github.com/google/uuid" 15 | 16 | "github.com/flume/enthistory" 17 | ) 18 | 19 | type StoreHistory struct { 20 | ent.Schema 21 | } 22 | 23 | func (StoreHistory) Fields() []ent.Field { 24 | return []ent.Field{ 25 | field.Int("id"). 26 | Immutable(), 27 | field.Time("history_time"). 28 | Immutable(). 29 | Default(time.Now), 30 | field.Enum("operation"). 31 | Immutable(). 32 | GoType(enthistory.OpType("")), 33 | field.UUID("ref", uuid.UUID{}). 34 | Optional(). 35 | Immutable(), 36 | field.UUID("updated_by", uuid.UUID{}). 37 | Nillable(). 38 | Optional(). 39 | Immutable(), 40 | field.String("name"), 41 | field.String("region"), 42 | field.UUID("organization_id", uuid.UUID{})} 43 | } 44 | func (StoreHistory) Edges() []ent.Edge { 45 | return nil 46 | } 47 | func (StoreHistory) Annotations() []schema.Annotation { 48 | return []schema.Annotation{entsql.Annotation{Table: "store_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 49 | } 50 | func (StoreHistory) Mixin() []ent.Mixin { 51 | return []ent.Mixin{mixins.TimeMixin{}} 52 | } 53 | func (StoreHistory) Indexes() []ent.Index { 54 | return []ent.Index{index.Fields("history_time")} 55 | } 56 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/store_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/updateby_uuid/ent/predicate" 7 | "_examples/updateby_uuid/ent/store" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // StoreDelete is the builder for deleting a Store entity. 16 | type StoreDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *StoreMutation 20 | } 21 | 22 | // Where appends a list predicates to the StoreDelete builder. 23 | func (sd *StoreDelete) Where(ps ...predicate.Store) *StoreDelete { 24 | sd.mutation.Where(ps...) 25 | return sd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (sd *StoreDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, sd.sqlExec, sd.mutation, sd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (sd *StoreDelete) ExecX(ctx context.Context) int { 35 | n, err := sd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (sd *StoreDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(store.Table, sqlgraph.NewFieldSpec(store.FieldID, field.TypeUUID)) 44 | if ps := sd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, sd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | sd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // StoreDeleteOne is the builder for deleting a single Store entity. 60 | type StoreDeleteOne struct { 61 | sd *StoreDelete 62 | } 63 | 64 | // Where appends a list predicates to the StoreDelete builder. 65 | func (sdo *StoreDeleteOne) Where(ps ...predicate.Store) *StoreDeleteOne { 66 | sdo.sd.mutation.Where(ps...) 67 | return sdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (sdo *StoreDeleteOne) Exec(ctx context.Context) error { 72 | n, err := sdo.sd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{store.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (sdo *StoreDeleteOne) ExecX(ctx context.Context) { 85 | if err := sdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/updateby_uuid/ent/storehistory_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/updateby_uuid/ent/predicate" 7 | "_examples/updateby_uuid/ent/storehistory" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // StoreHistoryDelete is the builder for deleting a StoreHistory entity. 16 | type StoreHistoryDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *StoreHistoryMutation 20 | } 21 | 22 | // Where appends a list predicates to the StoreHistoryDelete builder. 23 | func (shd *StoreHistoryDelete) Where(ps ...predicate.StoreHistory) *StoreHistoryDelete { 24 | shd.mutation.Where(ps...) 25 | return shd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (shd *StoreHistoryDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, shd.sqlExec, shd.mutation, shd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (shd *StoreHistoryDelete) ExecX(ctx context.Context) int { 35 | n, err := shd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (shd *StoreHistoryDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(storehistory.Table, sqlgraph.NewFieldSpec(storehistory.FieldID, field.TypeInt)) 44 | if ps := shd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, shd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | shd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // StoreHistoryDeleteOne is the builder for deleting a single StoreHistory entity. 60 | type StoreHistoryDeleteOne struct { 61 | shd *StoreHistoryDelete 62 | } 63 | 64 | // Where appends a list predicates to the StoreHistoryDelete builder. 65 | func (shdo *StoreHistoryDeleteOne) Where(ps ...predicate.StoreHistory) *StoreHistoryDeleteOne { 66 | shdo.shd.mutation.Where(ps...) 67 | return shdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (shdo *StoreHistoryDeleteOne) Exec(ctx context.Context) error { 72 | n, err := shdo.shd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{storehistory.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (shdo *StoreHistoryDeleteOne) ExecX(ctx context.Context) { 85 | if err := shdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/entc.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "_examples/uuidmixinid/ent/schema" 7 | "fmt" 8 | "log" 9 | 10 | "entgo.io/ent" 11 | "entgo.io/ent/entc" 12 | "entgo.io/ent/entc/gen" 13 | "entgo.io/ent/schema/field" 14 | 15 | "github.com/flume/enthistory" 16 | ) 17 | 18 | func main() { 19 | if err := enthistory.Generate("./schema", []ent.Interface{ 20 | // Add all the schemas you want history tracking on here 21 | schema.MenuItem{}, 22 | }, 23 | enthistory.WithInheritIdType(), 24 | enthistory.WithUpdatedBy("userId", enthistory.ValueTypeUUID), 25 | enthistory.WithHistoryTimeIndex(), 26 | enthistory.WithImmutableFields(), 27 | // Without this line, all triggers will be used as the default 28 | enthistory.WithTriggers(enthistory.OpTypeInsert), 29 | ); err != nil { 30 | log.Fatal(fmt.Sprintf("running enthistory codegen: %v", err)) 31 | } 32 | 33 | if err := entc.Generate("./schema", &gen.Config{ 34 | IDType: &field.TypeInfo{Type: field.TypeString}, 35 | Features: []gen.Feature{ 36 | gen.FeatureSnapshot, 37 | }, 38 | }, 39 | entc.Extensions( 40 | enthistory.NewHistoryExtension(enthistory.WithAuditing()), 41 | ), 42 | ); err != nil { 43 | log.Fatal("running ent codegen:", err) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/enttest/enttest.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package enttest 4 | 5 | import ( 6 | "context" 7 | 8 | "_examples/uuidmixinid/ent" 9 | // required by schema hooks. 10 | _ "_examples/uuidmixinid/ent/runtime" 11 | 12 | "_examples/uuidmixinid/ent/migrate" 13 | 14 | "entgo.io/ent/dialect/sql/schema" 15 | ) 16 | 17 | type ( 18 | // TestingT is the interface that is shared between 19 | // testing.T and testing.B and used by enttest. 20 | TestingT interface { 21 | FailNow() 22 | Error(...any) 23 | } 24 | 25 | // Option configures client creation. 26 | Option func(*options) 27 | 28 | options struct { 29 | opts []ent.Option 30 | migrateOpts []schema.MigrateOption 31 | } 32 | ) 33 | 34 | // WithOptions forwards options to client creation. 35 | func WithOptions(opts ...ent.Option) Option { 36 | return func(o *options) { 37 | o.opts = append(o.opts, opts...) 38 | } 39 | } 40 | 41 | // WithMigrateOptions forwards options to auto migration. 42 | func WithMigrateOptions(opts ...schema.MigrateOption) Option { 43 | return func(o *options) { 44 | o.migrateOpts = append(o.migrateOpts, opts...) 45 | } 46 | } 47 | 48 | func newOptions(opts []Option) *options { 49 | o := &options{} 50 | for _, opt := range opts { 51 | opt(o) 52 | } 53 | return o 54 | } 55 | 56 | // Open calls ent.Open and auto-run migration. 57 | func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { 58 | o := newOptions(opts) 59 | c, err := ent.Open(driverName, dataSourceName, o.opts...) 60 | if err != nil { 61 | t.Error(err) 62 | t.FailNow() 63 | } 64 | migrateSchema(t, c, o) 65 | return c 66 | } 67 | 68 | // NewClient calls ent.NewClient and auto-run migration. 69 | func NewClient(t TestingT, opts ...Option) *ent.Client { 70 | o := newOptions(opts) 71 | c := ent.NewClient(o.opts...) 72 | migrateSchema(t, c, o) 73 | return c 74 | } 75 | func migrateSchema(t TestingT, c *ent.Client, o *options) { 76 | tables, err := schema.CopyTables(migrate.Tables) 77 | if err != nil { 78 | t.Error(err) 79 | t.FailNow() 80 | } 81 | if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { 82 | t.Error(err) 83 | t.FailNow() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/generate.go: -------------------------------------------------------------------------------- 1 | package ent 2 | 3 | //go:generate go run entc.go 4 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/history_query.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | // Code generated by ent, DO NOT EDIT. 3 | 4 | package ent 5 | 6 | import ( 7 | "context" 8 | "time" 9 | 10 | "_examples/uuidmixinid/ent/menuitemhistory" 11 | 12 | "entgo.io/ent/dialect/sql" 13 | ) 14 | 15 | func (mi *MenuItem) History() *MenuItemHistoryQuery { 16 | historyClient := NewMenuItemHistoryClient(mi.config) 17 | return historyClient.Query().Where(menuitemhistory.Ref(mi.ID)) 18 | } 19 | 20 | func (mih *MenuItemHistory) Next(ctx context.Context) (*MenuItemHistory, error) { 21 | client := NewMenuItemHistoryClient(mih.config) 22 | return client.Query(). 23 | Where( 24 | menuitemhistory.Ref(mih.Ref), 25 | menuitemhistory.HistoryTimeGT(mih.HistoryTime), 26 | ). 27 | Order(menuitemhistory.ByHistoryTime()). 28 | First(ctx) 29 | } 30 | 31 | func (mih *MenuItemHistory) Prev(ctx context.Context) (*MenuItemHistory, error) { 32 | client := NewMenuItemHistoryClient(mih.config) 33 | return client.Query(). 34 | Where( 35 | menuitemhistory.Ref(mih.Ref), 36 | menuitemhistory.HistoryTimeLT(mih.HistoryTime), 37 | ). 38 | Order(menuitemhistory.ByHistoryTime(sql.OrderDesc())). 39 | First(ctx) 40 | } 41 | 42 | func (mihq *MenuItemHistoryQuery) Earliest(ctx context.Context) (*MenuItemHistory, error) { 43 | return mihq. 44 | Order(menuitemhistory.ByHistoryTime()). 45 | First(ctx) 46 | } 47 | 48 | func (mihq *MenuItemHistoryQuery) Latest(ctx context.Context) (*MenuItemHistory, error) { 49 | return mihq. 50 | Order(menuitemhistory.ByHistoryTime(sql.OrderDesc())). 51 | First(ctx) 52 | } 53 | 54 | func (mihq *MenuItemHistoryQuery) AsOf(ctx context.Context, time time.Time) (*MenuItemHistory, error) { 55 | return mihq. 56 | Where(menuitemhistory.HistoryTimeLTE(time)). 57 | Order(menuitemhistory.ByHistoryTime(sql.OrderDesc())). 58 | First(ctx) 59 | } 60 | 61 | func (mih *MenuItemHistory) Restore(ctx context.Context) (*MenuItem, error) { 62 | client := NewMenuItemClient(mih.config) 63 | return client. 64 | UpdateOneID(mih.Ref). 65 | SetUpdatedAt(mih.UpdatedAt). 66 | SetName(mih.Name). 67 | SetPrice(mih.Price). 68 | SetDescription(mih.Description). 69 | Save(ctx) 70 | } 71 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/menuitem_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/uuidmixinid/ent/menuitem" 7 | "_examples/uuidmixinid/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // MenuItemDelete is the builder for deleting a MenuItem entity. 16 | type MenuItemDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *MenuItemMutation 20 | } 21 | 22 | // Where appends a list predicates to the MenuItemDelete builder. 23 | func (mid *MenuItemDelete) Where(ps ...predicate.MenuItem) *MenuItemDelete { 24 | mid.mutation.Where(ps...) 25 | return mid 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (mid *MenuItemDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, mid.sqlExec, mid.mutation, mid.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (mid *MenuItemDelete) ExecX(ctx context.Context) int { 35 | n, err := mid.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (mid *MenuItemDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(menuitem.Table, sqlgraph.NewFieldSpec(menuitem.FieldID, field.TypeUUID)) 44 | if ps := mid.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, mid.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | mid.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // MenuItemDeleteOne is the builder for deleting a single MenuItem entity. 60 | type MenuItemDeleteOne struct { 61 | mid *MenuItemDelete 62 | } 63 | 64 | // Where appends a list predicates to the MenuItemDelete builder. 65 | func (mido *MenuItemDeleteOne) Where(ps ...predicate.MenuItem) *MenuItemDeleteOne { 66 | mido.mid.mutation.Where(ps...) 67 | return mido 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (mido *MenuItemDeleteOne) Exec(ctx context.Context) error { 72 | n, err := mido.mid.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{menuitem.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (mido *MenuItemDeleteOne) ExecX(ctx context.Context) { 85 | if err := mido.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/menuitemhistory_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/uuidmixinid/ent/menuitemhistory" 7 | "_examples/uuidmixinid/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // MenuItemHistoryDelete is the builder for deleting a MenuItemHistory entity. 16 | type MenuItemHistoryDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *MenuItemHistoryMutation 20 | } 21 | 22 | // Where appends a list predicates to the MenuItemHistoryDelete builder. 23 | func (mihd *MenuItemHistoryDelete) Where(ps ...predicate.MenuItemHistory) *MenuItemHistoryDelete { 24 | mihd.mutation.Where(ps...) 25 | return mihd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (mihd *MenuItemHistoryDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, mihd.sqlExec, mihd.mutation, mihd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (mihd *MenuItemHistoryDelete) ExecX(ctx context.Context) int { 35 | n, err := mihd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (mihd *MenuItemHistoryDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(menuitemhistory.Table, sqlgraph.NewFieldSpec(menuitemhistory.FieldID, field.TypeUUID)) 44 | if ps := mihd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, mihd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | mihd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // MenuItemHistoryDeleteOne is the builder for deleting a single MenuItemHistory entity. 60 | type MenuItemHistoryDeleteOne struct { 61 | mihd *MenuItemHistoryDelete 62 | } 63 | 64 | // Where appends a list predicates to the MenuItemHistoryDelete builder. 65 | func (mihdo *MenuItemHistoryDeleteOne) Where(ps ...predicate.MenuItemHistory) *MenuItemHistoryDeleteOne { 66 | mihdo.mihd.mutation.Where(ps...) 67 | return mihdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (mihdo *MenuItemHistoryDeleteOne) Exec(ctx context.Context) error { 72 | n, err := mihdo.mihd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{menuitemhistory.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (mihdo *MenuItemHistoryDeleteOne) ExecX(ctx context.Context) { 85 | if err := mihdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io" 9 | 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | var ( 15 | // WithGlobalUniqueID sets the universal ids options to the migration. 16 | // If this option is enabled, ent migration will allocate a 1<<32 range 17 | // for the ids of each entity (table). 18 | // Note that this option cannot be applied on tables that already exist. 19 | WithGlobalUniqueID = schema.WithGlobalUniqueID 20 | // WithDropColumn sets the drop column option to the migration. 21 | // If this option is enabled, ent migration will drop old columns 22 | // that were used for both fields and edges. This defaults to false. 23 | WithDropColumn = schema.WithDropColumn 24 | // WithDropIndex sets the drop index option to the migration. 25 | // If this option is enabled, ent migration will drop old indexes 26 | // that were defined in the schema. This defaults to false. 27 | // Note that unique constraints are defined using `UNIQUE INDEX`, 28 | // and therefore, it's recommended to enable this option to get more 29 | // flexibility in the schema changes. 30 | WithDropIndex = schema.WithDropIndex 31 | // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. 32 | WithForeignKeys = schema.WithForeignKeys 33 | ) 34 | 35 | // Schema is the API for creating, migrating and dropping a schema. 36 | type Schema struct { 37 | drv dialect.Driver 38 | } 39 | 40 | // NewSchema creates a new schema client. 41 | func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } 42 | 43 | // Create creates all schema resources. 44 | func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { 45 | return Create(ctx, s, Tables, opts...) 46 | } 47 | 48 | // Create creates all table resources using the given schema driver. 49 | func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error { 50 | migrate, err := schema.NewMigrate(s.drv, opts...) 51 | if err != nil { 52 | return fmt.Errorf("ent/migrate: %w", err) 53 | } 54 | return migrate.Create(ctx, tables...) 55 | } 56 | 57 | // WriteTo writes the schema changes to w instead of running them against the database. 58 | // 59 | // if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { 60 | // log.Fatal(err) 61 | // } 62 | func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { 63 | return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...) 64 | } 65 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/migrate/schema.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/entsql" 7 | "entgo.io/ent/dialect/sql/schema" 8 | "entgo.io/ent/schema/field" 9 | ) 10 | 11 | var ( 12 | // MenuItemColumns holds the columns for the "menu_item" table. 13 | MenuItemColumns = []*schema.Column{ 14 | {Name: "id", Type: field.TypeUUID}, 15 | {Name: "created_at", Type: field.TypeTime}, 16 | {Name: "updated_at", Type: field.TypeTime}, 17 | {Name: "name", Type: field.TypeString}, 18 | {Name: "price", Type: field.TypeFloat64}, 19 | {Name: "description", Type: field.TypeString, Nullable: true}, 20 | } 21 | // MenuItemTable holds the schema information for the "menu_item" table. 22 | MenuItemTable = &schema.Table{ 23 | Name: "menu_item", 24 | Columns: MenuItemColumns, 25 | PrimaryKey: []*schema.Column{MenuItemColumns[0]}, 26 | } 27 | // MenuItemHistoryColumns holds the columns for the "menu_item_history" table. 28 | MenuItemHistoryColumns = []*schema.Column{ 29 | {Name: "id", Type: field.TypeUUID}, 30 | {Name: "created_at", Type: field.TypeTime}, 31 | {Name: "updated_at", Type: field.TypeTime}, 32 | {Name: "history_time", Type: field.TypeTime}, 33 | {Name: "operation", Type: field.TypeEnum, Enums: []string{"INSERT", "UPDATE", "DELETE"}}, 34 | {Name: "ref", Type: field.TypeUUID, Nullable: true}, 35 | {Name: "updated_by", Type: field.TypeUUID, Nullable: true}, 36 | {Name: "name", Type: field.TypeString}, 37 | {Name: "price", Type: field.TypeFloat64}, 38 | {Name: "description", Type: field.TypeString, Nullable: true}, 39 | } 40 | // MenuItemHistoryTable holds the schema information for the "menu_item_history" table. 41 | MenuItemHistoryTable = &schema.Table{ 42 | Name: "menu_item_history", 43 | Columns: MenuItemHistoryColumns, 44 | PrimaryKey: []*schema.Column{MenuItemHistoryColumns[0]}, 45 | Indexes: []*schema.Index{ 46 | { 47 | Name: "menuitemhistory_history_time", 48 | Unique: false, 49 | Columns: []*schema.Column{MenuItemHistoryColumns[3]}, 50 | }, 51 | }, 52 | } 53 | // Tables holds all the tables in the schema. 54 | Tables = []*schema.Table{ 55 | MenuItemTable, 56 | MenuItemHistoryTable, 57 | } 58 | ) 59 | 60 | func init() { 61 | MenuItemTable.Annotation = &entsql.Annotation{ 62 | Table: "menu_item", 63 | } 64 | MenuItemHistoryTable.Annotation = &entsql.Annotation{ 65 | Table: "menu_item_history", 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // MenuItem is the predicate function for menuitem builders. 10 | type MenuItem func(*sql.Selector) 11 | 12 | // MenuItemHistory is the predicate function for menuitemhistory builders. 13 | type MenuItemHistory func(*sql.Selector) 14 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in _examples/uuidmixinid/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.14.4" // Version of ent codegen. 9 | Sum = "h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/schema/menu_item.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | mixins2 "_examples/uuidmixinid/ent/schema/mixins" 5 | 6 | "entgo.io/ent" 7 | "entgo.io/ent/dialect/entsql" 8 | "entgo.io/ent/schema" 9 | "entgo.io/ent/schema/field" 10 | ) 11 | 12 | // MenuItem holds the schema definition for the MenuItem entity. 13 | type MenuItem struct { 14 | ent.Schema 15 | } 16 | 17 | // Annotations of the MenuItem. 18 | func (MenuItem) Annotations() []schema.Annotation { 19 | return []schema.Annotation{ 20 | entsql.Annotation{ 21 | Table: "menu_item", 22 | }, 23 | } 24 | } 25 | 26 | // Fields of the MenuItem. 27 | func (MenuItem) Fields() []ent.Field { 28 | return []ent.Field{ 29 | field.String("name"). 30 | NotEmpty(), 31 | field.Float("price"). 32 | Positive(), 33 | field.String("description"). 34 | Optional(), 35 | } 36 | } 37 | 38 | // Edges of the MenuItem. 39 | func (MenuItem) Edges() []ent.Edge { 40 | return []ent.Edge{} 41 | } 42 | 43 | // Mixin of the MenuItem. 44 | func (MenuItem) Mixin() []ent.Mixin { 45 | return []ent.Mixin{ 46 | mixins2.IDMixin{}, 47 | mixins2.TimeMixin{}, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/schema/menu_item_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "_examples/uuidmixinid/ent/schema/mixins" 7 | "time" 8 | 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect/entsql" 11 | "entgo.io/ent/schema" 12 | "entgo.io/ent/schema/field" 13 | "entgo.io/ent/schema/index" 14 | "github.com/google/uuid" 15 | 16 | "github.com/flume/enthistory" 17 | ) 18 | 19 | type MenuItemHistory struct { 20 | ent.Schema 21 | } 22 | 23 | func (MenuItemHistory) Fields() []ent.Field { 24 | return []ent.Field{ 25 | field.UUID("id", uuid.UUID{}). 26 | Default(uuid.New), 27 | field.Time("history_time"). 28 | Immutable(). 29 | Default(time.Now), 30 | field.Enum("operation"). 31 | Immutable(). 32 | GoType(enthistory.OpType("")), 33 | field.UUID("ref", uuid.UUID{}). 34 | Optional(). 35 | Immutable(), 36 | field.UUID("updated_by", uuid.UUID{}). 37 | Nillable(). 38 | Optional(). 39 | Immutable(), 40 | field.String("name"). 41 | Immutable(), 42 | field.Float("price"). 43 | Immutable(), 44 | field.String("description"). 45 | Optional(). 46 | Immutable()} 47 | } 48 | func (MenuItemHistory) Edges() []ent.Edge { 49 | return nil 50 | } 51 | func (MenuItemHistory) Annotations() []schema.Annotation { 52 | return []schema.Annotation{entsql.Annotation{Table: "menu_item_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert}}} 53 | } 54 | func (MenuItemHistory) Mixin() []ent.Mixin { 55 | return []ent.Mixin{mixins.IDMixin{}, mixins.TimeMixin{}} 56 | } 57 | func (MenuItemHistory) Indexes() []ent.Index { 58 | return []ent.Index{index.Fields("history_time")} 59 | } 60 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/schema/mixins/idmixin.go: -------------------------------------------------------------------------------- 1 | package mixins 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/schema/field" 6 | "entgo.io/ent/schema/mixin" 7 | "github.com/google/uuid" 8 | ) 9 | 10 | type IDMixin struct { 11 | mixin.Schema 12 | } 13 | 14 | func (IDMixin) Fields() []ent.Field { 15 | return []ent.Field{ 16 | field.UUID("id", uuid.UUID{}). 17 | Default(uuid.New), 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /_examples/uuidmixinid/ent/schema/mixins/timemixin.go: -------------------------------------------------------------------------------- 1 | package mixins 2 | 3 | import ( 4 | "time" 5 | 6 | "entgo.io/ent" 7 | "entgo.io/ent/schema/field" 8 | "entgo.io/ent/schema/mixin" 9 | ) 10 | 11 | type TimeMixin struct { 12 | mixin.Schema 13 | } 14 | 15 | func (TimeMixin) Fields() []ent.Field { 16 | return []ent.Field{ 17 | field.Time("created_at"). 18 | Immutable(). 19 | Default(time.Now), 20 | field.Time("updated_at"). 21 | Default(time.Now). 22 | UpdateDefault(time.Now), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/character_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/without_updatedby/ent/character" 7 | "_examples/without_updatedby/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // CharacterDelete is the builder for deleting a Character entity. 16 | type CharacterDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *CharacterMutation 20 | } 21 | 22 | // Where appends a list predicates to the CharacterDelete builder. 23 | func (cd *CharacterDelete) Where(ps ...predicate.Character) *CharacterDelete { 24 | cd.mutation.Where(ps...) 25 | return cd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (cd *CharacterDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, cd.sqlExec, cd.mutation, cd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (cd *CharacterDelete) ExecX(ctx context.Context) int { 35 | n, err := cd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (cd *CharacterDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(character.Table, sqlgraph.NewFieldSpec(character.FieldID, field.TypeInt)) 44 | if ps := cd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, cd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | cd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // CharacterDeleteOne is the builder for deleting a single Character entity. 60 | type CharacterDeleteOne struct { 61 | cd *CharacterDelete 62 | } 63 | 64 | // Where appends a list predicates to the CharacterDelete builder. 65 | func (cdo *CharacterDeleteOne) Where(ps ...predicate.Character) *CharacterDeleteOne { 66 | cdo.cd.mutation.Where(ps...) 67 | return cdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (cdo *CharacterDeleteOne) Exec(ctx context.Context) error { 72 | n, err := cdo.cd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{character.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (cdo *CharacterDeleteOne) ExecX(ctx context.Context) { 85 | if err := cdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/entc.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "_examples/without_updatedby/ent/schema" 7 | "fmt" 8 | "log" 9 | 10 | "entgo.io/ent" 11 | 12 | "entgo.io/ent/entc/gen" 13 | 14 | "github.com/flume/enthistory" 15 | 16 | "entgo.io/ent/entc" 17 | ) 18 | 19 | func main() { 20 | if err := enthistory.Generate("./schema", []ent.Interface{ 21 | &schema.Character{}, 22 | &schema.Friendship{}, 23 | &schema.Residence{}, 24 | }, 25 | enthistory.WithHistoryTimeIndex(), 26 | enthistory.WithImmutableFields(), 27 | ); err != nil { 28 | log.Fatal(fmt.Sprintf("running enthistory codegen: %v", err)) 29 | } 30 | 31 | if err := entc.Generate("./schema", 32 | &gen.Config{ 33 | Features: []gen.Feature{gen.FeatureSnapshot}, 34 | }, 35 | entc.Extensions( 36 | enthistory.NewHistoryExtension(enthistory.WithAuditing()), 37 | ), 38 | ); err != nil { 39 | log.Fatal("running ent codegen:", err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/enttest/enttest.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package enttest 4 | 5 | import ( 6 | "context" 7 | 8 | "_examples/without_updatedby/ent" 9 | // required by schema hooks. 10 | _ "_examples/without_updatedby/ent/runtime" 11 | 12 | "_examples/without_updatedby/ent/migrate" 13 | 14 | "entgo.io/ent/dialect/sql/schema" 15 | ) 16 | 17 | type ( 18 | // TestingT is the interface that is shared between 19 | // testing.T and testing.B and used by enttest. 20 | TestingT interface { 21 | FailNow() 22 | Error(...any) 23 | } 24 | 25 | // Option configures client creation. 26 | Option func(*options) 27 | 28 | options struct { 29 | opts []ent.Option 30 | migrateOpts []schema.MigrateOption 31 | } 32 | ) 33 | 34 | // WithOptions forwards options to client creation. 35 | func WithOptions(opts ...ent.Option) Option { 36 | return func(o *options) { 37 | o.opts = append(o.opts, opts...) 38 | } 39 | } 40 | 41 | // WithMigrateOptions forwards options to auto migration. 42 | func WithMigrateOptions(opts ...schema.MigrateOption) Option { 43 | return func(o *options) { 44 | o.migrateOpts = append(o.migrateOpts, opts...) 45 | } 46 | } 47 | 48 | func newOptions(opts []Option) *options { 49 | o := &options{} 50 | for _, opt := range opts { 51 | opt(o) 52 | } 53 | return o 54 | } 55 | 56 | // Open calls ent.Open and auto-run migration. 57 | func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { 58 | o := newOptions(opts) 59 | c, err := ent.Open(driverName, dataSourceName, o.opts...) 60 | if err != nil { 61 | t.Error(err) 62 | t.FailNow() 63 | } 64 | migrateSchema(t, c, o) 65 | return c 66 | } 67 | 68 | // NewClient calls ent.NewClient and auto-run migration. 69 | func NewClient(t TestingT, opts ...Option) *ent.Client { 70 | o := newOptions(opts) 71 | c := ent.NewClient(o.opts...) 72 | migrateSchema(t, c, o) 73 | return c 74 | } 75 | func migrateSchema(t TestingT, c *ent.Client, o *options) { 76 | tables, err := schema.CopyTables(migrate.Tables) 77 | if err != nil { 78 | t.Error(err) 79 | t.FailNow() 80 | } 81 | if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { 82 | t.Error(err) 83 | t.FailNow() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/friendship_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/without_updatedby/ent/friendship" 7 | "_examples/without_updatedby/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // FriendshipDelete is the builder for deleting a Friendship entity. 16 | type FriendshipDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *FriendshipMutation 20 | } 21 | 22 | // Where appends a list predicates to the FriendshipDelete builder. 23 | func (fd *FriendshipDelete) Where(ps ...predicate.Friendship) *FriendshipDelete { 24 | fd.mutation.Where(ps...) 25 | return fd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (fd *FriendshipDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, fd.sqlExec, fd.mutation, fd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (fd *FriendshipDelete) ExecX(ctx context.Context) int { 35 | n, err := fd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (fd *FriendshipDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(friendship.Table, sqlgraph.NewFieldSpec(friendship.FieldID, field.TypeString)) 44 | if ps := fd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, fd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | fd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // FriendshipDeleteOne is the builder for deleting a single Friendship entity. 60 | type FriendshipDeleteOne struct { 61 | fd *FriendshipDelete 62 | } 63 | 64 | // Where appends a list predicates to the FriendshipDelete builder. 65 | func (fdo *FriendshipDeleteOne) Where(ps ...predicate.Friendship) *FriendshipDeleteOne { 66 | fdo.fd.mutation.Where(ps...) 67 | return fdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (fdo *FriendshipDeleteOne) Exec(ctx context.Context) error { 72 | n, err := fdo.fd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{friendship.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (fdo *FriendshipDeleteOne) ExecX(ctx context.Context) { 85 | if err := fdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/generate.go: -------------------------------------------------------------------------------- 1 | package ent 2 | 3 | //go:generate go run entc.go 4 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io" 9 | 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | var ( 15 | // WithGlobalUniqueID sets the universal ids options to the migration. 16 | // If this option is enabled, ent migration will allocate a 1<<32 range 17 | // for the ids of each entity (table). 18 | // Note that this option cannot be applied on tables that already exist. 19 | WithGlobalUniqueID = schema.WithGlobalUniqueID 20 | // WithDropColumn sets the drop column option to the migration. 21 | // If this option is enabled, ent migration will drop old columns 22 | // that were used for both fields and edges. This defaults to false. 23 | WithDropColumn = schema.WithDropColumn 24 | // WithDropIndex sets the drop index option to the migration. 25 | // If this option is enabled, ent migration will drop old indexes 26 | // that were defined in the schema. This defaults to false. 27 | // Note that unique constraints are defined using `UNIQUE INDEX`, 28 | // and therefore, it's recommended to enable this option to get more 29 | // flexibility in the schema changes. 30 | WithDropIndex = schema.WithDropIndex 31 | // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. 32 | WithForeignKeys = schema.WithForeignKeys 33 | ) 34 | 35 | // Schema is the API for creating, migrating and dropping a schema. 36 | type Schema struct { 37 | drv dialect.Driver 38 | } 39 | 40 | // NewSchema creates a new schema client. 41 | func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } 42 | 43 | // Create creates all schema resources. 44 | func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { 45 | return Create(ctx, s, Tables, opts...) 46 | } 47 | 48 | // Create creates all table resources using the given schema driver. 49 | func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error { 50 | migrate, err := schema.NewMigrate(s.drv, opts...) 51 | if err != nil { 52 | return fmt.Errorf("ent/migrate: %w", err) 53 | } 54 | return migrate.Create(ctx, tables...) 55 | } 56 | 57 | // WriteTo writes the schema changes to w instead of running them against the database. 58 | // 59 | // if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { 60 | // log.Fatal(err) 61 | // } 62 | func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { 63 | return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...) 64 | } 65 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // Character is the predicate function for character builders. 10 | type Character func(*sql.Selector) 11 | 12 | // CharacterHistory is the predicate function for characterhistory builders. 13 | type CharacterHistory func(*sql.Selector) 14 | 15 | // Friendship is the predicate function for friendship builders. 16 | type Friendship func(*sql.Selector) 17 | 18 | // FriendshipHistory is the predicate function for friendshiphistory builders. 19 | type FriendshipHistory func(*sql.Selector) 20 | 21 | // Residence is the predicate function for residence builders. 22 | type Residence func(*sql.Selector) 23 | 24 | // ResidenceHistory is the predicate function for residencehistory builders. 25 | type ResidenceHistory func(*sql.Selector) 26 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/residence_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "_examples/without_updatedby/ent/predicate" 7 | "_examples/without_updatedby/ent/residence" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // ResidenceDelete is the builder for deleting a Residence entity. 16 | type ResidenceDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *ResidenceMutation 20 | } 21 | 22 | // Where appends a list predicates to the ResidenceDelete builder. 23 | func (rd *ResidenceDelete) Where(ps ...predicate.Residence) *ResidenceDelete { 24 | rd.mutation.Where(ps...) 25 | return rd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (rd *ResidenceDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, rd.sqlExec, rd.mutation, rd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (rd *ResidenceDelete) ExecX(ctx context.Context) int { 35 | n, err := rd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (rd *ResidenceDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(residence.Table, sqlgraph.NewFieldSpec(residence.FieldID, field.TypeUUID)) 44 | if ps := rd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, rd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | rd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // ResidenceDeleteOne is the builder for deleting a single Residence entity. 60 | type ResidenceDeleteOne struct { 61 | rd *ResidenceDelete 62 | } 63 | 64 | // Where appends a list predicates to the ResidenceDelete builder. 65 | func (rdo *ResidenceDeleteOne) Where(ps ...predicate.Residence) *ResidenceDeleteOne { 66 | rdo.rd.mutation.Where(ps...) 67 | return rdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (rdo *ResidenceDeleteOne) Exec(ctx context.Context) error { 72 | n, err := rdo.rd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{residence.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (rdo *ResidenceDeleteOne) ExecX(ctx context.Context) { 85 | if err := rdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in _examples/without_updatedby/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.14.4" // Version of ent codegen. 9 | Sum = "h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/schema/character.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/edge" 8 | "entgo.io/ent/schema/field" 9 | 10 | "_examples/basic/ent/schema/mixins" 11 | ) 12 | 13 | // Character holds the schema definition for the Character entity. 14 | type Character struct { 15 | ent.Schema 16 | } 17 | 18 | // Annotations of the Character. 19 | func (Character) Annotations() []schema.Annotation { 20 | return []schema.Annotation{ 21 | entsql.Annotation{ 22 | Table: "character", 23 | }, 24 | } 25 | } 26 | 27 | // Fields of the Character. 28 | func (Character) Fields() []ent.Field { 29 | return []ent.Field{ 30 | field.Int("age"). 31 | Positive(), 32 | field.String("name"), 33 | field.JSON("nicknames", []string{}). 34 | Optional(), 35 | field.JSON("info", map[string]any{}). 36 | Optional(), 37 | } 38 | } 39 | 40 | // Edges of the Character. 41 | func (Character) Edges() []ent.Edge { 42 | return []ent.Edge{ 43 | edge.To("friends", Character.Type). 44 | Through("friendships", Friendship.Type), 45 | edge.From("residence", Residence.Type). 46 | Ref("occupants"). 47 | Unique(), 48 | } 49 | } 50 | 51 | // Mixin of the Character. 52 | func (Character) Mixin() []ent.Mixin { 53 | return []ent.Mixin{ 54 | mixins.TimeMixin{}, 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/schema/character_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "_examples/basic/ent/schema/mixins" 7 | "time" 8 | 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect/entsql" 11 | "entgo.io/ent/schema" 12 | "entgo.io/ent/schema/field" 13 | "entgo.io/ent/schema/index" 14 | 15 | "github.com/flume/enthistory" 16 | ) 17 | 18 | type CharacterHistory struct { 19 | ent.Schema 20 | } 21 | 22 | func (CharacterHistory) Fields() []ent.Field { 23 | return []ent.Field{ 24 | field.Time("history_time"). 25 | Immutable(). 26 | Default(time.Now), 27 | field.Enum("operation"). 28 | Immutable(). 29 | GoType(enthistory.OpType("")), 30 | field.Int("ref"). 31 | Optional(). 32 | Immutable(), 33 | field.Int("age"). 34 | Immutable(), 35 | field.String("name"). 36 | Immutable(), 37 | field.JSON("nicknames", []string{}). 38 | Optional(). 39 | Immutable(), 40 | field.JSON("info", map[string]any{}). 41 | Optional(). 42 | Immutable()} 43 | } 44 | func (CharacterHistory) Edges() []ent.Edge { 45 | return nil 46 | } 47 | func (CharacterHistory) Annotations() []schema.Annotation { 48 | return []schema.Annotation{entsql.Annotation{Table: "character_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 49 | } 50 | func (CharacterHistory) Mixin() []ent.Mixin { 51 | return []ent.Mixin{mixins.TimeMixin{}} 52 | } 53 | func (CharacterHistory) Indexes() []ent.Index { 54 | return []ent.Index{index.Fields("history_time")} 55 | } 56 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/schema/friendship.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/edge" 8 | "entgo.io/ent/schema/field" 9 | 10 | "_examples/basic/ent/schema/mixins" 11 | ) 12 | 13 | // Friendship holds the schema definition for the Friendship entity. 14 | type Friendship struct { 15 | ent.Schema 16 | } 17 | 18 | // Annotations of the Friendship. 19 | func (Friendship) Annotations() []schema.Annotation { 20 | return []schema.Annotation{ 21 | entsql.Annotation{ 22 | Table: "friendship", 23 | }, 24 | } 25 | } 26 | 27 | // Fields of the Friendship. 28 | func (Friendship) Fields() []ent.Field { 29 | return []ent.Field{ 30 | field.String("id"), 31 | field.Int("character_id"), 32 | field.Int("friend_id"), 33 | } 34 | } 35 | 36 | // Edges of the Friendship. 37 | func (Friendship) Edges() []ent.Edge { 38 | return []ent.Edge{ 39 | edge.To("character", Character.Type). 40 | Required(). 41 | Unique(). 42 | Field("character_id"), 43 | edge.To("friend", Character.Type). 44 | Required(). 45 | Unique(). 46 | Field("friend_id"), 47 | } 48 | } 49 | 50 | // Mixin of the Friendship. 51 | func (Friendship) Mixin() []ent.Mixin { 52 | return []ent.Mixin{ 53 | mixins.TimeMixin{}, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/schema/friendship_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "_examples/basic/ent/schema/mixins" 7 | "time" 8 | 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect/entsql" 11 | "entgo.io/ent/schema" 12 | "entgo.io/ent/schema/field" 13 | "entgo.io/ent/schema/index" 14 | 15 | "github.com/flume/enthistory" 16 | ) 17 | 18 | type FriendshipHistory struct { 19 | ent.Schema 20 | } 21 | 22 | func (FriendshipHistory) Fields() []ent.Field { 23 | return []ent.Field{ 24 | field.Int("id"). 25 | Immutable(), 26 | field.Time("history_time"). 27 | Immutable(). 28 | Default(time.Now), 29 | field.Enum("operation"). 30 | Immutable(). 31 | GoType(enthistory.OpType("")), 32 | field.String("ref"). 33 | Optional(). 34 | Immutable(), 35 | field.Int("character_id"). 36 | Immutable(), 37 | field.Int("friend_id"). 38 | Immutable()} 39 | } 40 | func (FriendshipHistory) Edges() []ent.Edge { 41 | return nil 42 | } 43 | func (FriendshipHistory) Annotations() []schema.Annotation { 44 | return []schema.Annotation{entsql.Annotation{Table: "friendship_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 45 | } 46 | func (FriendshipHistory) Mixin() []ent.Mixin { 47 | return []ent.Mixin{mixins.TimeMixin{}} 48 | } 49 | func (FriendshipHistory) Indexes() []ent.Index { 50 | return []ent.Index{index.Fields("history_time")} 51 | } 52 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/schema/mixins/timemixin.go: -------------------------------------------------------------------------------- 1 | package mixins 2 | 3 | import ( 4 | "time" 5 | 6 | "entgo.io/ent" 7 | "entgo.io/ent/schema/field" 8 | "entgo.io/ent/schema/mixin" 9 | ) 10 | 11 | type TimeMixin struct { 12 | mixin.Schema 13 | } 14 | 15 | func (TimeMixin) Fields() []ent.Field { 16 | return []ent.Field{ 17 | field.Time("created_at"). 18 | Immutable(). 19 | Default(time.Now), 20 | field.Time("updated_at"). 21 | Default(time.Now). 22 | UpdateDefault(time.Now), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/schema/residence.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/edge" 8 | "entgo.io/ent/schema/field" 9 | "github.com/google/uuid" 10 | 11 | "_examples/basic/ent/schema/mixins" 12 | ) 13 | 14 | // Residence holds the schema definition for the Residence entity. 15 | type Residence struct { 16 | ent.Schema 17 | } 18 | 19 | // Annotations of the Residence. 20 | func (Residence) Annotations() []schema.Annotation { 21 | return []schema.Annotation{ 22 | entsql.Annotation{ 23 | Table: "residence", 24 | }, 25 | } 26 | } 27 | 28 | // Fields of the Residence. 29 | func (Residence) Fields() []ent.Field { 30 | return []ent.Field{ 31 | field.UUID("id", uuid.UUID{}). 32 | Default(uuid.New), 33 | field.String("name"), 34 | } 35 | } 36 | 37 | // Edges of the Residence. 38 | func (Residence) Edges() []ent.Edge { 39 | return []ent.Edge{ 40 | edge.To("occupants", Character.Type), 41 | } 42 | } 43 | 44 | // Mixin of the Residence. 45 | func (Residence) Mixin() []ent.Mixin { 46 | return []ent.Mixin{ 47 | mixins.TimeMixin{}, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /_examples/without_updatedby/ent/schema/residence_history.go: -------------------------------------------------------------------------------- 1 | // Code generated by enthistory, DO NOT EDIT. 2 | 3 | package schema 4 | 5 | import ( 6 | "_examples/basic/ent/schema/mixins" 7 | "time" 8 | 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect/entsql" 11 | "entgo.io/ent/schema" 12 | "entgo.io/ent/schema/field" 13 | "entgo.io/ent/schema/index" 14 | "github.com/google/uuid" 15 | 16 | "github.com/flume/enthistory" 17 | ) 18 | 19 | type ResidenceHistory struct { 20 | ent.Schema 21 | } 22 | 23 | func (ResidenceHistory) Fields() []ent.Field { 24 | return []ent.Field{ 25 | field.Int("id"). 26 | Immutable(), 27 | field.Time("history_time"). 28 | Immutable(). 29 | Default(time.Now), 30 | field.Enum("operation"). 31 | Immutable(). 32 | GoType(enthistory.OpType("")), 33 | field.UUID("ref", uuid.UUID{}). 34 | Optional(). 35 | Immutable(), 36 | field.String("name"). 37 | Immutable()} 38 | } 39 | func (ResidenceHistory) Edges() []ent.Edge { 40 | return nil 41 | } 42 | func (ResidenceHistory) Annotations() []schema.Annotation { 43 | return []schema.Annotation{entsql.Annotation{Table: "residence_history"}, enthistory.Annotations{IsHistory: true, Triggers: []enthistory.OpType{enthistory.OpTypeInsert, enthistory.OpTypeUpdate, enthistory.OpTypeDelete}}} 44 | } 45 | func (ResidenceHistory) Mixin() []ent.Mixin { 46 | return []ent.Mixin{mixins.TimeMixin{}} 47 | } 48 | func (ResidenceHistory) Indexes() []ent.Index { 49 | return []ent.Index{index.Fields("history_time")} 50 | } 51 | -------------------------------------------------------------------------------- /extension.go: -------------------------------------------------------------------------------- 1 | package enthistory 2 | 3 | import ( 4 | "embed" 5 | 6 | "entgo.io/ent/entc" 7 | "entgo.io/ent/entc/gen" 8 | ) 9 | 10 | var ( 11 | //go:embed templates/* 12 | _templates embed.FS 13 | ) 14 | 15 | type Config struct { 16 | Auditing bool 17 | UpdatedBy *UpdatedBy 18 | } 19 | 20 | func (c Config) Name() string { 21 | return "HistoryConfig" 22 | } 23 | 24 | // HistoryExtension implements entc.Extension. 25 | type HistoryExtension struct { 26 | entc.DefaultExtension 27 | config *Config 28 | } 29 | 30 | type ExtensionOption = func(*HistoryExtension) 31 | 32 | // WithAuditing allows you to turn on the code generation for the `.Audit()` method 33 | func WithAuditing() ExtensionOption { 34 | return func(ex *HistoryExtension) { 35 | ex.config.Auditing = true 36 | } 37 | } 38 | 39 | func NewHistoryExtension(opts ...ExtensionOption) *HistoryExtension { 40 | extension := &HistoryExtension{ 41 | // Set configuration defaults that can get overridden with ExtensionOption 42 | config: &Config{ 43 | Auditing: false, 44 | UpdatedBy: updatedBy, 45 | }, 46 | } 47 | for _, opt := range opts { 48 | opt(extension) 49 | } 50 | 51 | return extension 52 | } 53 | 54 | func (h *HistoryExtension) Templates() []*gen.Template { 55 | templates := []*gen.Template{ 56 | parseTemplate("historyFromMutation", "templates/historyFromMutation.tmpl"), 57 | parseTemplate("historyQuery", "templates/historyQuery.tmpl"), 58 | parseTemplate("client", "templates/client.tmpl"), 59 | } 60 | if h.config.Auditing { 61 | templates = append(templates, parseTemplate("auditing", "templates/auditing.tmpl")) 62 | } 63 | return templates 64 | } 65 | 66 | // Hooks of the HistoryExtension. 67 | func (h *HistoryExtension) Hooks() []gen.Hook { 68 | return []gen.Hook{} 69 | } 70 | 71 | func (h *HistoryExtension) Annotations() []entc.Annotation { 72 | return []entc.Annotation{ 73 | h.config, 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/flume/enthistory 2 | 3 | go 1.24.2 4 | 5 | require ( 6 | entgo.io/contrib v0.6.0 7 | entgo.io/ent v0.14.4 8 | github.com/go-openapi/inflect v0.21.2 9 | github.com/google/uuid v1.6.0 10 | github.com/mitchellh/mapstructure v1.5.0 11 | github.com/stretchr/testify v1.10.0 12 | golang.org/x/sync v0.13.0 13 | golang.org/x/tools v0.32.0 14 | google.golang.org/protobuf v1.36.6 15 | ) 16 | 17 | require ( 18 | ariga.io/atlas v0.32.0 // indirect 19 | github.com/99designs/gqlgen v0.17.70 // indirect 20 | github.com/agext/levenshtein v1.2.3 // indirect 21 | github.com/agnivade/levenshtein v1.2.1 // indirect 22 | github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect 23 | github.com/bmatcuk/doublestar v1.3.4 // indirect 24 | github.com/bufbuild/protocompile v0.14.1 // indirect 25 | github.com/davecgh/go-spew v1.1.1 // indirect 26 | github.com/golang/protobuf v1.5.4 // indirect 27 | github.com/google/go-cmp v0.7.0 // indirect 28 | github.com/hashicorp/hcl/v2 v2.23.0 // indirect 29 | github.com/jhump/protoreflect v1.17.0 // indirect 30 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 31 | github.com/pmezard/go-difflib v1.0.0 // indirect 32 | github.com/sosodev/duration v1.3.1 // indirect 33 | github.com/vektah/gqlparser/v2 v2.5.24 // indirect 34 | github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 35 | github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 36 | github.com/zclconf/go-cty v1.16.2 // indirect 37 | github.com/zclconf/go-cty-yaml v1.1.0 // indirect 38 | go.uber.org/multierr v1.11.0 // indirect 39 | golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect 40 | golang.org/x/mod v0.24.0 // indirect 41 | golang.org/x/text v0.24.0 // indirect 42 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect 43 | gopkg.in/yaml.v3 v3.0.1 // indirect 44 | ) 45 | -------------------------------------------------------------------------------- /go.work: -------------------------------------------------------------------------------- 1 | go 1.24.2 2 | 3 | use ( 4 | . 5 | _examples 6 | ) 7 | -------------------------------------------------------------------------------- /internal/schemast/README.md: -------------------------------------------------------------------------------- 1 | # Schemast 2 | 3 | Ended up needing to make a handful of custom modifications to schemast so I brought 4 | it in here. 5 | 6 | Credit to https://github.com/ent/contrib for the original implementation. 7 | -------------------------------------------------------------------------------- /internal/schemast/index.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-present Facebook 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package schemast 16 | 17 | import ( 18 | "go/ast" 19 | 20 | "entgo.io/ent" 21 | "entgo.io/ent/schema/index" 22 | ) 23 | 24 | // Index converts an *index.Descriptor back into an *ast.CallExpr 25 | // of the ent Index package that can be used to construct it. 26 | func Index(desc *index.Descriptor) (*ast.CallExpr, error) { 27 | idx := newIndexCall(desc) 28 | if desc.Unique { 29 | idx.method("Unique") 30 | } 31 | if desc.StorageKey != "" { 32 | idx.method("StorageKey", strLit(desc.StorageKey)) 33 | } 34 | if len(desc.Edges) > 0 { 35 | var edges []ast.Expr 36 | for _, e := range desc.Edges { 37 | edges = append(edges, strLit(e)) 38 | } 39 | idx.method("Edges", edges...) 40 | } 41 | return idx.curr, nil 42 | } 43 | 44 | // AppendIndex adds an index to the returned values of the Indexes method of type typeName. 45 | func (c *Context) AppendIndex(typeName string, idx ent.Index) error { 46 | newIdx, err := Index(idx.Descriptor()) 47 | if err != nil { 48 | return err 49 | } 50 | return c.appendReturnItem(kindIndex, typeName, newIdx) 51 | } 52 | 53 | func newIndexCall(desc *index.Descriptor) *builderCall { 54 | var fields []ast.Expr 55 | for _, fld := range desc.Fields { 56 | fields = append(fields, strLit(fld)) 57 | } 58 | return &builderCall{ 59 | curr: &ast.CallExpr{ 60 | Fun: &ast.SelectorExpr{ 61 | X: ast.NewIdent("index"), 62 | Sel: ast.NewIdent("Fields"), 63 | }, 64 | Args: fields, 65 | }, 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /internal/schemast/kind.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-present Facebook 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package schemast 16 | 17 | import "go/ast" 18 | 19 | // kind stores configuration relevant to processing AST for different kinds of ent schema attributes 20 | // (fields, edges, annotation, etc.). 21 | type kind struct { 22 | // methodName is the name of the method on the schema that returns this kind. 23 | // For example, the "Fields" method returns the list of fields that a schema has. 24 | methodName string 25 | 26 | // ifaceSelector is the selector expression representing the type that is returned by the method. 27 | // For example, the Fields method returns a slice of "ent.Field". 28 | ifaceSelector *ast.SelectorExpr 29 | } 30 | 31 | var ( 32 | kindEdge = kind{ 33 | methodName: "Edges", 34 | ifaceSelector: selectorLit("ent", "Edge"), 35 | } 36 | kindField = kind{ 37 | methodName: "Fields", 38 | ifaceSelector: selectorLit("ent", "Field"), 39 | } 40 | kindMixin = kind{ 41 | methodName: "Mixin", 42 | ifaceSelector: selectorLit("ent", "Mixin"), 43 | } 44 | kindAnnot = kind{ 45 | methodName: "Annotations", 46 | ifaceSelector: selectorLit("schema", "Annotation"), 47 | } 48 | kindIndex = kind{ 49 | methodName: "Indexes", 50 | ifaceSelector: selectorLit("ent", "Index"), 51 | } 52 | ) 53 | -------------------------------------------------------------------------------- /internal/schemast/mixin.go: -------------------------------------------------------------------------------- 1 | package schemast 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | "reflect" 7 | "strings" 8 | 9 | "entgo.io/ent" 10 | ) 11 | 12 | // AppendMixin adds a mixin to the returned values of the Mixins method of type typeName. 13 | func (c *Context) AppendMixin(typeName string, mix ent.Mixin) error { 14 | mixType := reflect.TypeOf(mix) 15 | _ = mixType 16 | name := mixType.Name() 17 | path := mixType.PkgPath() 18 | 19 | split := strings.Split(path, "/") 20 | pkg := split[len(split)-1] 21 | 22 | var lit *ast.CompositeLit 23 | if pkg != c.SchemaPackage.Name { 24 | c.appendImport(typeName, fmt.Sprintf("\"%s\"", path)) 25 | lit = structLit(&ast.SelectorExpr{ 26 | X: ast.NewIdent(pkg), 27 | Sel: ast.NewIdent(name), 28 | }) 29 | } else { 30 | lit = structLit(ast.NewIdent(name)) 31 | } 32 | 33 | return c.appendReturnItem(kindMixin, typeName, lit) 34 | } 35 | -------------------------------------------------------------------------------- /internal/schemast/print.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-present Facebook 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package schemast 16 | 17 | import ( 18 | "bytes" 19 | "context" 20 | "go/printer" 21 | "os" 22 | "path/filepath" 23 | "regexp" 24 | 25 | "golang.org/x/sync/errgroup" 26 | "golang.org/x/tools/imports" 27 | ) 28 | 29 | // PrintOption modifies the behavior of Print. 30 | type PrintOption func(opt *printOpts) 31 | 32 | // Print writes the updated .go files from Context into path, the directory for the "schema" package in an 33 | // ent project. Print receives functional options of type PrintOption that modify its behavior. 34 | func (c *Context) Print(path string, opts ...PrintOption) error { 35 | options := &printOpts{} 36 | for _, apply := range opts { 37 | apply(options) 38 | } 39 | g, _ := errgroup.WithContext(context.Background()) 40 | for _, file := range c.syntax() { 41 | g.Go(func() error { 42 | var buf bytes.Buffer 43 | base := filepath.Base(c.SchemaPackage.Fset.File(file.Pos()).Name()) 44 | if err := printer.Fprint(&buf, c.SchemaPackage.Fset, file); err != nil { 45 | return err 46 | } 47 | process, err := imports.Process(base, buf.Bytes(), nil) 48 | if err != nil { 49 | return err 50 | } 51 | if options.headerComment != "" { 52 | if s := string(process); s != "" && options.commentRegexp.FindString(s) == "" { 53 | process = []byte(options.headerComment + "\n\n" + s) 54 | } 55 | } 56 | if err = os.WriteFile(filepath.Join(path, base), process, 0o600); err != nil { 57 | return err 58 | } 59 | return nil 60 | }) 61 | } 62 | 63 | return g.Wait() 64 | } 65 | 66 | // Header modifies Print to include a comment at the top of the printed .go files. 67 | // If the file already contains the comment, even if it is not located at the very top of the file 68 | // the comment will not be appended. 69 | // Example: 70 | // 71 | // ctx.Print("./schema", schemast.Header("File generated with ent-codegen-plugin.") 72 | func Header(c string) PrintOption { 73 | return func(opt *printOpts) { 74 | opt.headerComment = "// " + c 75 | opt.commentRegexp = regexp.MustCompile("(?m)^" + opt.headerComment + "$") 76 | } 77 | } 78 | 79 | type printOpts struct { 80 | headerComment string 81 | commentRegexp *regexp.Regexp 82 | } 83 | -------------------------------------------------------------------------------- /opType.go: -------------------------------------------------------------------------------- 1 | package enthistory 2 | 3 | import ( 4 | "database/sql/driver" 5 | "fmt" 6 | "io" 7 | "strconv" 8 | ) 9 | 10 | type OpType string 11 | 12 | const ( 13 | OpTypeInsert OpType = "INSERT" 14 | OpTypeUpdate OpType = "UPDATE" 15 | OpTypeDelete OpType = "DELETE" 16 | ) 17 | 18 | var opTypes = []string{ 19 | OpTypeInsert.String(), 20 | OpTypeUpdate.String(), 21 | OpTypeDelete.String(), 22 | } 23 | 24 | // Values provides list valid values for Enum. 25 | func (OpType) Values() (kinds []string) { 26 | kinds = append(kinds, opTypes...) 27 | return 28 | } 29 | 30 | func (op OpType) Value() (driver.Value, error) { 31 | return op.String(), nil 32 | } 33 | 34 | func (op OpType) String() string { 35 | return string(op) 36 | } 37 | 38 | func (op OpType) MarshalGQL(w io.Writer) { 39 | _, _ = w.Write([]byte(strconv.Quote(op.String()))) 40 | } 41 | 42 | // UnmarshalGQL implements graphql.Unmarshaler interface. 43 | func (op *OpType) UnmarshalGQL(val any) error { 44 | str, ok := val.(string) 45 | if !ok { 46 | return fmt.Errorf("enum %T must be a string", val) 47 | } 48 | *op = OpType(str) 49 | 50 | switch *op { 51 | case OpTypeInsert, OpTypeUpdate, OpTypeDelete: 52 | return nil 53 | default: 54 | return fmt.Errorf("%s is not a valid history operation type", str) 55 | } 56 | } 57 | 58 | func (op OpType) Name() (string, error) { 59 | switch op { 60 | case OpTypeInsert: 61 | return "OpTypeInsert", nil 62 | case OpTypeUpdate: 63 | return "OpTypeUpdate", nil 64 | case OpTypeDelete: 65 | return "OpTypeDelete", nil 66 | default: 67 | return "", fmt.Errorf("%s is not a valid history operation type", op) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /scripts/tag.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | 5 | LAST_TAG=$(git describe --tags --abbrev=0) 6 | echo "Last tag: $LAST_TAG" 7 | V_PREFIX=false 8 | if [[ $LAST_TAG == v* ]]; then 9 | V_PREFIX=true 10 | LAST_TAG="${LAST_TAG#v}" # Remove the 'v' prefix 11 | fi 12 | 13 | LAST_TAG_PARTS=(${LAST_TAG//./ }) 14 | LAST_MAJOR=${LAST_TAG_PARTS[0]} 15 | LAST_MINOR=${LAST_TAG_PARTS[1]} 16 | LAST_PATCH=${LAST_TAG_PARTS[2]} 17 | 18 | 19 | FEATURES=$(git log "$(git describe --tags --abbrev=0)"..HEAD --oneline --grep='feat:') 20 | FIXES=$(git log "$(git describe --tags --abbrev=0)"..HEAD --oneline --grep='fix:') 21 | CHORES=$(git log "$(git describe --tags --abbrev=0)"..HEAD --oneline --grep='chore:') 22 | 23 | if [[ -z "$FEATURES" && -z "$FIXES" && -z "$CHORES" ]]; then 24 | echo "No changes since last tag" 25 | exit 0 26 | fi 27 | 28 | # Check if feature is not empty 29 | if [[ -n "$FEATURES" ]]; then 30 | echo "Minor version bump" 31 | NEXT_MAJOR=$LAST_MAJOR 32 | NEXT_MINOR="$((10#$LAST_MINOR + 1))" 33 | NEXT_PATCH="0" 34 | elif [[ -n "$FIXES" || -n "$CHORES" ]]; then 35 | echo "Patch version bump" 36 | NEXT_MAJOR=$LAST_MAJOR 37 | NEXT_MINOR=$LAST_MINOR 38 | NEXT_PATCH="$((10#$LAST_PATCH + 1))" 39 | fi 40 | 41 | NEXT_TAG="$NEXT_MAJOR.$NEXT_MINOR.$NEXT_PATCH" 42 | if [[ $V_PREFIX == true ]]; then 43 | NEXT_TAG="v$NEXT_TAG" 44 | fi 45 | echo "Next tag: $NEXT_TAG" 46 | 47 | git tag -a "$NEXT_TAG" -m "$NEXT_TAG" 48 | git push origin "$NEXT_TAG" 49 | -------------------------------------------------------------------------------- /templates/client.tmpl: -------------------------------------------------------------------------------- 1 | {{/* gotype: entgo.io/ent/entc/gen.Graph */}} 2 | 3 | {{ define "client/init" }} 4 | // Client is the client that holds all ent builders. 5 | type Client struct { 6 | config 7 | {{- if $.SupportMigrate }} 8 | // Schema is the client for creating, migrating and dropping schema. 9 | Schema *migrate.Schema 10 | {{- end }} 11 | {{- range $n := $.Nodes }} 12 | // {{ $n.Name }} is the client for interacting with the {{ $n.Name }} builders. 13 | {{ $n.Name }} *{{ $n.ClientName }} 14 | {{- end }} 15 | {{- template "client/fields/additional" $ }} 16 | {{- with $tmpls := matchTemplate "client/fields/additional/*" }} 17 | {{- range $tmpl := $tmpls }} 18 | {{- xtemplate $tmpl $ }} 19 | {{- end }} 20 | {{- end }} 21 | // historyActivated determines if the history hooks have already been activated 22 | historyActivated bool 23 | } 24 | 25 | // NewClient creates a new client configured with the given options. 26 | func NewClient(opts ...Option) *Client { 27 | cfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}} 28 | cfg.options(opts...) 29 | client := &Client{config: cfg} 30 | client.init() 31 | return client 32 | } 33 | 34 | func (c *Client) init() { 35 | {{- if $.SupportMigrate }} 36 | c.Schema = migrate.NewSchema(c.driver) 37 | {{- end }} 38 | {{- range $n := $.Nodes }} 39 | c.{{ $n.Name }} = New{{ $n.ClientName }}(c.config) 40 | {{- end }} 41 | } 42 | 43 | // withHistory adds the history hooks to the appropriate schemas - generated by enthistory 44 | func (c *Client) WithHistory() { 45 | if !c.historyActivated { 46 | {{- range $n := $.Nodes }} 47 | {{- $name := $n.Name }} 48 | {{- $history := hasSuffix $name "History" }} 49 | {{- if $history }} 50 | {{- else }} 51 | {{- range $h := $.Nodes }} 52 | {{- $sameNodeType := hasPrefix $h.Name (printf "%sHistory" $name) }} 53 | {{- if $sameNodeType }} 54 | {{ calculateHooks $n $h }} 55 | {{- end }} 56 | {{- end }} 57 | {{- end }} 58 | {{- end }} 59 | c.historyActivated = true 60 | } 61 | } 62 | 63 | {{ end }} 64 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package enthistory 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func deref[T any](t *T) T { 8 | var zero T 9 | if t == nil { 10 | return zero 11 | } 12 | return *t 13 | } 14 | 15 | func typedSliceToType[T any, U any](records []T) ([]U, error) { 16 | res := make([]U, len(records)) 17 | for i, record := range records { 18 | a := any(record) 19 | if b, ok := a.(U); ok { 20 | res[i] = b 21 | } else { 22 | return nil, fmt.Errorf("failed to convert %T to %T", a, b) 23 | } 24 | } 25 | return res, nil 26 | } 27 | 28 | func reduce[T any, R any](collection []T, accumulator func(agg R, item T) R, initial R) R { 29 | for _, item := range collection { 30 | initial = accumulator(initial, item) 31 | } 32 | 33 | return initial 34 | } 35 | --------------------------------------------------------------------------------