diff --git a/.github/workflows/pr-auto-create.yml b/.github/workflows/pr-auto-create.yml index 409da09..507daeb 100644 --- a/.github/workflows/pr-auto-create.yml +++ b/.github/workflows/pr-auto-create.yml @@ -30,10 +30,11 @@ jobs: script: | let lastRelease = 'v0.0.0' try { - const { data: { tag_name: lastRelease } } = await github.rest.repos.getLatestRelease({ + const { data: { tag_name: fetchedLastRelease } } = await github.rest.repos.getLatestRelease({ owner: context.repo.owner, repo: context.repo.repo }) + lastRelease = fetchedLastRelease } catch (e) { console.log('No release found, creating first release') } diff --git a/cmd/app/app.go b/cmd/app/app.go index e6332ef..f96a113 100644 --- a/cmd/app/app.go +++ b/cmd/app/app.go @@ -6,7 +6,6 @@ import ( "github.com/rs/zerolog/log" "github.com/urfave/cli/v2" - "exusiai.dev/roguestats-backend/cmd/app/cli/db" "exusiai.dev/roguestats-backend/cmd/app/cli/script" "exusiai.dev/roguestats-backend/cmd/app/server" ) @@ -16,7 +15,6 @@ func Run() { Name: "app", Commands: []*cli.Command{ server.Command(), - db.Command(), script.Command(), }, } diff --git a/cmd/app/cli/db/command.go b/cmd/app/cli/db/command.go deleted file mode 100644 index 50bad22..0000000 --- a/cmd/app/cli/db/command.go +++ /dev/null @@ -1,101 +0,0 @@ -package db - -import ( - "strings" - - "github.com/uptrace/bun" - "github.com/uptrace/bun/migrate" - "github.com/urfave/cli/v2" - "go.uber.org/fx" - - cliapp "exusiai.dev/roguestats-backend/cmd/app/cli" - "exusiai.dev/roguestats-backend/internal/infra/db/migrations" -) - -type dbCommandDeps struct { - fx.In - - DB *bun.DB -} - -func Command() *cli.Command { - migrator := func() *migrations.Migrator { - var deps dbCommandDeps - cliapp.Start(fx.Populate(&deps)) - - m := migrate.NewMigrator(deps.DB, migrations.Migrations) - return migrations.NewMigrator(m) - } - - return &cli.Command{ - Name: "db", - Usage: "manage database migrations", - Subcommands: []*cli.Command{ - { - Name: "init", - Usage: "create migration tables", - Action: func(c *cli.Context) error { - return migrator().Init(c.Context) - }, - }, - { - Name: "migrate", - Usage: "migrate database", - Action: func(c *cli.Context) error { - return migrator().Migrate(c.Context) - }, - }, - { - Name: "rollback", - Usage: "rollback the last migration group", - Action: func(c *cli.Context) error { - return migrator().Rollback(c.Context) - }, - }, - { - Name: "lock", - Usage: "lock migrations", - Action: func(c *cli.Context) error { - return migrator().Lock(c.Context) - }, - }, - { - Name: "unlock", - Usage: "unlock migrations", - Action: func(c *cli.Context) error { - return migrator().Unlock(c.Context) - }, - }, - { - Name: "create_go", - Usage: "create Go migration", - Action: func(c *cli.Context) error { - name := strings.Join(c.Args().Slice(), "_") - return migrator().CreateGoMigration(c.Context, name) - }, - }, - { - Name: "create_sql", - Usage: "create up and down SQL migrations", - Action: func(c *cli.Context) error { - name := strings.Join(c.Args().Slice(), "_") - return migrator().CreateSQLMigrations(c.Context, name) - }, - }, - { - Name: "status", - Usage: "print migrations status", - Action: func(c *cli.Context) error { - return migrator().Status(c.Context) - }, - }, - { - Name: "mark_applied", - Usage: "mark migrations as applied without actually running them", - Action: func(c *cli.Context) error { - return migrator().MarkApplied(c.Context) - }, - }, - }, - } -} diff --git a/cmd/app/cli/script/battle_csv_import.go b/cmd/app/cli/script/battle_csv_import.go index 0796a9f..6fa8252 100644 --- a/cmd/app/cli/script/battle_csv_import.go +++ b/cmd/app/cli/script/battle_csv_import.go @@ -29,8 +29,8 @@ func (c *BattleCSVImport) Run() error { return nil } -func (c *BattleCSVImport) convertRowToContent(row []string) map[string]interface{} { - content := make(map[string]interface{}) +func (c *BattleCSVImport) convertRowToContent(row []string) map[string]any { + content := make(map[string]any) columnHandler := GetColumnHandler() band := columnHandler.HandleBand(strings.TrimSpace(row[1])) diff --git a/cmd/app/cli/script/column_handler.go b/cmd/app/cli/script/column_handler.go index 896be7b..c7171c0 100644 --- a/cmd/app/cli/script/column_handler.go +++ b/cmd/app/cli/script/column_handler.go @@ -5,7 +5,7 @@ import ( "strings" "sync" - "gopkg.in/guregu/null.v3" + "gopkg.in/guregu/null.v4" ) type ColumnHandler struct { @@ -18,8 +18,10 @@ type ColumnHandler struct { layoutMap map[string]string } -var columnHandlerInstance *ColumnHandler -var columnHanlderOnce sync.Once +var ( + columnHandlerInstance *ColumnHandler + columnHanlderOnce sync.Once +) func GetColumnHandler() *ColumnHandler { columnHanlderOnce.Do(func() { diff --git a/cmd/app/cli/script/import_util.go b/cmd/app/cli/script/import_util.go index 19bc5cf..84bd450 100644 --- a/cmd/app/cli/script/import_util.go +++ b/cmd/app/cli/script/import_util.go @@ -6,9 +6,8 @@ import ( "log" "os" - "github.com/machinebox/graphql" - "exusiai.dev/roguestats-backend/internal/model" + "github.com/machinebox/graphql" ) func ReadCSVFile(filePath string) [][]string { @@ -25,25 +24,25 @@ func ReadCSVFile(filePath string) [][]string { return records } -func PostEvent(content map[string]interface{}, researchID string) { +func PostEvent(content map[string]any, researchID string) { client := graphql.NewClient("http://localhost:3500/graphql") req := graphql.NewRequest(` - mutation CreateEvent($newEvent: NewEvent!) { - createEvent(input: $newEvent) { + mutation CreateEvent($input: CreateEventInput!) { + createEvent(input: $input) { content } }`, ) userAgent := "cli" - newEvent := model.NewEvent{ + input := model.CreateEventInput{ Content: content, ResearchID: researchID, - UserAgent: &userAgent, + UserAgent: userAgent, } - req.Var("newEvent", newEvent) - // req.Header.Set("Authorization", "") + req.Var("input", input) + req.Header.Set("Authorization", "Bearer eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJyb2d1ZXN0YXRzIiwiZXhwIjoxNjk0MjA0MjY1LCJpYXQiOjE2OTI5OTQ2NjUsImlzcyI6InJvZ3Vlc3RhdHMvdjAuMC4wIiwibmJmIjoxNjkyOTk0NjY1LCJzdWIiOiIwMWg4cTVlYnJuNWV0aG0xcDZ6anhyOWVmdyJ9.AHlIYrx7tKj6nnXO4MYRd_0mXqzOVWPyG6FHidPitfI2IbrtZI3-lXA-bZP_nl0Op7d4TgzacdYwJPDgYGLoZcznAfopT-ahoHmDZrflhrK-Soo8ji7OZENjOIH5VetkkTaKl9zuqdAivds4DQPefSYngsn5vqzIgIZhaoR8nJoaq6MT") ctx := context.Background() - var respData interface{} + var respData any if err := client.Run(ctx, req, &respData); err != nil { log.Fatal(err) } diff --git a/cmd/app/cli/script/incident_csv_import.go b/cmd/app/cli/script/incident_csv_import.go index 39bddfc..9e4bc6b 100644 --- a/cmd/app/cli/script/incident_csv_import.go +++ b/cmd/app/cli/script/incident_csv_import.go @@ -29,8 +29,8 @@ func (c *IncidentCSVImport) Run() error { return nil } -func (c *IncidentCSVImport) convertRowToContent(row []string) map[string]interface{} { - content := make(map[string]interface{}) +func (c *IncidentCSVImport) convertRowToContent(row []string) map[string]any { + content := make(map[string]any) columnHandler := GetColumnHandler() grade := columnHandler.HandleInt(strings.TrimSpace(row[1])) diff --git a/cmd/app/cli/script/portal_csv_import.go b/cmd/app/cli/script/portal_csv_import.go index 9ffa81b..6e875bf 100644 --- a/cmd/app/cli/script/portal_csv_import.go +++ b/cmd/app/cli/script/portal_csv_import.go @@ -29,8 +29,8 @@ func (c *PortalCSVImport) Run() error { return nil } -func (c *PortalCSVImport) convertRowToContent(row []string) map[string]interface{} { - content := make(map[string]interface{}) +func (c *PortalCSVImport) convertRowToContent(row []string) map[string]any { + content := make(map[string]any) columnHandler := GetColumnHandler() grade := columnHandler.HandleInt(strings.TrimSpace(row[1])) diff --git a/cmd/app/cli/script/rest_csv_import.go b/cmd/app/cli/script/rest_csv_import.go index fde5dd8..55589f0 100644 --- a/cmd/app/cli/script/rest_csv_import.go +++ b/cmd/app/cli/script/rest_csv_import.go @@ -29,8 +29,8 @@ func (c *RestCSVImport) Run() error { return nil } -func (c *RestCSVImport) convertRowToContent(row []string) map[string]interface{} { - content := make(map[string]interface{}) +func (c *RestCSVImport) convertRowToContent(row []string) map[string]any { + content := make(map[string]any) columnHandler := GetColumnHandler() grade := columnHandler.HandleInt(strings.TrimSpace(row[1])) diff --git a/generate.go b/generate.go new file mode 100644 index 0000000..03cc4ef --- /dev/null +++ b/generate.go @@ -0,0 +1,4 @@ +package main + +//go:generate go run -mod=mod ./internal/ent/entc.go +//go:generate go run -mod=mod github.com/99designs/gqlgen diff --git a/go.mod b/go.mod index 4b8a10f..994c8e7 100644 --- a/go.mod +++ b/go.mod @@ -3,32 +3,45 @@ module exusiai.dev/roguestats-backend go 1.19 require ( + entgo.io/contrib v0.4.6-0.20230725054517-9e1dadfef7fa + entgo.io/ent v0.12.3 github.com/99designs/gqlgen v0.17.36 github.com/antonmedv/expr v1.14.3 - github.com/bwmarrin/snowflake v0.3.0 github.com/dchest/uniuri v1.2.0 github.com/gofiber/adaptor/v2 v2.2.1 github.com/gofiber/fiber/v2 v2.48.0 github.com/golang-jwt/jwt/v5 v5.0.0 + github.com/hashicorp/go-multierror v1.1.1 github.com/joho/godotenv v1.5.1 github.com/kelseyhightower/envconfig v1.4.0 + github.com/lib/pq v1.10.9 github.com/machinebox/graphql v0.2.2 github.com/oklog/ulid/v2 v2.1.0 github.com/pkg/errors v0.9.1 github.com/resendlabs/resend-go v1.7.0 github.com/rs/zerolog v1.30.0 - github.com/uptrace/bun v1.1.14 - github.com/uptrace/bun/dialect/pgdialect v1.1.14 - github.com/uptrace/bun/driver/pgdriver v1.1.14 github.com/urfave/cli/v2 v2.25.7 github.com/vektah/gqlparser/v2 v2.5.8 go.uber.org/fx v1.20.0 golang.org/x/crypto v0.12.0 - gopkg.in/guregu/null.v3 v3.5.0 gopkg.in/guregu/null.v4 v4.0.0 ) -require github.com/matryer/is v1.4.1 // indirect +require ( + ariga.io/atlas v0.10.2-0.20230427182402-87a07dfb83bf // indirect + github.com/agext/levenshtein v1.2.1 // indirect + github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/go-openapi/inflect v0.19.0 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/hcl/v2 v2.13.0 // indirect + github.com/matryer/is v1.4.1 // indirect + github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/zclconf/go-cty v1.8.0 // indirect + golang.org/x/exp v0.0.0-20221230185412-738e83a70c30 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect +) require ( github.com/agnivade/levenshtein v1.1.1 // indirect @@ -37,7 +50,6 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.3 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect github.com/klauspost/compress v1.16.3 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect @@ -46,21 +58,19 @@ require ( github.com/rivo/uniseg v0.2.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 - github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.48.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - go.uber.org/atomic v1.7.0 // indirect + go.uber.org/atomic v1.10.0 // indirect go.uber.org/dig v1.17.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.23.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + go.uber.org/zap v1.24.0 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/sys v0.11.0 // indirect golang.org/x/text v0.12.0 // indirect golang.org/x/tools v0.9.3 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - mellium.im/sasl v0.3.1 // indirect ) diff --git a/go.sum b/go.sum index 3990efb..e2bef57 100644 --- a/go.sum +++ b/go.sum @@ -1,20 +1,27 @@ +ariga.io/atlas v0.10.2-0.20230427182402-87a07dfb83bf h1:Tq2DRB39ZHScIwWACjPKLv5oEErv7zv6PBb5RTz5CKA= +ariga.io/atlas v0.10.2-0.20230427182402-87a07dfb83bf/go.mod h1:+TR129FJZ5Lvzms6dvCeGWh1yR6hMvmXBhug4hrNIGk= +entgo.io/contrib v0.4.6-0.20230725054517-9e1dadfef7fa h1:0wlS+DGEFEnnxfEVVxNpwnms12U+V5N1uTOhxITnqkY= +entgo.io/contrib v0.4.6-0.20230725054517-9e1dadfef7fa/go.mod h1:CUOp0ujdvm4vp2ItkoOujjLqXVulRvic3kyhmyY2kas= +entgo.io/ent v0.12.3 h1:N5lO2EOrHpCH5HYfiMOCHYbo+oh5M8GjT0/cx5x6xkk= +entgo.io/ent v0.12.3/go.mod h1:AigGGx+tbrBBYHAzGOg8ND661E5cxx1Uiu5o/otJ6Yg= github.com/99designs/gqlgen v0.17.36 h1:u/o/rv2SZ9s5280dyUOOrkpIIkr/7kITMXYD3rkJ9go= github.com/99designs/gqlgen v0.17.36/go.mod h1:6RdyY8puhCoWAQVr2qzF2OMVfudQzc8ACxzpzluoQm4= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= +github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antonmedv/expr v1.14.2 h1:3gSOv3dGHPjou5yXNTM85KPEGMj0rAf2GpsMD4H7Js0= -github.com/antonmedv/expr v1.14.2/go.mod h1:FPC8iWArxls7axbVLsW+kpg1mz29A1b2M6jt+hZfDkU= github.com/antonmedv/expr v1.14.3 h1:GPrP7xKPWkFaLANPS7tPrgkNs7FMHpZdL72Dc5kFykg= github.com/antonmedv/expr v1.14.3/go.mod h1:FPC8iWArxls7axbVLsW+kpg1mz29A1b2M6jt+hZfDkU= +github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= -github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -25,6 +32,9 @@ github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g= github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= +github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= +github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofiber/adaptor/v2 v2.2.1 h1:givE7iViQWlsTR4Jh7tB4iXzrlKBgiraB/yTdHs9Lv4= github.com/gofiber/adaptor/v2 v2.2.1/go.mod h1:AhR16dEqs25W2FY/l8gSj1b51Azg5dtPDmm+pruNOrc= @@ -32,24 +42,37 @@ github.com/gofiber/fiber/v2 v2.48.0 h1:cRVMCb9aUJDsyHxGFLwz/sGzDggdailZZyptU9F9c github.com/gofiber/fiber/v2 v2.48.0/go.mod h1:xqJgfqrc23FJuqGOW6DVgi3HyZEm2Mn9pRqUb2kHSX8= github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru/v2 v2.0.3 h1:kmRrRLlInXvng0SmLxmQpQkpbYAvcXm7NPDrgxJa9mE= github.com/hashicorp/golang-lru/v2 v2.0.3/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc= +github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/machinebox/graphql v0.2.2 h1:dWKpJligYKhYKO5A2gvNhkJdQMNZeChZYyBbrZkBZfo= github.com/machinebox/graphql v0.2.2/go.mod h1:F+kbVMHuwrQ5tYgU9JXlnskM8nOaFxCAEolaQybkjWA= github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= @@ -63,9 +86,13 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= @@ -88,20 +115,12 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= -github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= -github.com/uptrace/bun v1.1.14 h1:S5vvNnjEynJ0CvnrBOD7MIRW7q/WbtvFXrdfy0lddAM= -github.com/uptrace/bun v1.1.14/go.mod h1:RHk6DrIisO62dv10pUOJCz5MphXThuOTpVNYEYv7NI8= -github.com/uptrace/bun/dialect/pgdialect v1.1.14 h1:b7+V1KDJPQSFYgkG/6YLXCl2uvwEY3kf/GSM7hTHRDY= -github.com/uptrace/bun/dialect/pgdialect v1.1.14/go.mod h1:v6YiaXmnKQ2FlhRD2c0ZfKd+QXH09pYn4H8ojaavkKk= -github.com/uptrace/bun/driver/pgdriver v1.1.14 h1:V2Etm7mLGS3mhx8ddxZcUnwZLX02Jmq9JTlo0sNVDhA= -github.com/uptrace/bun/driver/pgdriver v1.1.14/go.mod h1:D4FjWV9arDYct6sjMJhFoyU71SpllZRHXFRRP2Kd0Kw= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -112,49 +131,59 @@ github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVS github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vektah/gqlparser/v2 v2.5.8 h1:pm6WOnGdzFOCfcQo9L3+xzW51mKrlwTEg4Wr7AH1JW4= github.com/vektah/gqlparser/v2 v2.5.8/go.mod h1:z8xXUff237NntSuH8mLFijZ+1tjV1swDbpDqjJmk6ME= +github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA= +github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/exp v0.0.0-20221230185412-738e83a70c30 h1:m9O6OTJ627iFnN2JIWfdqlZCzneRO6EEBsHXI25P8ws= +golang.org/x/exp v0.0.0-20221230185412-738e83a70c30/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/guregu/null.v3 v3.5.0 h1:xTcasT8ETfMcUHn0zTvIYtQud/9Mx5dJqD554SZct0o= -gopkg.in/guregu/null.v3 v3.5.0/go.mod h1:E4tX2Qe3h7QdL+uZ3a0vqvYwKQsRSQKM5V4YltdgH9Y= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -162,5 +191,3 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo= -mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw= diff --git a/gqlgen.yml b/gqlgen.yml index dce1815..1d9781c 100644 --- a/gqlgen.yml +++ b/gqlgen.yml @@ -66,7 +66,11 @@ resolver: # gqlgen will search for any type names in the schema in these go packages # if they match it will use them, otherwise it will generate them. autobind: - - "exusiai.dev/roguestats-backend/internal/model" + - "exusiai.dev/roguestats-backend/internal/ent" + - "exusiai.dev/roguestats-backend/internal/ent/event" + - "exusiai.dev/roguestats-backend/internal/ent/research" + - "exusiai.dev/roguestats-backend/internal/ent/user" + - "exusiai.dev/roguestats-backend/internal/model" # This section declares type mapping between the GraphQL and go type systems # @@ -83,8 +87,11 @@ models: model: - github.com/99designs/gqlgen/graphql.Int - github.com/99designs/gqlgen/graphql.Int64 - User: - extraFields: - Credential: - description: "User's encrypted credential" - type: string \ No newline at end of file + Node: + model: + - exusiai.dev/roguestats-backend/internal/ent.Noder + # User: + # extraFields: + # Credential: + # description: "User's encrypted credential" + # type: string \ No newline at end of file diff --git a/internal/app/app.go b/internal/app/app.go index 986db00..714275f 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -8,7 +8,6 @@ import ( "exusiai.dev/roguestats-backend/internal/controller" "exusiai.dev/roguestats-backend/internal/infra" "exusiai.dev/roguestats-backend/internal/middleware" - "exusiai.dev/roguestats-backend/internal/repo" "exusiai.dev/roguestats-backend/internal/server" "exusiai.dev/roguestats-backend/internal/service" "exusiai.dev/roguestats-backend/internal/x/logger" @@ -31,7 +30,6 @@ func New(ctx appenv.Ctx, additionalOpts ...fx.Option) *fx.App { middleware.Module(), controller.Module(), infra.Module(), - repo.Module(), service.Module(), server.Module(), } diff --git a/internal/appcontext/appcontext.go b/internal/appcontext/appcontext.go index fb6f3b3..8a93708 100644 --- a/internal/appcontext/appcontext.go +++ b/internal/appcontext/appcontext.go @@ -3,36 +3,35 @@ package appcontext import ( "context" + "exusiai.dev/roguestats-backend/internal/ent" "github.com/gofiber/fiber/v2" - - "exusiai.dev/roguestats-backend/internal/model" ) var ( - ctxKeyCurrentUser = "currentUser" - ctxKeyFiberCtx = "fiberCtx" + CtxKeyCurrentUser ctxKey = "currentUser" + CtxKeyFiberCtx ctxKey = "fiberCtx" ) -// type ctxKey string +type ctxKey string -func CurrentUser(ctx context.Context) *model.User { - v := ctx.Value(ctxKeyCurrentUser) +func CurrentUser(ctx context.Context) *ent.User { + v := ctx.Value(CtxKeyCurrentUser) if v == nil { return nil } - u, ok := v.(*model.User) + u, ok := v.(*ent.User) if !ok { return nil } return u } -func WithCurrentUser(ctx context.Context, user *model.User) context.Context { - return context.WithValue(ctx, ctxKeyCurrentUser, user) +func WithCurrentUser(ctx context.Context, user *ent.User) context.Context { + return context.WithValue(ctx, CtxKeyCurrentUser, user) } func FiberCtx(ctx context.Context) *fiber.Ctx { - v := ctx.Value(ctxKeyFiberCtx) + v := ctx.Value(CtxKeyFiberCtx) if v == nil { return nil } @@ -44,5 +43,5 @@ func FiberCtx(ctx context.Context) *fiber.Ctx { } func WithFiberCtx(ctx context.Context, fiberCtx *fiber.Ctx) context.Context { - return context.WithValue(ctx, ctxKeyFiberCtx, fiberCtx) + return context.WithValue(ctx, CtxKeyFiberCtx, fiberCtx) } diff --git a/internal/blob/blob.go b/internal/blob/blob.go index ba10d16..6e944be 100644 --- a/internal/blob/blob.go +++ b/internal/blob/blob.go @@ -18,7 +18,7 @@ type RenderArtifact struct { } func RenderHTML(filename string, data any) (string, error) { - t, err := htmltmpl.ParseFS(content, "template/"+filename+".tmpl") + t, err := htmltmpl.ParseFS(content, "template/"+filename+".html.tmpl") if err != nil { return "", err } @@ -33,7 +33,7 @@ func RenderHTML(filename string, data any) (string, error) { } func RenderText(filename string, data any) (string, error) { - t, err := texttmpl.ParseFS(content, "template/"+filename+".tmpl") + t, err := texttmpl.ParseFS(content, "template/"+filename+".txt.tmpl") if err != nil { return "", err } diff --git a/internal/controller/graphql.go b/internal/controller/graphql.go index 25041f7..f601946 100644 --- a/internal/controller/graphql.go +++ b/internal/controller/graphql.go @@ -3,6 +3,7 @@ package controller import ( "time" + "entgo.io/contrib/entgql" "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/handler/extension" "github.com/99designs/gqlgen/graphql/handler/lru" @@ -12,6 +13,7 @@ import ( "github.com/gofiber/fiber/v2" "go.uber.org/fx" + "exusiai.dev/roguestats-backend/internal/ent" "exusiai.dev/roguestats-backend/internal/graph" "exusiai.dev/roguestats-backend/internal/middleware" "exusiai.dev/roguestats-backend/internal/service" @@ -23,6 +25,7 @@ type GraphQL struct { ResolverDeps graph.ResolverDeps Middleware middleware.Middleware DirectiveService service.Directive + Ent *ent.Client Route fiber.Router `name:"root"` } @@ -51,12 +54,8 @@ func RegisterGraphQL(c GraphQL) { srv.Use(extension.AutomaticPersistedQuery{ Cache: lru.New(100), }) + srv.Use(entgql.Transactioner{TxOpener: c.Ent}) c.Route.Get("/", adaptor.HTTPHandler(playground.Handler("GraphQL playground", "/graphql"))) - c.Route.Post("/graphql", func(c *fiber.Ctx) error { - // inject fiber context into *fasthttp.RequestCtx - ctx := c.Context() - ctx.SetUserValue("fiberCtx", c) - return c.Next() - }, c.Middleware.CurrentUser(), adaptor.HTTPHandler(srv)) + c.Route.Post("/graphql", c.Middleware.InjectFiberCtx(), c.Middleware.CurrentUser(), adaptor.HTTPHandler(srv)) } diff --git a/internal/cursorutils/encoding.go b/internal/cursorutils/encoding.go deleted file mode 100644 index 3a83156..0000000 --- a/internal/cursorutils/encoding.go +++ /dev/null @@ -1,15 +0,0 @@ -package cursorutils - -import "encoding/base64" - -func EncodeCursor(cursor string) string { - return base64.StdEncoding.EncodeToString([]byte(cursor)) -} - -func DecodeCursor(cursor string) (string, error) { - decodedCursor, err := base64.StdEncoding.DecodeString(cursor) - if err != nil { - return "", err - } - return string(decodedCursor), nil -} diff --git a/internal/ent/client.go b/internal/ent/client.go new file mode 100644 index 0000000..45f7e76 --- /dev/null +++ b/internal/ent/client.go @@ -0,0 +1,637 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "log" + + "exusiai.dev/roguestats-backend/internal/ent/migrate" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// Client is the client that holds all ent builders. +type Client struct { + config + // Schema is the client for creating, migrating and dropping schema. + Schema *migrate.Schema + // Event is the client for interacting with the Event builders. + Event *EventClient + // Research is the client for interacting with the Research builders. + Research *ResearchClient + // User is the client for interacting with the User builders. + User *UserClient +} + +// NewClient creates a new client configured with the given options. +func NewClient(opts ...Option) *Client { + cfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}} + cfg.options(opts...) + client := &Client{config: cfg} + client.init() + return client +} + +func (c *Client) init() { + c.Schema = migrate.NewSchema(c.driver) + c.Event = NewEventClient(c.config) + c.Research = NewResearchClient(c.config) + c.User = NewUserClient(c.config) +} + +type ( + // config is the configuration for the client and its builder. + config struct { + // driver used for executing database requests. + driver dialect.Driver + // debug enable a debug logging. + debug bool + // log used for logging on debug mode. + log func(...any) + // hooks to execute on mutations. + hooks *hooks + // interceptors to execute on queries. + inters *inters + } + // Option function to configure the client. + Option func(*config) +) + +// options applies the options on the config object. +func (c *config) options(opts ...Option) { + for _, opt := range opts { + opt(c) + } + if c.debug { + c.driver = dialect.Debug(c.driver, c.log) + } +} + +// Debug enables debug logging on the ent.Driver. +func Debug() Option { + return func(c *config) { + c.debug = true + } +} + +// Log sets the logging function for debug mode. +func Log(fn func(...any)) Option { + return func(c *config) { + c.log = fn + } +} + +// Driver configures the client driver. +func Driver(driver dialect.Driver) Option { + return func(c *config) { + c.driver = driver + } +} + +// Open opens a database/sql.DB specified by the driver name and +// the data source name, and returns a new client attached to it. +// Optional parameters can be added for configuring the client. +func Open(driverName, dataSourceName string, options ...Option) (*Client, error) { + switch driverName { + case dialect.MySQL, dialect.Postgres, dialect.SQLite: + drv, err := sql.Open(driverName, dataSourceName) + if err != nil { + return nil, err + } + return NewClient(append(options, Driver(drv))...), nil + default: + return nil, fmt.Errorf("unsupported driver: %q", driverName) + } +} + +// Tx returns a new transactional client. The provided context +// is used until the transaction is committed or rolled back. +func (c *Client) Tx(ctx context.Context) (*Tx, error) { + if _, ok := c.driver.(*txDriver); ok { + return nil, errors.New("ent: cannot start a transaction within a transaction") + } + tx, err := newTx(ctx, c.driver) + if err != nil { + return nil, fmt.Errorf("ent: starting a transaction: %w", err) + } + cfg := c.config + cfg.driver = tx + return &Tx{ + ctx: ctx, + config: cfg, + Event: NewEventClient(cfg), + Research: NewResearchClient(cfg), + User: NewUserClient(cfg), + }, nil +} + +// BeginTx returns a transactional client with specified options. +func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { + if _, ok := c.driver.(*txDriver); ok { + return nil, errors.New("ent: cannot start a transaction within a transaction") + } + tx, err := c.driver.(interface { + BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error) + }).BeginTx(ctx, opts) + if err != nil { + return nil, fmt.Errorf("ent: starting a transaction: %w", err) + } + cfg := c.config + cfg.driver = &txDriver{tx: tx, drv: c.driver} + return &Tx{ + ctx: ctx, + config: cfg, + Event: NewEventClient(cfg), + Research: NewResearchClient(cfg), + User: NewUserClient(cfg), + }, nil +} + +// Debug returns a new debug-client. It's used to get verbose logging on specific operations. +// +// client.Debug(). +// Event. +// Query(). +// Count(ctx) +func (c *Client) Debug() *Client { + if c.debug { + return c + } + cfg := c.config + cfg.driver = dialect.Debug(c.driver, c.log) + client := &Client{config: cfg} + client.init() + return client +} + +// Close closes the database connection and prevents new queries from starting. +func (c *Client) Close() error { + return c.driver.Close() +} + +// Use adds the mutation hooks to all the entity clients. +// In order to add hooks to a specific client, call: `client.Node.Use(...)`. +func (c *Client) Use(hooks ...Hook) { + c.Event.Use(hooks...) + c.Research.Use(hooks...) + c.User.Use(hooks...) +} + +// Intercept adds the query interceptors to all the entity clients. +// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`. +func (c *Client) Intercept(interceptors ...Interceptor) { + c.Event.Intercept(interceptors...) + c.Research.Intercept(interceptors...) + c.User.Intercept(interceptors...) +} + +// Mutate implements the ent.Mutator interface. +func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { + switch m := m.(type) { + case *EventMutation: + return c.Event.mutate(ctx, m) + case *ResearchMutation: + return c.Research.mutate(ctx, m) + case *UserMutation: + return c.User.mutate(ctx, m) + default: + return nil, fmt.Errorf("ent: unknown mutation type %T", m) + } +} + +// EventClient is a client for the Event schema. +type EventClient struct { + config +} + +// NewEventClient returns a client for the Event from the given config. +func NewEventClient(c config) *EventClient { + return &EventClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `event.Hooks(f(g(h())))`. +func (c *EventClient) Use(hooks ...Hook) { + c.hooks.Event = append(c.hooks.Event, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `event.Intercept(f(g(h())))`. +func (c *EventClient) Intercept(interceptors ...Interceptor) { + c.inters.Event = append(c.inters.Event, interceptors...) +} + +// Create returns a builder for creating a Event entity. +func (c *EventClient) Create() *EventCreate { + mutation := newEventMutation(c.config, OpCreate) + return &EventCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of Event entities. +func (c *EventClient) CreateBulk(builders ...*EventCreate) *EventCreateBulk { + return &EventCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for Event. +func (c *EventClient) Update() *EventUpdate { + mutation := newEventMutation(c.config, OpUpdate) + return &EventUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *EventClient) UpdateOne(e *Event) *EventUpdateOne { + mutation := newEventMutation(c.config, OpUpdateOne, withEvent(e)) + return &EventUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *EventClient) UpdateOneID(id string) *EventUpdateOne { + mutation := newEventMutation(c.config, OpUpdateOne, withEventID(id)) + return &EventUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for Event. +func (c *EventClient) Delete() *EventDelete { + mutation := newEventMutation(c.config, OpDelete) + return &EventDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *EventClient) DeleteOne(e *Event) *EventDeleteOne { + return c.DeleteOneID(e.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *EventClient) DeleteOneID(id string) *EventDeleteOne { + builder := c.Delete().Where(event.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &EventDeleteOne{builder} +} + +// Query returns a query builder for Event. +func (c *EventClient) Query() *EventQuery { + return &EventQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeEvent}, + inters: c.Interceptors(), + } +} + +// Get returns a Event entity by its id. +func (c *EventClient) Get(ctx context.Context, id string) (*Event, error) { + return c.Query().Where(event.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *EventClient) GetX(ctx context.Context, id string) *Event { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryUser queries the user edge of a Event. +func (c *EventClient) QueryUser(e *Event) *UserQuery { + query := (&UserClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := e.ID + step := sqlgraph.NewStep( + sqlgraph.From(event.Table, event.FieldID, id), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, event.UserTable, event.UserColumn), + ) + fromV = sqlgraph.Neighbors(e.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// QueryResearch queries the research edge of a Event. +func (c *EventClient) QueryResearch(e *Event) *ResearchQuery { + query := (&ResearchClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := e.ID + step := sqlgraph.NewStep( + sqlgraph.From(event.Table, event.FieldID, id), + sqlgraph.To(research.Table, research.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, event.ResearchTable, event.ResearchColumn), + ) + fromV = sqlgraph.Neighbors(e.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *EventClient) Hooks() []Hook { + return c.hooks.Event +} + +// Interceptors returns the client interceptors. +func (c *EventClient) Interceptors() []Interceptor { + return c.inters.Event +} + +func (c *EventClient) mutate(ctx context.Context, m *EventMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&EventCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&EventUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&EventUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&EventDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown Event mutation op: %q", m.Op()) + } +} + +// ResearchClient is a client for the Research schema. +type ResearchClient struct { + config +} + +// NewResearchClient returns a client for the Research from the given config. +func NewResearchClient(c config) *ResearchClient { + return &ResearchClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `research.Hooks(f(g(h())))`. +func (c *ResearchClient) Use(hooks ...Hook) { + c.hooks.Research = append(c.hooks.Research, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `research.Intercept(f(g(h())))`. +func (c *ResearchClient) Intercept(interceptors ...Interceptor) { + c.inters.Research = append(c.inters.Research, interceptors...) +} + +// Create returns a builder for creating a Research entity. +func (c *ResearchClient) Create() *ResearchCreate { + mutation := newResearchMutation(c.config, OpCreate) + return &ResearchCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of Research entities. +func (c *ResearchClient) CreateBulk(builders ...*ResearchCreate) *ResearchCreateBulk { + return &ResearchCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for Research. +func (c *ResearchClient) Update() *ResearchUpdate { + mutation := newResearchMutation(c.config, OpUpdate) + return &ResearchUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *ResearchClient) UpdateOne(r *Research) *ResearchUpdateOne { + mutation := newResearchMutation(c.config, OpUpdateOne, withResearch(r)) + return &ResearchUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *ResearchClient) UpdateOneID(id string) *ResearchUpdateOne { + mutation := newResearchMutation(c.config, OpUpdateOne, withResearchID(id)) + return &ResearchUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for Research. +func (c *ResearchClient) Delete() *ResearchDelete { + mutation := newResearchMutation(c.config, OpDelete) + return &ResearchDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *ResearchClient) DeleteOne(r *Research) *ResearchDeleteOne { + return c.DeleteOneID(r.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *ResearchClient) DeleteOneID(id string) *ResearchDeleteOne { + builder := c.Delete().Where(research.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &ResearchDeleteOne{builder} +} + +// Query returns a query builder for Research. +func (c *ResearchClient) Query() *ResearchQuery { + return &ResearchQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeResearch}, + inters: c.Interceptors(), + } +} + +// Get returns a Research entity by its id. +func (c *ResearchClient) Get(ctx context.Context, id string) (*Research, error) { + return c.Query().Where(research.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *ResearchClient) GetX(ctx context.Context, id string) *Research { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryEvents queries the events edge of a Research. +func (c *ResearchClient) QueryEvents(r *Research) *EventQuery { + query := (&EventClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := r.ID + step := sqlgraph.NewStep( + sqlgraph.From(research.Table, research.FieldID, id), + sqlgraph.To(event.Table, event.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, research.EventsTable, research.EventsColumn), + ) + fromV = sqlgraph.Neighbors(r.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *ResearchClient) Hooks() []Hook { + return c.hooks.Research +} + +// Interceptors returns the client interceptors. +func (c *ResearchClient) Interceptors() []Interceptor { + return c.inters.Research +} + +func (c *ResearchClient) mutate(ctx context.Context, m *ResearchMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&ResearchCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&ResearchUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&ResearchUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&ResearchDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown Research mutation op: %q", m.Op()) + } +} + +// UserClient is a client for the User schema. +type UserClient struct { + config +} + +// NewUserClient returns a client for the User from the given config. +func NewUserClient(c config) *UserClient { + return &UserClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `user.Hooks(f(g(h())))`. +func (c *UserClient) Use(hooks ...Hook) { + c.hooks.User = append(c.hooks.User, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `user.Intercept(f(g(h())))`. +func (c *UserClient) Intercept(interceptors ...Interceptor) { + c.inters.User = append(c.inters.User, interceptors...) +} + +// Create returns a builder for creating a User entity. +func (c *UserClient) Create() *UserCreate { + mutation := newUserMutation(c.config, OpCreate) + return &UserCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of User entities. +func (c *UserClient) CreateBulk(builders ...*UserCreate) *UserCreateBulk { + return &UserCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for User. +func (c *UserClient) Update() *UserUpdate { + mutation := newUserMutation(c.config, OpUpdate) + return &UserUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *UserClient) UpdateOne(u *User) *UserUpdateOne { + mutation := newUserMutation(c.config, OpUpdateOne, withUser(u)) + return &UserUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *UserClient) UpdateOneID(id string) *UserUpdateOne { + mutation := newUserMutation(c.config, OpUpdateOne, withUserID(id)) + return &UserUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for User. +func (c *UserClient) Delete() *UserDelete { + mutation := newUserMutation(c.config, OpDelete) + return &UserDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *UserClient) DeleteOne(u *User) *UserDeleteOne { + return c.DeleteOneID(u.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *UserClient) DeleteOneID(id string) *UserDeleteOne { + builder := c.Delete().Where(user.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &UserDeleteOne{builder} +} + +// Query returns a query builder for User. +func (c *UserClient) Query() *UserQuery { + return &UserQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeUser}, + inters: c.Interceptors(), + } +} + +// Get returns a User entity by its id. +func (c *UserClient) Get(ctx context.Context, id string) (*User, error) { + return c.Query().Where(user.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *UserClient) GetX(ctx context.Context, id string) *User { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryEvents queries the events edge of a User. +func (c *UserClient) QueryEvents(u *User) *EventQuery { + query := (&EventClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := u.ID + step := sqlgraph.NewStep( + sqlgraph.From(user.Table, user.FieldID, id), + sqlgraph.To(event.Table, event.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, user.EventsTable, user.EventsColumn), + ) + fromV = sqlgraph.Neighbors(u.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *UserClient) Hooks() []Hook { + return c.hooks.User +} + +// Interceptors returns the client interceptors. +func (c *UserClient) Interceptors() []Interceptor { + return c.inters.User +} + +func (c *UserClient) mutate(ctx context.Context, m *UserMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&UserCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&UserUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&UserUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&UserDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown User mutation op: %q", m.Op()) + } +} + +// hooks and interceptors per client, for fast access. +type ( + hooks struct { + Event, Research, User []ent.Hook + } + inters struct { + Event, Research, User []ent.Interceptor + } +) diff --git a/internal/ent/ent.go b/internal/ent/ent.go new file mode 100644 index 0000000..e24c49f --- /dev/null +++ b/internal/ent/ent.go @@ -0,0 +1,612 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "reflect" + "sync" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// ent aliases to avoid import conflicts in user's code. +type ( + Op = ent.Op + Hook = ent.Hook + Value = ent.Value + Query = ent.Query + QueryContext = ent.QueryContext + Querier = ent.Querier + QuerierFunc = ent.QuerierFunc + Interceptor = ent.Interceptor + InterceptFunc = ent.InterceptFunc + Traverser = ent.Traverser + TraverseFunc = ent.TraverseFunc + Policy = ent.Policy + Mutator = ent.Mutator + Mutation = ent.Mutation + MutateFunc = ent.MutateFunc +) + +type clientCtxKey struct{} + +// FromContext returns a Client stored inside a context, or nil if there isn't one. +func FromContext(ctx context.Context) *Client { + c, _ := ctx.Value(clientCtxKey{}).(*Client) + return c +} + +// NewContext returns a new context with the given Client attached. +func NewContext(parent context.Context, c *Client) context.Context { + return context.WithValue(parent, clientCtxKey{}, c) +} + +type txCtxKey struct{} + +// TxFromContext returns a Tx stored inside a context, or nil if there isn't one. +func TxFromContext(ctx context.Context) *Tx { + tx, _ := ctx.Value(txCtxKey{}).(*Tx) + return tx +} + +// NewTxContext returns a new context with the given Tx attached. +func NewTxContext(parent context.Context, tx *Tx) context.Context { + return context.WithValue(parent, txCtxKey{}, tx) +} + +// OrderFunc applies an ordering on the sql selector. +// Deprecated: Use Asc/Desc functions or the package builders instead. +type OrderFunc func(*sql.Selector) + +var ( + initCheck sync.Once + columnCheck sql.ColumnCheck +) + +// columnChecker checks if the column exists in the given table. +func checkColumn(table, column string) error { + initCheck.Do(func() { + columnCheck = sql.NewColumnCheck(map[string]func(string) bool{ + event.Table: event.ValidColumn, + research.Table: research.ValidColumn, + user.Table: user.ValidColumn, + }) + }) + return columnCheck(table, column) +} + +// Asc applies the given fields in ASC order. +func Asc(fields ...string) func(*sql.Selector) { + return func(s *sql.Selector) { + for _, f := range fields { + if err := checkColumn(s.TableName(), f); err != nil { + s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)}) + } + s.OrderBy(sql.Asc(s.C(f))) + } + } +} + +// Desc applies the given fields in DESC order. +func Desc(fields ...string) func(*sql.Selector) { + return func(s *sql.Selector) { + for _, f := range fields { + if err := checkColumn(s.TableName(), f); err != nil { + s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)}) + } + s.OrderBy(sql.Desc(s.C(f))) + } + } +} + +// AggregateFunc applies an aggregation step on the group-by traversal/selector. +type AggregateFunc func(*sql.Selector) string + +// As is a pseudo aggregation function for renaming another other functions with custom names. For example: +// +// GroupBy(field1, field2). +// Aggregate(ent.As(ent.Sum(field1), "sum_field1"), (ent.As(ent.Sum(field2), "sum_field2")). +// Scan(ctx, &v) +func As(fn AggregateFunc, end string) AggregateFunc { + return func(s *sql.Selector) string { + return sql.As(fn(s), end) + } +} + +// Count applies the "count" aggregation function on each group. +func Count() AggregateFunc { + return func(s *sql.Selector) string { + return sql.Count("*") + } +} + +// Max applies the "max" aggregation function on the given field of each group. +func Max(field string) AggregateFunc { + return func(s *sql.Selector) string { + if err := checkColumn(s.TableName(), field); err != nil { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) + return "" + } + return sql.Max(s.C(field)) + } +} + +// Mean applies the "mean" aggregation function on the given field of each group. +func Mean(field string) AggregateFunc { + return func(s *sql.Selector) string { + if err := checkColumn(s.TableName(), field); err != nil { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) + return "" + } + return sql.Avg(s.C(field)) + } +} + +// Min applies the "min" aggregation function on the given field of each group. +func Min(field string) AggregateFunc { + return func(s *sql.Selector) string { + if err := checkColumn(s.TableName(), field); err != nil { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) + return "" + } + return sql.Min(s.C(field)) + } +} + +// Sum applies the "sum" aggregation function on the given field of each group. +func Sum(field string) AggregateFunc { + return func(s *sql.Selector) string { + if err := checkColumn(s.TableName(), field); err != nil { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) + return "" + } + return sql.Sum(s.C(field)) + } +} + +// ValidationError returns when validating a field or edge fails. +type ValidationError struct { + Name string // Field or edge name. + err error +} + +// Error implements the error interface. +func (e *ValidationError) Error() string { + return e.err.Error() +} + +// Unwrap implements the errors.Wrapper interface. +func (e *ValidationError) Unwrap() error { + return e.err +} + +// IsValidationError returns a boolean indicating whether the error is a validation error. +func IsValidationError(err error) bool { + if err == nil { + return false + } + var e *ValidationError + return errors.As(err, &e) +} + +// NotFoundError returns when trying to fetch a specific entity and it was not found in the database. +type NotFoundError struct { + label string +} + +// Error implements the error interface. +func (e *NotFoundError) Error() string { + return "ent: " + e.label + " not found" +} + +// IsNotFound returns a boolean indicating whether the error is a not found error. +func IsNotFound(err error) bool { + if err == nil { + return false + } + var e *NotFoundError + return errors.As(err, &e) +} + +// MaskNotFound masks not found error. +func MaskNotFound(err error) error { + if IsNotFound(err) { + return nil + } + return err +} + +// NotSingularError returns when trying to fetch a singular entity and more then one was found in the database. +type NotSingularError struct { + label string +} + +// Error implements the error interface. +func (e *NotSingularError) Error() string { + return "ent: " + e.label + " not singular" +} + +// IsNotSingular returns a boolean indicating whether the error is a not singular error. +func IsNotSingular(err error) bool { + if err == nil { + return false + } + var e *NotSingularError + return errors.As(err, &e) +} + +// NotLoadedError returns when trying to get a node that was not loaded by the query. +type NotLoadedError struct { + edge string +} + +// Error implements the error interface. +func (e *NotLoadedError) Error() string { + return "ent: " + e.edge + " edge was not loaded" +} + +// IsNotLoaded returns a boolean indicating whether the error is a not loaded error. +func IsNotLoaded(err error) bool { + if err == nil { + return false + } + var e *NotLoadedError + return errors.As(err, &e) +} + +// ConstraintError returns when trying to create/update one or more entities and +// one or more of their constraints failed. For example, violation of edge or +// field uniqueness. +type ConstraintError struct { + msg string + wrap error +} + +// Error implements the error interface. +func (e ConstraintError) Error() string { + return "ent: constraint failed: " + e.msg +} + +// Unwrap implements the errors.Wrapper interface. +func (e *ConstraintError) Unwrap() error { + return e.wrap +} + +// IsConstraintError returns a boolean indicating whether the error is a constraint failure. +func IsConstraintError(err error) bool { + if err == nil { + return false + } + var e *ConstraintError + return errors.As(err, &e) +} + +// selector embedded by the different Select/GroupBy builders. +type selector struct { + label string + flds *[]string + fns []AggregateFunc + scan func(context.Context, any) error +} + +// ScanX is like Scan, but panics if an error occurs. +func (s *selector) ScanX(ctx context.Context, v any) { + if err := s.scan(ctx, v); err != nil { + panic(err) + } +} + +// Strings returns list of strings from a selector. It is only allowed when selecting one field. +func (s *selector) Strings(ctx context.Context) ([]string, error) { + if len(*s.flds) > 1 { + return nil, errors.New("ent: Strings is not achievable when selecting more than 1 field") + } + var v []string + if err := s.scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// StringsX is like Strings, but panics if an error occurs. +func (s *selector) StringsX(ctx context.Context) []string { + v, err := s.Strings(ctx) + if err != nil { + panic(err) + } + return v +} + +// String returns a single string from a selector. It is only allowed when selecting one field. +func (s *selector) String(ctx context.Context) (_ string, err error) { + var v []string + if v, err = s.Strings(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{s.label} + default: + err = fmt.Errorf("ent: Strings returned %d results when one was expected", len(v)) + } + return +} + +// StringX is like String, but panics if an error occurs. +func (s *selector) StringX(ctx context.Context) string { + v, err := s.String(ctx) + if err != nil { + panic(err) + } + return v +} + +// Ints returns list of ints from a selector. It is only allowed when selecting one field. +func (s *selector) Ints(ctx context.Context) ([]int, error) { + if len(*s.flds) > 1 { + return nil, errors.New("ent: Ints is not achievable when selecting more than 1 field") + } + var v []int + if err := s.scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// IntsX is like Ints, but panics if an error occurs. +func (s *selector) IntsX(ctx context.Context) []int { + v, err := s.Ints(ctx) + if err != nil { + panic(err) + } + return v +} + +// Int returns a single int from a selector. It is only allowed when selecting one field. +func (s *selector) Int(ctx context.Context) (_ int, err error) { + var v []int + if v, err = s.Ints(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{s.label} + default: + err = fmt.Errorf("ent: Ints returned %d results when one was expected", len(v)) + } + return +} + +// IntX is like Int, but panics if an error occurs. +func (s *selector) IntX(ctx context.Context) int { + v, err := s.Int(ctx) + if err != nil { + panic(err) + } + return v +} + +// Float64s returns list of float64s from a selector. It is only allowed when selecting one field. +func (s *selector) Float64s(ctx context.Context) ([]float64, error) { + if len(*s.flds) > 1 { + return nil, errors.New("ent: Float64s is not achievable when selecting more than 1 field") + } + var v []float64 + if err := s.scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// Float64sX is like Float64s, but panics if an error occurs. +func (s *selector) Float64sX(ctx context.Context) []float64 { + v, err := s.Float64s(ctx) + if err != nil { + panic(err) + } + return v +} + +// Float64 returns a single float64 from a selector. It is only allowed when selecting one field. +func (s *selector) Float64(ctx context.Context) (_ float64, err error) { + var v []float64 + if v, err = s.Float64s(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{s.label} + default: + err = fmt.Errorf("ent: Float64s returned %d results when one was expected", len(v)) + } + return +} + +// Float64X is like Float64, but panics if an error occurs. +func (s *selector) Float64X(ctx context.Context) float64 { + v, err := s.Float64(ctx) + if err != nil { + panic(err) + } + return v +} + +// Bools returns list of bools from a selector. It is only allowed when selecting one field. +func (s *selector) Bools(ctx context.Context) ([]bool, error) { + if len(*s.flds) > 1 { + return nil, errors.New("ent: Bools is not achievable when selecting more than 1 field") + } + var v []bool + if err := s.scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// BoolsX is like Bools, but panics if an error occurs. +func (s *selector) BoolsX(ctx context.Context) []bool { + v, err := s.Bools(ctx) + if err != nil { + panic(err) + } + return v +} + +// Bool returns a single bool from a selector. It is only allowed when selecting one field. +func (s *selector) Bool(ctx context.Context) (_ bool, err error) { + var v []bool + if v, err = s.Bools(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{s.label} + default: + err = fmt.Errorf("ent: Bools returned %d results when one was expected", len(v)) + } + return +} + +// BoolX is like Bool, but panics if an error occurs. +func (s *selector) BoolX(ctx context.Context) bool { + v, err := s.Bool(ctx) + if err != nil { + panic(err) + } + return v +} + +// withHooks invokes the builder operation with the given hooks, if any. +func withHooks[V Value, M any, PM interface { + *M + Mutation +}](ctx context.Context, exec func(context.Context) (V, error), mutation PM, hooks []Hook) (value V, err error) { + if len(hooks) == 0 { + return exec(ctx) + } + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutationT, ok := any(m).(PM) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + // Set the mutation to the builder. + *mutation = *mutationT + return exec(ctx) + }) + for i := len(hooks) - 1; i >= 0; i-- { + if hooks[i] == nil { + return value, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)") + } + mut = hooks[i](mut) + } + v, err := mut.Mutate(ctx, mutation) + if err != nil { + return value, err + } + nv, ok := v.(V) + if !ok { + return value, fmt.Errorf("unexpected node type %T returned from %T", v, mutation) + } + return nv, nil +} + +// setContextOp returns a new context with the given QueryContext attached (including its op) in case it does not exist. +func setContextOp(ctx context.Context, qc *QueryContext, op string) context.Context { + if ent.QueryFromContext(ctx) == nil { + qc.Op = op + ctx = ent.NewQueryContext(ctx, qc) + } + return ctx +} + +func querierAll[V Value, Q interface { + sqlAll(context.Context, ...queryHook) (V, error) +}]() Querier { + return QuerierFunc(func(ctx context.Context, q Query) (Value, error) { + query, ok := q.(Q) + if !ok { + return nil, fmt.Errorf("unexpected query type %T", q) + } + return query.sqlAll(ctx) + }) +} + +func querierCount[Q interface { + sqlCount(context.Context) (int, error) +}]() Querier { + return QuerierFunc(func(ctx context.Context, q Query) (Value, error) { + query, ok := q.(Q) + if !ok { + return nil, fmt.Errorf("unexpected query type %T", q) + } + return query.sqlCount(ctx) + }) +} + +func withInterceptors[V Value](ctx context.Context, q Query, qr Querier, inters []Interceptor) (v V, err error) { + for i := len(inters) - 1; i >= 0; i-- { + qr = inters[i].Intercept(qr) + } + rv, err := qr.Query(ctx, q) + if err != nil { + return v, err + } + vt, ok := rv.(V) + if !ok { + return v, fmt.Errorf("unexpected type %T returned from %T. expected type: %T", vt, q, v) + } + return vt, nil +} + +func scanWithInterceptors[Q1 ent.Query, Q2 interface { + sqlScan(context.Context, Q1, any) error +}](ctx context.Context, rootQuery Q1, selectOrGroup Q2, inters []Interceptor, v any) error { + rv := reflect.ValueOf(v) + var qr Querier = QuerierFunc(func(ctx context.Context, q Query) (Value, error) { + query, ok := q.(Q1) + if !ok { + return nil, fmt.Errorf("unexpected query type %T", q) + } + if err := selectOrGroup.sqlScan(ctx, query, v); err != nil { + return nil, err + } + if k := rv.Kind(); k == reflect.Pointer && rv.Elem().CanInterface() { + return rv.Elem().Interface(), nil + } + return v, nil + }) + for i := len(inters) - 1; i >= 0; i-- { + qr = inters[i].Intercept(qr) + } + vv, err := qr.Query(ctx, rootQuery) + if err != nil { + return err + } + switch rv2 := reflect.ValueOf(vv); { + case rv.IsNil(), rv2.IsNil(), rv.Kind() != reflect.Pointer: + case rv.Type() == rv2.Type(): + rv.Elem().Set(rv2.Elem()) + case rv.Elem().Type() == rv2.Type(): + rv.Elem().Set(rv2) + } + return nil +} + +// queryHook describes an internal hook for the different sqlAll methods. +type queryHook func(context.Context, *sqlgraph.QuerySpec) diff --git a/internal/ent/entc.go b/internal/ent/entc.go new file mode 100644 index 0000000..5b67ee6 --- /dev/null +++ b/internal/ent/entc.go @@ -0,0 +1,30 @@ +//go:build ignore + +package main + +import ( + "log" + + "entgo.io/contrib/entgql" + "entgo.io/ent/entc" + "entgo.io/ent/entc/gen" +) + +func main() { + ex, err := entgql.NewExtension( + // Tell Ent to generate a GraphQL schema for + // the Ent schema in a file named ent.graphql. + // entgql.WithSchemaGenerator(), + // entgql.WithSchemaPath("./internal/graph/defs/schema.graphqls"), + // entgql.WithConfigPath("gqlgen.yml"), + ) + if err != nil { + log.Fatalf("creating entgql extension: %v", err) + } + opts := []entc.Option{ + entc.Extensions(ex), + } + if err := entc.Generate("./internal/ent/schema", &gen.Config{}, opts...); err != nil { + log.Fatalf("running ent codegen: %v", err) + } +} diff --git a/internal/ent/enttest/enttest.go b/internal/ent/enttest/enttest.go new file mode 100644 index 0000000..54e4a5b --- /dev/null +++ b/internal/ent/enttest/enttest.go @@ -0,0 +1,84 @@ +// Code generated by ent, DO NOT EDIT. + +package enttest + +import ( + "context" + + "exusiai.dev/roguestats-backend/internal/ent" + // required by schema hooks. + _ "exusiai.dev/roguestats-backend/internal/ent/runtime" + + "entgo.io/ent/dialect/sql/schema" + "exusiai.dev/roguestats-backend/internal/ent/migrate" +) + +type ( + // TestingT is the interface that is shared between + // testing.T and testing.B and used by enttest. + TestingT interface { + FailNow() + Error(...any) + } + + // Option configures client creation. + Option func(*options) + + options struct { + opts []ent.Option + migrateOpts []schema.MigrateOption + } +) + +// WithOptions forwards options to client creation. +func WithOptions(opts ...ent.Option) Option { + return func(o *options) { + o.opts = append(o.opts, opts...) + } +} + +// WithMigrateOptions forwards options to auto migration. +func WithMigrateOptions(opts ...schema.MigrateOption) Option { + return func(o *options) { + o.migrateOpts = append(o.migrateOpts, opts...) + } +} + +func newOptions(opts []Option) *options { + o := &options{} + for _, opt := range opts { + opt(o) + } + return o +} + +// Open calls ent.Open and auto-run migration. +func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { + o := newOptions(opts) + c, err := ent.Open(driverName, dataSourceName, o.opts...) + if err != nil { + t.Error(err) + t.FailNow() + } + migrateSchema(t, c, o) + return c +} + +// NewClient calls ent.NewClient and auto-run migration. +func NewClient(t TestingT, opts ...Option) *ent.Client { + o := newOptions(opts) + c := ent.NewClient(o.opts...) + migrateSchema(t, c, o) + return c +} +func migrateSchema(t TestingT, c *ent.Client, o *options) { + tables, err := schema.CopyTables(migrate.Tables) + if err != nil { + t.Error(err) + t.FailNow() + } + if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { + t.Error(err) + t.FailNow() + } +} diff --git a/internal/ent/event.go b/internal/ent/event.go new file mode 100644 index 0000000..10ee170 --- /dev/null +++ b/internal/ent/event.go @@ -0,0 +1,205 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// Event is the model entity for the Event schema. +type Event struct { + config `json:"-"` + // ID of the ent. + ID string `json:"id,omitempty"` + // CreatedAt holds the value of the "created_at" field. + CreatedAt time.Time `json:"created_at,omitempty"` + // UserAgent holds the value of the "user_agent" field. + UserAgent string `json:"user_agent,omitempty"` + // Content holds the value of the "content" field. + Content map[string]interface{} `json:"content,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the EventQuery when eager-loading is set. + Edges EventEdges `json:"edges"` + research_events *string + user_events *string + selectValues sql.SelectValues +} + +// EventEdges holds the relations/edges for other nodes in the graph. +type EventEdges struct { + // User holds the value of the user edge. + User *User `json:"user,omitempty"` + // Research holds the value of the research edge. + Research *Research `json:"research,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [2]bool + // totalCount holds the count of the edges above. + totalCount [2]map[string]int +} + +// UserOrErr returns the User value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e EventEdges) UserOrErr() (*User, error) { + if e.loadedTypes[0] { + if e.User == nil { + // Edge was loaded but was not found. + return nil, &NotFoundError{label: user.Label} + } + return e.User, nil + } + return nil, &NotLoadedError{edge: "user"} +} + +// ResearchOrErr returns the Research value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e EventEdges) ResearchOrErr() (*Research, error) { + if e.loadedTypes[1] { + if e.Research == nil { + // Edge was loaded but was not found. + return nil, &NotFoundError{label: research.Label} + } + return e.Research, nil + } + return nil, &NotLoadedError{edge: "research"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*Event) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case event.FieldContent: + values[i] = new([]byte) + case event.FieldID, event.FieldUserAgent: + values[i] = new(sql.NullString) + case event.FieldCreatedAt: + values[i] = new(sql.NullTime) + case event.ForeignKeys[0]: // research_events + values[i] = new(sql.NullString) + case event.ForeignKeys[1]: // user_events + values[i] = new(sql.NullString) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the Event fields. +func (e *Event) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case event.FieldID: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field id", values[i]) + } else if value.Valid { + e.ID = value.String + } + case event.FieldCreatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field created_at", values[i]) + } else if value.Valid { + e.CreatedAt = value.Time + } + case event.FieldUserAgent: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field user_agent", values[i]) + } else if value.Valid { + e.UserAgent = value.String + } + case event.FieldContent: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field content", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &e.Content); err != nil { + return fmt.Errorf("unmarshal field content: %w", err) + } + } + case event.ForeignKeys[0]: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field research_events", values[i]) + } else if value.Valid { + e.research_events = new(string) + *e.research_events = value.String + } + case event.ForeignKeys[1]: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field user_events", values[i]) + } else if value.Valid { + e.user_events = new(string) + *e.user_events = value.String + } + default: + e.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the Event. +// This includes values selected through modifiers, order, etc. +func (e *Event) Value(name string) (ent.Value, error) { + return e.selectValues.Get(name) +} + +// QueryUser queries the "user" edge of the Event entity. +func (e *Event) QueryUser() *UserQuery { + return NewEventClient(e.config).QueryUser(e) +} + +// QueryResearch queries the "research" edge of the Event entity. +func (e *Event) QueryResearch() *ResearchQuery { + return NewEventClient(e.config).QueryResearch(e) +} + +// Update returns a builder for updating this Event. +// Note that you need to call Event.Unwrap() before calling this method if this Event +// was returned from a transaction, and the transaction was committed or rolled back. +func (e *Event) Update() *EventUpdateOne { + return NewEventClient(e.config).UpdateOne(e) +} + +// Unwrap unwraps the Event entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (e *Event) Unwrap() *Event { + _tx, ok := e.config.driver.(*txDriver) + if !ok { + panic("ent: Event is not a transactional entity") + } + e.config.driver = _tx.drv + return e +} + +// String implements the fmt.Stringer. +func (e *Event) String() string { + var builder strings.Builder + builder.WriteString("Event(") + builder.WriteString(fmt.Sprintf("id=%v, ", e.ID)) + builder.WriteString("created_at=") + builder.WriteString(e.CreatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("user_agent=") + builder.WriteString(e.UserAgent) + builder.WriteString(", ") + builder.WriteString("content=") + builder.WriteString(fmt.Sprintf("%v", e.Content)) + builder.WriteByte(')') + return builder.String() +} + +// Events is a parsable slice of Event. +type Events []*Event diff --git a/internal/ent/event/event.go b/internal/ent/event/event.go new file mode 100644 index 0000000..2d6b583 --- /dev/null +++ b/internal/ent/event/event.go @@ -0,0 +1,130 @@ +// Code generated by ent, DO NOT EDIT. + +package event + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +const ( + // Label holds the string label denoting the event type in the database. + Label = "event" + // FieldID holds the string denoting the id field in the database. + FieldID = "event_id" + // FieldCreatedAt holds the string denoting the created_at field in the database. + FieldCreatedAt = "created_at" + // FieldUserAgent holds the string denoting the user_agent field in the database. + FieldUserAgent = "user_agent" + // FieldContent holds the string denoting the content field in the database. + FieldContent = "content" + // EdgeUser holds the string denoting the user edge name in mutations. + EdgeUser = "user" + // EdgeResearch holds the string denoting the research edge name in mutations. + EdgeResearch = "research" + // UserFieldID holds the string denoting the ID field of the User. + UserFieldID = "user_id" + // ResearchFieldID holds the string denoting the ID field of the Research. + ResearchFieldID = "research_id" + // Table holds the table name of the event in the database. + Table = "events" + // UserTable is the table that holds the user relation/edge. + UserTable = "events" + // UserInverseTable is the table name for the User entity. + // It exists in this package in order to avoid circular dependency with the "user" package. + UserInverseTable = "users" + // UserColumn is the table column denoting the user relation/edge. + UserColumn = "user_events" + // ResearchTable is the table that holds the research relation/edge. + ResearchTable = "events" + // ResearchInverseTable is the table name for the Research entity. + // It exists in this package in order to avoid circular dependency with the "research" package. + ResearchInverseTable = "researches" + // ResearchColumn is the table column denoting the research relation/edge. + ResearchColumn = "research_events" +) + +// Columns holds all SQL columns for event fields. +var Columns = []string{ + FieldID, + FieldCreatedAt, + FieldUserAgent, + FieldContent, +} + +// ForeignKeys holds the SQL foreign-keys that are owned by the "events" +// table and are not defined as standalone fields in the schema. +var ForeignKeys = []string{ + "research_events", + "user_events", +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + for i := range ForeignKeys { + if column == ForeignKeys[i] { + return true + } + } + return false +} + +var ( + // DefaultCreatedAt holds the default value on creation for the "created_at" field. + DefaultCreatedAt func() time.Time + // DefaultID holds the default value on creation for the "id" field. + DefaultID func() string +) + +// OrderOption defines the ordering options for the Event queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByCreatedAt orders the results by the created_at field. +func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() +} + +// ByUserAgent orders the results by the user_agent field. +func ByUserAgent(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldUserAgent, opts...).ToFunc() +} + +// ByUserField orders the results by user field. +func ByUserField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newUserStep(), sql.OrderByField(field, opts...)) + } +} + +// ByResearchField orders the results by research field. +func ByResearchField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newResearchStep(), sql.OrderByField(field, opts...)) + } +} +func newUserStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(UserInverseTable, UserFieldID), + sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn), + ) +} +func newResearchStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ResearchInverseTable, ResearchFieldID), + sqlgraph.Edge(sqlgraph.M2O, true, ResearchTable, ResearchColumn), + ) +} diff --git a/internal/ent/event/where.go b/internal/ent/event/where.go new file mode 100644 index 0000000..25af99e --- /dev/null +++ b/internal/ent/event/where.go @@ -0,0 +1,259 @@ +// Code generated by ent, DO NOT EDIT. + +package event + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "exusiai.dev/roguestats-backend/internal/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id string) predicate.Event { + return predicate.Event(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id string) predicate.Event { + return predicate.Event(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id string) predicate.Event { + return predicate.Event(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...string) predicate.Event { + return predicate.Event(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...string) predicate.Event { + return predicate.Event(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id string) predicate.Event { + return predicate.Event(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id string) predicate.Event { + return predicate.Event(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id string) predicate.Event { + return predicate.Event(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id string) predicate.Event { + return predicate.Event(sql.FieldLTE(FieldID, id)) +} + +// IDEqualFold applies the EqualFold predicate on the ID field. +func IDEqualFold(id string) predicate.Event { + return predicate.Event(sql.FieldEqualFold(FieldID, id)) +} + +// IDContainsFold applies the ContainsFold predicate on the ID field. +func IDContainsFold(id string) predicate.Event { + return predicate.Event(sql.FieldContainsFold(FieldID, id)) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.Event { + return predicate.Event(sql.FieldEQ(FieldCreatedAt, v)) +} + +// UserAgent applies equality check predicate on the "user_agent" field. It's identical to UserAgentEQ. +func UserAgent(v string) predicate.Event { + return predicate.Event(sql.FieldEQ(FieldUserAgent, v)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.Event { + return predicate.Event(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.Event { + return predicate.Event(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.Event { + return predicate.Event(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.Event { + return predicate.Event(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.Event { + return predicate.Event(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.Event { + return predicate.Event(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.Event { + return predicate.Event(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.Event { + return predicate.Event(sql.FieldLTE(FieldCreatedAt, v)) +} + +// UserAgentEQ applies the EQ predicate on the "user_agent" field. +func UserAgentEQ(v string) predicate.Event { + return predicate.Event(sql.FieldEQ(FieldUserAgent, v)) +} + +// UserAgentNEQ applies the NEQ predicate on the "user_agent" field. +func UserAgentNEQ(v string) predicate.Event { + return predicate.Event(sql.FieldNEQ(FieldUserAgent, v)) +} + +// UserAgentIn applies the In predicate on the "user_agent" field. +func UserAgentIn(vs ...string) predicate.Event { + return predicate.Event(sql.FieldIn(FieldUserAgent, vs...)) +} + +// UserAgentNotIn applies the NotIn predicate on the "user_agent" field. +func UserAgentNotIn(vs ...string) predicate.Event { + return predicate.Event(sql.FieldNotIn(FieldUserAgent, vs...)) +} + +// UserAgentGT applies the GT predicate on the "user_agent" field. +func UserAgentGT(v string) predicate.Event { + return predicate.Event(sql.FieldGT(FieldUserAgent, v)) +} + +// UserAgentGTE applies the GTE predicate on the "user_agent" field. +func UserAgentGTE(v string) predicate.Event { + return predicate.Event(sql.FieldGTE(FieldUserAgent, v)) +} + +// UserAgentLT applies the LT predicate on the "user_agent" field. +func UserAgentLT(v string) predicate.Event { + return predicate.Event(sql.FieldLT(FieldUserAgent, v)) +} + +// UserAgentLTE applies the LTE predicate on the "user_agent" field. +func UserAgentLTE(v string) predicate.Event { + return predicate.Event(sql.FieldLTE(FieldUserAgent, v)) +} + +// UserAgentContains applies the Contains predicate on the "user_agent" field. +func UserAgentContains(v string) predicate.Event { + return predicate.Event(sql.FieldContains(FieldUserAgent, v)) +} + +// UserAgentHasPrefix applies the HasPrefix predicate on the "user_agent" field. +func UserAgentHasPrefix(v string) predicate.Event { + return predicate.Event(sql.FieldHasPrefix(FieldUserAgent, v)) +} + +// UserAgentHasSuffix applies the HasSuffix predicate on the "user_agent" field. +func UserAgentHasSuffix(v string) predicate.Event { + return predicate.Event(sql.FieldHasSuffix(FieldUserAgent, v)) +} + +// UserAgentEqualFold applies the EqualFold predicate on the "user_agent" field. +func UserAgentEqualFold(v string) predicate.Event { + return predicate.Event(sql.FieldEqualFold(FieldUserAgent, v)) +} + +// UserAgentContainsFold applies the ContainsFold predicate on the "user_agent" field. +func UserAgentContainsFold(v string) predicate.Event { + return predicate.Event(sql.FieldContainsFold(FieldUserAgent, v)) +} + +// HasUser applies the HasEdge predicate on the "user" edge. +func HasUser() predicate.Event { + return predicate.Event(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates). +func HasUserWith(preds ...predicate.User) predicate.Event { + return predicate.Event(func(s *sql.Selector) { + step := newUserStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// HasResearch applies the HasEdge predicate on the "research" edge. +func HasResearch() predicate.Event { + return predicate.Event(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, ResearchTable, ResearchColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasResearchWith applies the HasEdge predicate on the "research" edge with a given conditions (other predicates). +func HasResearchWith(preds ...predicate.Research) predicate.Event { + return predicate.Event(func(s *sql.Selector) { + step := newResearchStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.Event) predicate.Event { + return predicate.Event(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.Event) predicate.Event { + return predicate.Event(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.Event) predicate.Event { + return predicate.Event(func(s *sql.Selector) { + p(s.Not()) + }) +} diff --git a/internal/ent/event_create.go b/internal/ent/event_create.go new file mode 100644 index 0000000..5a53176 --- /dev/null +++ b/internal/ent/event_create.go @@ -0,0 +1,321 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// EventCreate is the builder for creating a Event entity. +type EventCreate struct { + config + mutation *EventMutation + hooks []Hook +} + +// SetCreatedAt sets the "created_at" field. +func (ec *EventCreate) SetCreatedAt(t time.Time) *EventCreate { + ec.mutation.SetCreatedAt(t) + return ec +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (ec *EventCreate) SetNillableCreatedAt(t *time.Time) *EventCreate { + if t != nil { + ec.SetCreatedAt(*t) + } + return ec +} + +// SetUserAgent sets the "user_agent" field. +func (ec *EventCreate) SetUserAgent(s string) *EventCreate { + ec.mutation.SetUserAgent(s) + return ec +} + +// SetContent sets the "content" field. +func (ec *EventCreate) SetContent(m map[string]interface{}) *EventCreate { + ec.mutation.SetContent(m) + return ec +} + +// SetID sets the "id" field. +func (ec *EventCreate) SetID(s string) *EventCreate { + ec.mutation.SetID(s) + return ec +} + +// SetNillableID sets the "id" field if the given value is not nil. +func (ec *EventCreate) SetNillableID(s *string) *EventCreate { + if s != nil { + ec.SetID(*s) + } + return ec +} + +// SetUserID sets the "user" edge to the User entity by ID. +func (ec *EventCreate) SetUserID(id string) *EventCreate { + ec.mutation.SetUserID(id) + return ec +} + +// SetNillableUserID sets the "user" edge to the User entity by ID if the given value is not nil. +func (ec *EventCreate) SetNillableUserID(id *string) *EventCreate { + if id != nil { + ec = ec.SetUserID(*id) + } + return ec +} + +// SetUser sets the "user" edge to the User entity. +func (ec *EventCreate) SetUser(u *User) *EventCreate { + return ec.SetUserID(u.ID) +} + +// SetResearchID sets the "research" edge to the Research entity by ID. +func (ec *EventCreate) SetResearchID(id string) *EventCreate { + ec.mutation.SetResearchID(id) + return ec +} + +// SetNillableResearchID sets the "research" edge to the Research entity by ID if the given value is not nil. +func (ec *EventCreate) SetNillableResearchID(id *string) *EventCreate { + if id != nil { + ec = ec.SetResearchID(*id) + } + return ec +} + +// SetResearch sets the "research" edge to the Research entity. +func (ec *EventCreate) SetResearch(r *Research) *EventCreate { + return ec.SetResearchID(r.ID) +} + +// Mutation returns the EventMutation object of the builder. +func (ec *EventCreate) Mutation() *EventMutation { + return ec.mutation +} + +// Save creates the Event in the database. +func (ec *EventCreate) Save(ctx context.Context) (*Event, error) { + ec.defaults() + return withHooks(ctx, ec.sqlSave, ec.mutation, ec.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (ec *EventCreate) SaveX(ctx context.Context) *Event { + v, err := ec.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (ec *EventCreate) Exec(ctx context.Context) error { + _, err := ec.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (ec *EventCreate) ExecX(ctx context.Context) { + if err := ec.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (ec *EventCreate) defaults() { + if _, ok := ec.mutation.CreatedAt(); !ok { + v := event.DefaultCreatedAt() + ec.mutation.SetCreatedAt(v) + } + if _, ok := ec.mutation.ID(); !ok { + v := event.DefaultID() + ec.mutation.SetID(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (ec *EventCreate) check() error { + if _, ok := ec.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Event.created_at"`)} + } + if _, ok := ec.mutation.UserAgent(); !ok { + return &ValidationError{Name: "user_agent", err: errors.New(`ent: missing required field "Event.user_agent"`)} + } + if _, ok := ec.mutation.Content(); !ok { + return &ValidationError{Name: "content", err: errors.New(`ent: missing required field "Event.content"`)} + } + return nil +} + +func (ec *EventCreate) sqlSave(ctx context.Context) (*Event, error) { + if err := ec.check(); err != nil { + return nil, err + } + _node, _spec := ec.createSpec() + if err := sqlgraph.CreateNode(ctx, ec.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + if _spec.ID.Value != nil { + if id, ok := _spec.ID.Value.(string); ok { + _node.ID = id + } else { + return nil, fmt.Errorf("unexpected Event.ID type: %T", _spec.ID.Value) + } + } + ec.mutation.id = &_node.ID + ec.mutation.done = true + return _node, nil +} + +func (ec *EventCreate) createSpec() (*Event, *sqlgraph.CreateSpec) { + var ( + _node = &Event{config: ec.config} + _spec = sqlgraph.NewCreateSpec(event.Table, sqlgraph.NewFieldSpec(event.FieldID, field.TypeString)) + ) + if id, ok := ec.mutation.ID(); ok { + _node.ID = id + _spec.ID.Value = id + } + if value, ok := ec.mutation.CreatedAt(); ok { + _spec.SetField(event.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := ec.mutation.UserAgent(); ok { + _spec.SetField(event.FieldUserAgent, field.TypeString, value) + _node.UserAgent = value + } + if value, ok := ec.mutation.Content(); ok { + _spec.SetField(event.FieldContent, field.TypeJSON, value) + _node.Content = value + } + if nodes := ec.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: event.UserTable, + Columns: []string{event.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.user_events = &nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + if nodes := ec.mutation.ResearchIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: event.ResearchTable, + Columns: []string{event.ResearchColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(research.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.research_events = &nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// EventCreateBulk is the builder for creating many Event entities in bulk. +type EventCreateBulk struct { + config + builders []*EventCreate +} + +// Save creates the Event entities in the database. +func (ecb *EventCreateBulk) Save(ctx context.Context) ([]*Event, error) { + specs := make([]*sqlgraph.CreateSpec, len(ecb.builders)) + nodes := make([]*Event, len(ecb.builders)) + mutators := make([]Mutator, len(ecb.builders)) + for i := range ecb.builders { + func(i int, root context.Context) { + builder := ecb.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*EventMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, ecb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, ecb.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, ecb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (ecb *EventCreateBulk) SaveX(ctx context.Context) []*Event { + v, err := ecb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (ecb *EventCreateBulk) Exec(ctx context.Context) error { + _, err := ecb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (ecb *EventCreateBulk) ExecX(ctx context.Context) { + if err := ecb.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/internal/ent/event_delete.go b/internal/ent/event_delete.go new file mode 100644 index 0000000..e53fd8e --- /dev/null +++ b/internal/ent/event_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/predicate" +) + +// EventDelete is the builder for deleting a Event entity. +type EventDelete struct { + config + hooks []Hook + mutation *EventMutation +} + +// Where appends a list predicates to the EventDelete builder. +func (ed *EventDelete) Where(ps ...predicate.Event) *EventDelete { + ed.mutation.Where(ps...) + return ed +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (ed *EventDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, ed.sqlExec, ed.mutation, ed.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (ed *EventDelete) ExecX(ctx context.Context) int { + n, err := ed.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (ed *EventDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(event.Table, sqlgraph.NewFieldSpec(event.FieldID, field.TypeString)) + if ps := ed.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, ed.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + ed.mutation.done = true + return affected, err +} + +// EventDeleteOne is the builder for deleting a single Event entity. +type EventDeleteOne struct { + ed *EventDelete +} + +// Where appends a list predicates to the EventDelete builder. +func (edo *EventDeleteOne) Where(ps ...predicate.Event) *EventDeleteOne { + edo.ed.mutation.Where(ps...) + return edo +} + +// Exec executes the deletion query. +func (edo *EventDeleteOne) Exec(ctx context.Context) error { + n, err := edo.ed.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{event.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (edo *EventDeleteOne) ExecX(ctx context.Context) { + if err := edo.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/internal/ent/event_query.go b/internal/ent/event_query.go new file mode 100644 index 0000000..cac091d --- /dev/null +++ b/internal/ent/event_query.go @@ -0,0 +1,701 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/predicate" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// EventQuery is the builder for querying Event entities. +type EventQuery struct { + config + ctx *QueryContext + order []event.OrderOption + inters []Interceptor + predicates []predicate.Event + withUser *UserQuery + withResearch *ResearchQuery + withFKs bool + modifiers []func(*sql.Selector) + loadTotal []func(context.Context, []*Event) error + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the EventQuery builder. +func (eq *EventQuery) Where(ps ...predicate.Event) *EventQuery { + eq.predicates = append(eq.predicates, ps...) + return eq +} + +// Limit the number of records to be returned by this query. +func (eq *EventQuery) Limit(limit int) *EventQuery { + eq.ctx.Limit = &limit + return eq +} + +// Offset to start from. +func (eq *EventQuery) Offset(offset int) *EventQuery { + eq.ctx.Offset = &offset + return eq +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (eq *EventQuery) Unique(unique bool) *EventQuery { + eq.ctx.Unique = &unique + return eq +} + +// Order specifies how the records should be ordered. +func (eq *EventQuery) Order(o ...event.OrderOption) *EventQuery { + eq.order = append(eq.order, o...) + return eq +} + +// QueryUser chains the current query on the "user" edge. +func (eq *EventQuery) QueryUser() *UserQuery { + query := (&UserClient{config: eq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := eq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := eq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(event.Table, event.FieldID, selector), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, event.UserTable, event.UserColumn), + ) + fromU = sqlgraph.SetNeighbors(eq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// QueryResearch chains the current query on the "research" edge. +func (eq *EventQuery) QueryResearch() *ResearchQuery { + query := (&ResearchClient{config: eq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := eq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := eq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(event.Table, event.FieldID, selector), + sqlgraph.To(research.Table, research.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, event.ResearchTable, event.ResearchColumn), + ) + fromU = sqlgraph.SetNeighbors(eq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first Event entity from the query. +// Returns a *NotFoundError when no Event was found. +func (eq *EventQuery) First(ctx context.Context) (*Event, error) { + nodes, err := eq.Limit(1).All(setContextOp(ctx, eq.ctx, "First")) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{event.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (eq *EventQuery) FirstX(ctx context.Context) *Event { + node, err := eq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first Event ID from the query. +// Returns a *NotFoundError when no Event ID was found. +func (eq *EventQuery) FirstID(ctx context.Context) (id string, err error) { + var ids []string + if ids, err = eq.Limit(1).IDs(setContextOp(ctx, eq.ctx, "FirstID")); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{event.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (eq *EventQuery) FirstIDX(ctx context.Context) string { + id, err := eq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single Event entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one Event entity is found. +// Returns a *NotFoundError when no Event entities are found. +func (eq *EventQuery) Only(ctx context.Context) (*Event, error) { + nodes, err := eq.Limit(2).All(setContextOp(ctx, eq.ctx, "Only")) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{event.Label} + default: + return nil, &NotSingularError{event.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (eq *EventQuery) OnlyX(ctx context.Context) *Event { + node, err := eq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only Event ID in the query. +// Returns a *NotSingularError when more than one Event ID is found. +// Returns a *NotFoundError when no entities are found. +func (eq *EventQuery) OnlyID(ctx context.Context) (id string, err error) { + var ids []string + if ids, err = eq.Limit(2).IDs(setContextOp(ctx, eq.ctx, "OnlyID")); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{event.Label} + default: + err = &NotSingularError{event.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (eq *EventQuery) OnlyIDX(ctx context.Context) string { + id, err := eq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of Events. +func (eq *EventQuery) All(ctx context.Context) ([]*Event, error) { + ctx = setContextOp(ctx, eq.ctx, "All") + if err := eq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*Event, *EventQuery]() + return withInterceptors[[]*Event](ctx, eq, qr, eq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (eq *EventQuery) AllX(ctx context.Context) []*Event { + nodes, err := eq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of Event IDs. +func (eq *EventQuery) IDs(ctx context.Context) (ids []string, err error) { + if eq.ctx.Unique == nil && eq.path != nil { + eq.Unique(true) + } + ctx = setContextOp(ctx, eq.ctx, "IDs") + if err = eq.Select(event.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (eq *EventQuery) IDsX(ctx context.Context) []string { + ids, err := eq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (eq *EventQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, eq.ctx, "Count") + if err := eq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, eq, querierCount[*EventQuery](), eq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (eq *EventQuery) CountX(ctx context.Context) int { + count, err := eq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (eq *EventQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, eq.ctx, "Exist") + switch _, err := eq.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (eq *EventQuery) ExistX(ctx context.Context) bool { + exist, err := eq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the EventQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (eq *EventQuery) Clone() *EventQuery { + if eq == nil { + return nil + } + return &EventQuery{ + config: eq.config, + ctx: eq.ctx.Clone(), + order: append([]event.OrderOption{}, eq.order...), + inters: append([]Interceptor{}, eq.inters...), + predicates: append([]predicate.Event{}, eq.predicates...), + withUser: eq.withUser.Clone(), + withResearch: eq.withResearch.Clone(), + // clone intermediate query. + sql: eq.sql.Clone(), + path: eq.path, + } +} + +// WithUser tells the query-builder to eager-load the nodes that are connected to +// the "user" edge. The optional arguments are used to configure the query builder of the edge. +func (eq *EventQuery) WithUser(opts ...func(*UserQuery)) *EventQuery { + query := (&UserClient{config: eq.config}).Query() + for _, opt := range opts { + opt(query) + } + eq.withUser = query + return eq +} + +// WithResearch tells the query-builder to eager-load the nodes that are connected to +// the "research" edge. The optional arguments are used to configure the query builder of the edge. +func (eq *EventQuery) WithResearch(opts ...func(*ResearchQuery)) *EventQuery { + query := (&ResearchClient{config: eq.config}).Query() + for _, opt := range opts { + opt(query) + } + eq.withResearch = query + return eq +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Event.Query(). +// GroupBy(event.FieldCreatedAt). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (eq *EventQuery) GroupBy(field string, fields ...string) *EventGroupBy { + eq.ctx.Fields = append([]string{field}, fields...) + grbuild := &EventGroupBy{build: eq} + grbuild.flds = &eq.ctx.Fields + grbuild.label = event.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// } +// +// client.Event.Query(). +// Select(event.FieldCreatedAt). +// Scan(ctx, &v) +func (eq *EventQuery) Select(fields ...string) *EventSelect { + eq.ctx.Fields = append(eq.ctx.Fields, fields...) + sbuild := &EventSelect{EventQuery: eq} + sbuild.label = event.Label + sbuild.flds, sbuild.scan = &eq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a EventSelect configured with the given aggregations. +func (eq *EventQuery) Aggregate(fns ...AggregateFunc) *EventSelect { + return eq.Select().Aggregate(fns...) +} + +func (eq *EventQuery) prepareQuery(ctx context.Context) error { + for _, inter := range eq.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, eq); err != nil { + return err + } + } + } + for _, f := range eq.ctx.Fields { + if !event.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if eq.path != nil { + prev, err := eq.path(ctx) + if err != nil { + return err + } + eq.sql = prev + } + return nil +} + +func (eq *EventQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Event, error) { + var ( + nodes = []*Event{} + withFKs = eq.withFKs + _spec = eq.querySpec() + loadedTypes = [2]bool{ + eq.withUser != nil, + eq.withResearch != nil, + } + ) + if eq.withUser != nil || eq.withResearch != nil { + withFKs = true + } + if withFKs { + _spec.Node.Columns = append(_spec.Node.Columns, event.ForeignKeys...) + } + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*Event).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &Event{config: eq.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + if len(eq.modifiers) > 0 { + _spec.Modifiers = eq.modifiers + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, eq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := eq.withUser; query != nil { + if err := eq.loadUser(ctx, query, nodes, nil, + func(n *Event, e *User) { n.Edges.User = e }); err != nil { + return nil, err + } + } + if query := eq.withResearch; query != nil { + if err := eq.loadResearch(ctx, query, nodes, nil, + func(n *Event, e *Research) { n.Edges.Research = e }); err != nil { + return nil, err + } + } + for i := range eq.loadTotal { + if err := eq.loadTotal[i](ctx, nodes); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (eq *EventQuery) loadUser(ctx context.Context, query *UserQuery, nodes []*Event, init func(*Event), assign func(*Event, *User)) error { + ids := make([]string, 0, len(nodes)) + nodeids := make(map[string][]*Event) + for i := range nodes { + if nodes[i].user_events == nil { + continue + } + fk := *nodes[i].user_events + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(user.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "user_events" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} +func (eq *EventQuery) loadResearch(ctx context.Context, query *ResearchQuery, nodes []*Event, init func(*Event), assign func(*Event, *Research)) error { + ids := make([]string, 0, len(nodes)) + nodeids := make(map[string][]*Event) + for i := range nodes { + if nodes[i].research_events == nil { + continue + } + fk := *nodes[i].research_events + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(research.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "research_events" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} + +func (eq *EventQuery) sqlCount(ctx context.Context) (int, error) { + _spec := eq.querySpec() + if len(eq.modifiers) > 0 { + _spec.Modifiers = eq.modifiers + } + _spec.Node.Columns = eq.ctx.Fields + if len(eq.ctx.Fields) > 0 { + _spec.Unique = eq.ctx.Unique != nil && *eq.ctx.Unique + } + return sqlgraph.CountNodes(ctx, eq.driver, _spec) +} + +func (eq *EventQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(event.Table, event.Columns, sqlgraph.NewFieldSpec(event.FieldID, field.TypeString)) + _spec.From = eq.sql + if unique := eq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if eq.path != nil { + _spec.Unique = true + } + if fields := eq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, event.FieldID) + for i := range fields { + if fields[i] != event.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := eq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := eq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := eq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := eq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (eq *EventQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(eq.driver.Dialect()) + t1 := builder.Table(event.Table) + columns := eq.ctx.Fields + if len(columns) == 0 { + columns = event.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if eq.sql != nil { + selector = eq.sql + selector.Select(selector.Columns(columns...)...) + } + if eq.ctx.Unique != nil && *eq.ctx.Unique { + selector.Distinct() + } + for _, p := range eq.predicates { + p(selector) + } + for _, p := range eq.order { + p(selector) + } + if offset := eq.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := eq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// EventGroupBy is the group-by builder for Event entities. +type EventGroupBy struct { + selector + build *EventQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (egb *EventGroupBy) Aggregate(fns ...AggregateFunc) *EventGroupBy { + egb.fns = append(egb.fns, fns...) + return egb +} + +// Scan applies the selector query and scans the result into the given value. +func (egb *EventGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, egb.build.ctx, "GroupBy") + if err := egb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*EventQuery, *EventGroupBy](ctx, egb.build, egb, egb.build.inters, v) +} + +func (egb *EventGroupBy) sqlScan(ctx context.Context, root *EventQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(egb.fns)) + for _, fn := range egb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*egb.flds)+len(egb.fns)) + for _, f := range *egb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*egb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := egb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// EventSelect is the builder for selecting fields of Event entities. +type EventSelect struct { + *EventQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (es *EventSelect) Aggregate(fns ...AggregateFunc) *EventSelect { + es.fns = append(es.fns, fns...) + return es +} + +// Scan applies the selector query and scans the result into the given value. +func (es *EventSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, es.ctx, "Select") + if err := es.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*EventQuery, *EventSelect](ctx, es.EventQuery, es, es.inters, v) +} + +func (es *EventSelect) sqlScan(ctx context.Context, root *EventQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(es.fns)) + for _, fn := range es.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*es.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := es.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/internal/ent/event_update.go b/internal/ent/event_update.go new file mode 100644 index 0000000..7071150 --- /dev/null +++ b/internal/ent/event_update.go @@ -0,0 +1,429 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/predicate" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// EventUpdate is the builder for updating Event entities. +type EventUpdate struct { + config + hooks []Hook + mutation *EventMutation +} + +// Where appends a list predicates to the EventUpdate builder. +func (eu *EventUpdate) Where(ps ...predicate.Event) *EventUpdate { + eu.mutation.Where(ps...) + return eu +} + +// SetUserAgent sets the "user_agent" field. +func (eu *EventUpdate) SetUserAgent(s string) *EventUpdate { + eu.mutation.SetUserAgent(s) + return eu +} + +// SetContent sets the "content" field. +func (eu *EventUpdate) SetContent(m map[string]interface{}) *EventUpdate { + eu.mutation.SetContent(m) + return eu +} + +// SetUserID sets the "user" edge to the User entity by ID. +func (eu *EventUpdate) SetUserID(id string) *EventUpdate { + eu.mutation.SetUserID(id) + return eu +} + +// SetNillableUserID sets the "user" edge to the User entity by ID if the given value is not nil. +func (eu *EventUpdate) SetNillableUserID(id *string) *EventUpdate { + if id != nil { + eu = eu.SetUserID(*id) + } + return eu +} + +// SetUser sets the "user" edge to the User entity. +func (eu *EventUpdate) SetUser(u *User) *EventUpdate { + return eu.SetUserID(u.ID) +} + +// SetResearchID sets the "research" edge to the Research entity by ID. +func (eu *EventUpdate) SetResearchID(id string) *EventUpdate { + eu.mutation.SetResearchID(id) + return eu +} + +// SetNillableResearchID sets the "research" edge to the Research entity by ID if the given value is not nil. +func (eu *EventUpdate) SetNillableResearchID(id *string) *EventUpdate { + if id != nil { + eu = eu.SetResearchID(*id) + } + return eu +} + +// SetResearch sets the "research" edge to the Research entity. +func (eu *EventUpdate) SetResearch(r *Research) *EventUpdate { + return eu.SetResearchID(r.ID) +} + +// Mutation returns the EventMutation object of the builder. +func (eu *EventUpdate) Mutation() *EventMutation { + return eu.mutation +} + +// ClearUser clears the "user" edge to the User entity. +func (eu *EventUpdate) ClearUser() *EventUpdate { + eu.mutation.ClearUser() + return eu +} + +// ClearResearch clears the "research" edge to the Research entity. +func (eu *EventUpdate) ClearResearch() *EventUpdate { + eu.mutation.ClearResearch() + return eu +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (eu *EventUpdate) Save(ctx context.Context) (int, error) { + return withHooks(ctx, eu.sqlSave, eu.mutation, eu.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (eu *EventUpdate) SaveX(ctx context.Context) int { + affected, err := eu.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (eu *EventUpdate) Exec(ctx context.Context) error { + _, err := eu.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (eu *EventUpdate) ExecX(ctx context.Context) { + if err := eu.Exec(ctx); err != nil { + panic(err) + } +} + +func (eu *EventUpdate) sqlSave(ctx context.Context) (n int, err error) { + _spec := sqlgraph.NewUpdateSpec(event.Table, event.Columns, sqlgraph.NewFieldSpec(event.FieldID, field.TypeString)) + if ps := eu.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := eu.mutation.UserAgent(); ok { + _spec.SetField(event.FieldUserAgent, field.TypeString, value) + } + if value, ok := eu.mutation.Content(); ok { + _spec.SetField(event.FieldContent, field.TypeJSON, value) + } + if eu.mutation.UserCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: event.UserTable, + Columns: []string{event.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeString), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := eu.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: event.UserTable, + Columns: []string{event.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if eu.mutation.ResearchCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: event.ResearchTable, + Columns: []string{event.ResearchColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(research.FieldID, field.TypeString), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := eu.mutation.ResearchIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: event.ResearchTable, + Columns: []string{event.ResearchColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(research.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if n, err = sqlgraph.UpdateNodes(ctx, eu.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{event.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + eu.mutation.done = true + return n, nil +} + +// EventUpdateOne is the builder for updating a single Event entity. +type EventUpdateOne struct { + config + fields []string + hooks []Hook + mutation *EventMutation +} + +// SetUserAgent sets the "user_agent" field. +func (euo *EventUpdateOne) SetUserAgent(s string) *EventUpdateOne { + euo.mutation.SetUserAgent(s) + return euo +} + +// SetContent sets the "content" field. +func (euo *EventUpdateOne) SetContent(m map[string]interface{}) *EventUpdateOne { + euo.mutation.SetContent(m) + return euo +} + +// SetUserID sets the "user" edge to the User entity by ID. +func (euo *EventUpdateOne) SetUserID(id string) *EventUpdateOne { + euo.mutation.SetUserID(id) + return euo +} + +// SetNillableUserID sets the "user" edge to the User entity by ID if the given value is not nil. +func (euo *EventUpdateOne) SetNillableUserID(id *string) *EventUpdateOne { + if id != nil { + euo = euo.SetUserID(*id) + } + return euo +} + +// SetUser sets the "user" edge to the User entity. +func (euo *EventUpdateOne) SetUser(u *User) *EventUpdateOne { + return euo.SetUserID(u.ID) +} + +// SetResearchID sets the "research" edge to the Research entity by ID. +func (euo *EventUpdateOne) SetResearchID(id string) *EventUpdateOne { + euo.mutation.SetResearchID(id) + return euo +} + +// SetNillableResearchID sets the "research" edge to the Research entity by ID if the given value is not nil. +func (euo *EventUpdateOne) SetNillableResearchID(id *string) *EventUpdateOne { + if id != nil { + euo = euo.SetResearchID(*id) + } + return euo +} + +// SetResearch sets the "research" edge to the Research entity. +func (euo *EventUpdateOne) SetResearch(r *Research) *EventUpdateOne { + return euo.SetResearchID(r.ID) +} + +// Mutation returns the EventMutation object of the builder. +func (euo *EventUpdateOne) Mutation() *EventMutation { + return euo.mutation +} + +// ClearUser clears the "user" edge to the User entity. +func (euo *EventUpdateOne) ClearUser() *EventUpdateOne { + euo.mutation.ClearUser() + return euo +} + +// ClearResearch clears the "research" edge to the Research entity. +func (euo *EventUpdateOne) ClearResearch() *EventUpdateOne { + euo.mutation.ClearResearch() + return euo +} + +// Where appends a list predicates to the EventUpdate builder. +func (euo *EventUpdateOne) Where(ps ...predicate.Event) *EventUpdateOne { + euo.mutation.Where(ps...) + return euo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (euo *EventUpdateOne) Select(field string, fields ...string) *EventUpdateOne { + euo.fields = append([]string{field}, fields...) + return euo +} + +// Save executes the query and returns the updated Event entity. +func (euo *EventUpdateOne) Save(ctx context.Context) (*Event, error) { + return withHooks(ctx, euo.sqlSave, euo.mutation, euo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (euo *EventUpdateOne) SaveX(ctx context.Context) *Event { + node, err := euo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (euo *EventUpdateOne) Exec(ctx context.Context) error { + _, err := euo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (euo *EventUpdateOne) ExecX(ctx context.Context) { + if err := euo.Exec(ctx); err != nil { + panic(err) + } +} + +func (euo *EventUpdateOne) sqlSave(ctx context.Context) (_node *Event, err error) { + _spec := sqlgraph.NewUpdateSpec(event.Table, event.Columns, sqlgraph.NewFieldSpec(event.FieldID, field.TypeString)) + id, ok := euo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Event.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := euo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, event.FieldID) + for _, f := range fields { + if !event.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != event.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := euo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := euo.mutation.UserAgent(); ok { + _spec.SetField(event.FieldUserAgent, field.TypeString, value) + } + if value, ok := euo.mutation.Content(); ok { + _spec.SetField(event.FieldContent, field.TypeJSON, value) + } + if euo.mutation.UserCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: event.UserTable, + Columns: []string{event.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeString), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := euo.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: event.UserTable, + Columns: []string{event.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if euo.mutation.ResearchCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: event.ResearchTable, + Columns: []string{event.ResearchColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(research.FieldID, field.TypeString), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := euo.mutation.ResearchIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: event.ResearchTable, + Columns: []string{event.ResearchColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(research.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &Event{config: euo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, euo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{event.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + euo.mutation.done = true + return _node, nil +} diff --git a/internal/ent/gql_collection.go b/internal/ent/gql_collection.go new file mode 100644 index 0000000..469a675 --- /dev/null +++ b/internal/ent/gql_collection.go @@ -0,0 +1,414 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/contrib/entgql" + "entgo.io/ent/dialect/sql" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/user" + "github.com/99designs/gqlgen/graphql" +) + +// CollectFields tells the query-builder to eagerly load connected nodes by resolver context. +func (e *EventQuery) CollectFields(ctx context.Context, satisfies ...string) (*EventQuery, error) { + fc := graphql.GetFieldContext(ctx) + if fc == nil { + return e, nil + } + if err := e.collectField(ctx, graphql.GetOperationContext(ctx), fc.Field, nil, satisfies...); err != nil { + return nil, err + } + return e, nil +} + +func (e *EventQuery) collectField(ctx context.Context, opCtx *graphql.OperationContext, collected graphql.CollectedField, path []string, satisfies ...string) error { + path = append([]string(nil), path...) + var ( + unknownSeen bool + fieldSeen = make(map[string]struct{}, len(event.Columns)) + selectedFields = []string{event.FieldID} + ) + for _, field := range graphql.CollectFields(opCtx, collected.Selections, satisfies) { + switch field.Name { + case "user": + var ( + alias = field.Alias + path = append(path, alias) + query = (&UserClient{config: e.config}).Query() + ) + if err := query.collectField(ctx, opCtx, field, path, mayAddCondition(satisfies, userImplementors)...); err != nil { + return err + } + e.withUser = query + case "research": + var ( + alias = field.Alias + path = append(path, alias) + query = (&ResearchClient{config: e.config}).Query() + ) + if err := query.collectField(ctx, opCtx, field, path, mayAddCondition(satisfies, researchImplementors)...); err != nil { + return err + } + e.withResearch = query + case "createdAt": + if _, ok := fieldSeen[event.FieldCreatedAt]; !ok { + selectedFields = append(selectedFields, event.FieldCreatedAt) + fieldSeen[event.FieldCreatedAt] = struct{}{} + } + case "userAgent": + if _, ok := fieldSeen[event.FieldUserAgent]; !ok { + selectedFields = append(selectedFields, event.FieldUserAgent) + fieldSeen[event.FieldUserAgent] = struct{}{} + } + case "content": + if _, ok := fieldSeen[event.FieldContent]; !ok { + selectedFields = append(selectedFields, event.FieldContent) + fieldSeen[event.FieldContent] = struct{}{} + } + case "id": + case "__typename": + default: + unknownSeen = true + } + } + if !unknownSeen { + e.Select(selectedFields...) + } + return nil +} + +type eventPaginateArgs struct { + first, last *int + after, before *Cursor + opts []EventPaginateOption +} + +func newEventPaginateArgs(rv map[string]any) *eventPaginateArgs { + args := &eventPaginateArgs{} + if rv == nil { + return args + } + if v := rv[firstField]; v != nil { + args.first = v.(*int) + } + if v := rv[lastField]; v != nil { + args.last = v.(*int) + } + if v := rv[afterField]; v != nil { + args.after = v.(*Cursor) + } + if v := rv[beforeField]; v != nil { + args.before = v.(*Cursor) + } + if v, ok := rv[orderByField]; ok { + switch v := v.(type) { + case map[string]any: + var ( + err1, err2 error + order = &EventOrder{Field: &EventOrderField{}, Direction: entgql.OrderDirectionAsc} + ) + if d, ok := v[directionField]; ok { + err1 = order.Direction.UnmarshalGQL(d) + } + if f, ok := v[fieldField]; ok { + err2 = order.Field.UnmarshalGQL(f) + } + if err1 == nil && err2 == nil { + args.opts = append(args.opts, WithEventOrder(order)) + } + case *EventOrder: + if v != nil { + args.opts = append(args.opts, WithEventOrder(v)) + } + } + } + return args +} + +// CollectFields tells the query-builder to eagerly load connected nodes by resolver context. +func (r *ResearchQuery) CollectFields(ctx context.Context, satisfies ...string) (*ResearchQuery, error) { + fc := graphql.GetFieldContext(ctx) + if fc == nil { + return r, nil + } + if err := r.collectField(ctx, graphql.GetOperationContext(ctx), fc.Field, nil, satisfies...); err != nil { + return nil, err + } + return r, nil +} + +func (r *ResearchQuery) collectField(ctx context.Context, opCtx *graphql.OperationContext, collected graphql.CollectedField, path []string, satisfies ...string) error { + path = append([]string(nil), path...) + var ( + unknownSeen bool + fieldSeen = make(map[string]struct{}, len(research.Columns)) + selectedFields = []string{research.FieldID} + ) + for _, field := range graphql.CollectFields(opCtx, collected.Selections, satisfies) { + switch field.Name { + case "events": + var ( + alias = field.Alias + path = append(path, alias) + query = (&EventClient{config: r.config}).Query() + ) + if err := query.collectField(ctx, opCtx, field, path, mayAddCondition(satisfies, eventImplementors)...); err != nil { + return err + } + r.WithNamedEvents(alias, func(wq *EventQuery) { + *wq = *query + }) + case "name": + if _, ok := fieldSeen[research.FieldName]; !ok { + selectedFields = append(selectedFields, research.FieldName) + fieldSeen[research.FieldName] = struct{}{} + } + case "schema": + if _, ok := fieldSeen[research.FieldSchema]; !ok { + selectedFields = append(selectedFields, research.FieldSchema) + fieldSeen[research.FieldSchema] = struct{}{} + } + case "id": + case "__typename": + default: + unknownSeen = true + } + } + if !unknownSeen { + r.Select(selectedFields...) + } + return nil +} + +type researchPaginateArgs struct { + first, last *int + after, before *Cursor + opts []ResearchPaginateOption +} + +func newResearchPaginateArgs(rv map[string]any) *researchPaginateArgs { + args := &researchPaginateArgs{} + if rv == nil { + return args + } + if v := rv[firstField]; v != nil { + args.first = v.(*int) + } + if v := rv[lastField]; v != nil { + args.last = v.(*int) + } + if v := rv[afterField]; v != nil { + args.after = v.(*Cursor) + } + if v := rv[beforeField]; v != nil { + args.before = v.(*Cursor) + } + if v, ok := rv[orderByField]; ok { + switch v := v.(type) { + case map[string]any: + var ( + err1, err2 error + order = &ResearchOrder{Field: &ResearchOrderField{}, Direction: entgql.OrderDirectionAsc} + ) + if d, ok := v[directionField]; ok { + err1 = order.Direction.UnmarshalGQL(d) + } + if f, ok := v[fieldField]; ok { + err2 = order.Field.UnmarshalGQL(f) + } + if err1 == nil && err2 == nil { + args.opts = append(args.opts, WithResearchOrder(order)) + } + case *ResearchOrder: + if v != nil { + args.opts = append(args.opts, WithResearchOrder(v)) + } + } + } + return args +} + +// CollectFields tells the query-builder to eagerly load connected nodes by resolver context. +func (u *UserQuery) CollectFields(ctx context.Context, satisfies ...string) (*UserQuery, error) { + fc := graphql.GetFieldContext(ctx) + if fc == nil { + return u, nil + } + if err := u.collectField(ctx, graphql.GetOperationContext(ctx), fc.Field, nil, satisfies...); err != nil { + return nil, err + } + return u, nil +} + +func (u *UserQuery) collectField(ctx context.Context, opCtx *graphql.OperationContext, collected graphql.CollectedField, path []string, satisfies ...string) error { + path = append([]string(nil), path...) + var ( + unknownSeen bool + fieldSeen = make(map[string]struct{}, len(user.Columns)) + selectedFields = []string{user.FieldID} + ) + for _, field := range graphql.CollectFields(opCtx, collected.Selections, satisfies) { + switch field.Name { + case "events": + var ( + alias = field.Alias + path = append(path, alias) + query = (&EventClient{config: u.config}).Query() + ) + if err := query.collectField(ctx, opCtx, field, path, mayAddCondition(satisfies, eventImplementors)...); err != nil { + return err + } + u.WithNamedEvents(alias, func(wq *EventQuery) { + *wq = *query + }) + case "name": + if _, ok := fieldSeen[user.FieldName]; !ok { + selectedFields = append(selectedFields, user.FieldName) + fieldSeen[user.FieldName] = struct{}{} + } + case "email": + if _, ok := fieldSeen[user.FieldEmail]; !ok { + selectedFields = append(selectedFields, user.FieldEmail) + fieldSeen[user.FieldEmail] = struct{}{} + } + case "credential": + if _, ok := fieldSeen[user.FieldCredential]; !ok { + selectedFields = append(selectedFields, user.FieldCredential) + fieldSeen[user.FieldCredential] = struct{}{} + } + case "attributes": + if _, ok := fieldSeen[user.FieldAttributes]; !ok { + selectedFields = append(selectedFields, user.FieldAttributes) + fieldSeen[user.FieldAttributes] = struct{}{} + } + case "id": + case "__typename": + default: + unknownSeen = true + } + } + if !unknownSeen { + u.Select(selectedFields...) + } + return nil +} + +type userPaginateArgs struct { + first, last *int + after, before *Cursor + opts []UserPaginateOption +} + +func newUserPaginateArgs(rv map[string]any) *userPaginateArgs { + args := &userPaginateArgs{} + if rv == nil { + return args + } + if v := rv[firstField]; v != nil { + args.first = v.(*int) + } + if v := rv[lastField]; v != nil { + args.last = v.(*int) + } + if v := rv[afterField]; v != nil { + args.after = v.(*Cursor) + } + if v := rv[beforeField]; v != nil { + args.before = v.(*Cursor) + } + return args +} + +const ( + afterField = "after" + firstField = "first" + beforeField = "before" + lastField = "last" + orderByField = "orderBy" + directionField = "direction" + fieldField = "field" + whereField = "where" +) + +func fieldArgs(ctx context.Context, whereInput any, path ...string) map[string]any { + field := collectedField(ctx, path...) + if field == nil || field.Arguments == nil { + return nil + } + oc := graphql.GetOperationContext(ctx) + args := field.ArgumentMap(oc.Variables) + return unmarshalArgs(ctx, whereInput, args) +} + +// unmarshalArgs allows extracting the field arguments from their raw representation. +func unmarshalArgs(ctx context.Context, whereInput any, args map[string]any) map[string]any { + for _, k := range []string{firstField, lastField} { + v, ok := args[k] + if !ok { + continue + } + i, err := graphql.UnmarshalInt(v) + if err == nil { + args[k] = &i + } + } + for _, k := range []string{beforeField, afterField} { + v, ok := args[k] + if !ok { + continue + } + c := &Cursor{} + if c.UnmarshalGQL(v) == nil { + args[k] = c + } + } + if v, ok := args[whereField]; ok && whereInput != nil { + if err := graphql.UnmarshalInputFromContext(ctx, v, whereInput); err == nil { + args[whereField] = whereInput + } + } + + return args +} + +func limitRows(partitionBy string, limit int, orderBy ...sql.Querier) func(s *sql.Selector) { + return func(s *sql.Selector) { + d := sql.Dialect(s.Dialect()) + s.SetDistinct(false) + with := d.With("src_query"). + As(s.Clone()). + With("limited_query"). + As( + d.Select("*"). + AppendSelectExprAs( + sql.RowNumber().PartitionBy(partitionBy).OrderExpr(orderBy...), + "row_number", + ). + From(d.Table("src_query")), + ) + t := d.Table("limited_query").As(s.TableName()) + *s = *d.Select(s.UnqualifiedColumns()...). + From(t). + Where(sql.LTE(t.C("row_number"), limit)). + Prefix(with) + } +} + +// mayAddCondition appends another type condition to the satisfies list +// if it does not exist in the list. +func mayAddCondition(satisfies []string, typeCond []string) []string { +Cond: + for _, c := range typeCond { + for _, s := range satisfies { + if c == s { + continue Cond + } + } + satisfies = append(satisfies, c) + } + return satisfies +} diff --git a/internal/ent/gql_edge.go b/internal/ent/gql_edge.go new file mode 100644 index 0000000..553a2be --- /dev/null +++ b/internal/ent/gql_edge.go @@ -0,0 +1,49 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "github.com/99designs/gqlgen/graphql" +) + +func (e *Event) User(ctx context.Context) (*User, error) { + result, err := e.Edges.UserOrErr() + if IsNotLoaded(err) { + result, err = e.QueryUser().Only(ctx) + } + return result, MaskNotFound(err) +} + +func (e *Event) Research(ctx context.Context) (*Research, error) { + result, err := e.Edges.ResearchOrErr() + if IsNotLoaded(err) { + result, err = e.QueryResearch().Only(ctx) + } + return result, MaskNotFound(err) +} + +func (r *Research) Events(ctx context.Context) (result []*Event, err error) { + if fc := graphql.GetFieldContext(ctx); fc != nil && fc.Field.Alias != "" { + result, err = r.NamedEvents(graphql.GetFieldContext(ctx).Field.Alias) + } else { + result, err = r.Edges.EventsOrErr() + } + if IsNotLoaded(err) { + result, err = r.QueryEvents().All(ctx) + } + return result, err +} + +func (u *User) Events(ctx context.Context) (result []*Event, err error) { + if fc := graphql.GetFieldContext(ctx); fc != nil && fc.Field.Alias != "" { + result, err = u.NamedEvents(graphql.GetFieldContext(ctx).Field.Alias) + } else { + result, err = u.Edges.EventsOrErr() + } + if IsNotLoaded(err) { + result, err = u.QueryEvents().All(ctx) + } + return result, err +} diff --git a/internal/ent/gql_node.go b/internal/ent/gql_node.go new file mode 100644 index 0000000..3245978 --- /dev/null +++ b/internal/ent/gql_node.go @@ -0,0 +1,256 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + + "entgo.io/contrib/entgql" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/user" + "github.com/99designs/gqlgen/graphql" + "github.com/hashicorp/go-multierror" +) + +// Noder wraps the basic Node method. +type Noder interface { + IsNode() +} + +var eventImplementors = []string{"Event", "Node"} + +// IsNode implements the Node interface check for GQLGen. +func (*Event) IsNode() {} + +var researchImplementors = []string{"Research", "Node"} + +// IsNode implements the Node interface check for GQLGen. +func (*Research) IsNode() {} + +var userImplementors = []string{"User", "Node"} + +// IsNode implements the Node interface check for GQLGen. +func (*User) IsNode() {} + +var errNodeInvalidID = &NotFoundError{"node"} + +// NodeOption allows configuring the Noder execution using functional options. +type NodeOption func(*nodeOptions) + +// WithNodeType sets the node Type resolver function (i.e. the table to query). +// If was not provided, the table will be derived from the universal-id +// configuration as described in: https://entgo.io/docs/migrate/#universal-ids. +func WithNodeType(f func(context.Context, string) (string, error)) NodeOption { + return func(o *nodeOptions) { + o.nodeType = f + } +} + +// WithFixedNodeType sets the Type of the node to a fixed value. +func WithFixedNodeType(t string) NodeOption { + return WithNodeType(func(context.Context, string) (string, error) { + return t, nil + }) +} + +type nodeOptions struct { + nodeType func(context.Context, string) (string, error) +} + +func (c *Client) newNodeOpts(opts []NodeOption) *nodeOptions { + nopts := &nodeOptions{} + for _, opt := range opts { + opt(nopts) + } + if nopts.nodeType == nil { + nopts.nodeType = func(ctx context.Context, id string) (string, error) { + return "", fmt.Errorf("cannot resolve noder (%v) without its type", id) + } + } + return nopts +} + +// Noder returns a Node by its id. If the NodeType was not provided, it will +// be derived from the id value according to the universal-id configuration. +// +// c.Noder(ctx, id) +// c.Noder(ctx, id, ent.WithNodeType(typeResolver)) +func (c *Client) Noder(ctx context.Context, id string, opts ...NodeOption) (_ Noder, err error) { + defer func() { + if IsNotFound(err) { + err = multierror.Append(err, entgql.ErrNodeNotFound(id)) + } + }() + table, err := c.newNodeOpts(opts).nodeType(ctx, id) + if err != nil { + return nil, err + } + return c.noder(ctx, table, id) +} + +func (c *Client) noder(ctx context.Context, table string, id string) (Noder, error) { + switch table { + case event.Table: + query := c.Event.Query(). + Where(event.ID(id)) + query, err := query.CollectFields(ctx, eventImplementors...) + if err != nil { + return nil, err + } + n, err := query.Only(ctx) + if err != nil { + return nil, err + } + return n, nil + case research.Table: + query := c.Research.Query(). + Where(research.ID(id)) + query, err := query.CollectFields(ctx, researchImplementors...) + if err != nil { + return nil, err + } + n, err := query.Only(ctx) + if err != nil { + return nil, err + } + return n, nil + case user.Table: + query := c.User.Query(). + Where(user.ID(id)) + query, err := query.CollectFields(ctx, userImplementors...) + if err != nil { + return nil, err + } + n, err := query.Only(ctx) + if err != nil { + return nil, err + } + return n, nil + default: + return nil, fmt.Errorf("cannot resolve noder from table %q: %w", table, errNodeInvalidID) + } +} + +func (c *Client) Noders(ctx context.Context, ids []string, opts ...NodeOption) ([]Noder, error) { + switch len(ids) { + case 1: + noder, err := c.Noder(ctx, ids[0], opts...) + if err != nil { + return nil, err + } + return []Noder{noder}, nil + case 0: + return []Noder{}, nil + } + + noders := make([]Noder, len(ids)) + errors := make([]error, len(ids)) + tables := make(map[string][]string) + id2idx := make(map[string][]int, len(ids)) + nopts := c.newNodeOpts(opts) + for i, id := range ids { + table, err := nopts.nodeType(ctx, id) + if err != nil { + errors[i] = err + continue + } + tables[table] = append(tables[table], id) + id2idx[id] = append(id2idx[id], i) + } + + for table, ids := range tables { + nodes, err := c.noders(ctx, table, ids) + if err != nil { + for _, id := range ids { + for _, idx := range id2idx[id] { + errors[idx] = err + } + } + } else { + for i, id := range ids { + for _, idx := range id2idx[id] { + noders[idx] = nodes[i] + } + } + } + } + + for i, id := range ids { + if errors[i] == nil { + if noders[i] != nil { + continue + } + errors[i] = entgql.ErrNodeNotFound(id) + } else if IsNotFound(errors[i]) { + errors[i] = multierror.Append(errors[i], entgql.ErrNodeNotFound(id)) + } + ctx := graphql.WithPathContext(ctx, + graphql.NewPathWithIndex(i), + ) + graphql.AddError(ctx, errors[i]) + } + return noders, nil +} + +func (c *Client) noders(ctx context.Context, table string, ids []string) ([]Noder, error) { + noders := make([]Noder, len(ids)) + idmap := make(map[string][]*Noder, len(ids)) + for i, id := range ids { + idmap[id] = append(idmap[id], &noders[i]) + } + switch table { + case event.Table: + query := c.Event.Query(). + Where(event.IDIn(ids...)) + query, err := query.CollectFields(ctx, eventImplementors...) + if err != nil { + return nil, err + } + nodes, err := query.All(ctx) + if err != nil { + return nil, err + } + for _, node := range nodes { + for _, noder := range idmap[node.ID] { + *noder = node + } + } + case research.Table: + query := c.Research.Query(). + Where(research.IDIn(ids...)) + query, err := query.CollectFields(ctx, researchImplementors...) + if err != nil { + return nil, err + } + nodes, err := query.All(ctx) + if err != nil { + return nil, err + } + for _, node := range nodes { + for _, noder := range idmap[node.ID] { + *noder = node + } + } + case user.Table: + query := c.User.Query(). + Where(user.IDIn(ids...)) + query, err := query.CollectFields(ctx, userImplementors...) + if err != nil { + return nil, err + } + nodes, err := query.All(ctx) + if err != nil { + return nil, err + } + for _, node := range nodes { + for _, noder := range idmap[node.ID] { + *noder = node + } + } + default: + return nil, fmt.Errorf("cannot resolve noders from table %q: %w", table, errNodeInvalidID) + } + return noders, nil +} diff --git a/internal/ent/gql_pagination.go b/internal/ent/gql_pagination.go new file mode 100644 index 0000000..0df9a06 --- /dev/null +++ b/internal/ent/gql_pagination.go @@ -0,0 +1,957 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "io" + "strconv" + + "entgo.io/contrib/entgql" + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/user" + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/errcode" + "github.com/vektah/gqlparser/v2/gqlerror" +) + +// Common entgql types. +type ( + Cursor = entgql.Cursor[string] + PageInfo = entgql.PageInfo[string] + OrderDirection = entgql.OrderDirection +) + +func orderFunc(o OrderDirection, field string) func(*sql.Selector) { + if o == entgql.OrderDirectionDesc { + return Desc(field) + } + return Asc(field) +} + +const errInvalidPagination = "INVALID_PAGINATION" + +func validateFirstLast(first, last *int) (err *gqlerror.Error) { + switch { + case first != nil && last != nil: + err = &gqlerror.Error{ + Message: "Passing both `first` and `last` to paginate a connection is not supported.", + } + case first != nil && *first < 0: + err = &gqlerror.Error{ + Message: "`first` on a connection cannot be less than zero.", + } + errcode.Set(err, errInvalidPagination) + case last != nil && *last < 0: + err = &gqlerror.Error{ + Message: "`last` on a connection cannot be less than zero.", + } + errcode.Set(err, errInvalidPagination) + } + return err +} + +func collectedField(ctx context.Context, path ...string) *graphql.CollectedField { + fc := graphql.GetFieldContext(ctx) + if fc == nil { + return nil + } + field := fc.Field + oc := graphql.GetOperationContext(ctx) +walk: + for _, name := range path { + for _, f := range graphql.CollectFields(oc, field.Selections, nil) { + if f.Alias == name { + field = f + continue walk + } + } + return nil + } + return &field +} + +func hasCollectedField(ctx context.Context, path ...string) bool { + if graphql.GetFieldContext(ctx) == nil { + return true + } + return collectedField(ctx, path...) != nil +} + +const ( + edgesField = "edges" + nodeField = "node" + pageInfoField = "pageInfo" + totalCountField = "totalCount" +) + +func paginateLimit(first, last *int) int { + var limit int + if first != nil { + limit = *first + 1 + } else if last != nil { + limit = *last + 1 + } + return limit +} + +// EventEdge is the edge representation of Event. +type EventEdge struct { + Node *Event `json:"node"` + Cursor Cursor `json:"cursor"` +} + +// EventConnection is the connection containing edges to Event. +type EventConnection struct { + Edges []*EventEdge `json:"edges"` + PageInfo PageInfo `json:"pageInfo"` + TotalCount int `json:"totalCount"` +} + +func (c *EventConnection) build(nodes []*Event, pager *eventPager, after *Cursor, first *int, before *Cursor, last *int) { + c.PageInfo.HasNextPage = before != nil + c.PageInfo.HasPreviousPage = after != nil + if first != nil && *first+1 == len(nodes) { + c.PageInfo.HasNextPage = true + nodes = nodes[:len(nodes)-1] + } else if last != nil && *last+1 == len(nodes) { + c.PageInfo.HasPreviousPage = true + nodes = nodes[:len(nodes)-1] + } + var nodeAt func(int) *Event + if last != nil { + n := len(nodes) - 1 + nodeAt = func(i int) *Event { + return nodes[n-i] + } + } else { + nodeAt = func(i int) *Event { + return nodes[i] + } + } + c.Edges = make([]*EventEdge, len(nodes)) + for i := range nodes { + node := nodeAt(i) + c.Edges[i] = &EventEdge{ + Node: node, + Cursor: pager.toCursor(node), + } + } + if l := len(c.Edges); l > 0 { + c.PageInfo.StartCursor = &c.Edges[0].Cursor + c.PageInfo.EndCursor = &c.Edges[l-1].Cursor + } + if c.TotalCount == 0 { + c.TotalCount = len(nodes) + } +} + +// EventPaginateOption enables pagination customization. +type EventPaginateOption func(*eventPager) error + +// WithEventOrder configures pagination ordering. +func WithEventOrder(order *EventOrder) EventPaginateOption { + if order == nil { + order = DefaultEventOrder + } + o := *order + return func(pager *eventPager) error { + if err := o.Direction.Validate(); err != nil { + return err + } + if o.Field == nil { + o.Field = DefaultEventOrder.Field + } + pager.order = &o + return nil + } +} + +// WithEventFilter configures pagination filter. +func WithEventFilter(filter func(*EventQuery) (*EventQuery, error)) EventPaginateOption { + return func(pager *eventPager) error { + if filter == nil { + return errors.New("EventQuery filter cannot be nil") + } + pager.filter = filter + return nil + } +} + +type eventPager struct { + reverse bool + order *EventOrder + filter func(*EventQuery) (*EventQuery, error) +} + +func newEventPager(opts []EventPaginateOption, reverse bool) (*eventPager, error) { + pager := &eventPager{reverse: reverse} + for _, opt := range opts { + if err := opt(pager); err != nil { + return nil, err + } + } + if pager.order == nil { + pager.order = DefaultEventOrder + } + return pager, nil +} + +func (p *eventPager) applyFilter(query *EventQuery) (*EventQuery, error) { + if p.filter != nil { + return p.filter(query) + } + return query, nil +} + +func (p *eventPager) toCursor(e *Event) Cursor { + return p.order.Field.toCursor(e) +} + +func (p *eventPager) applyCursors(query *EventQuery, after, before *Cursor) (*EventQuery, error) { + direction := p.order.Direction + if p.reverse { + direction = direction.Reverse() + } + for _, predicate := range entgql.CursorsPredicate(after, before, DefaultEventOrder.Field.column, p.order.Field.column, direction) { + query = query.Where(predicate) + } + return query, nil +} + +func (p *eventPager) applyOrder(query *EventQuery) *EventQuery { + direction := p.order.Direction + if p.reverse { + direction = direction.Reverse() + } + query = query.Order(p.order.Field.toTerm(direction.OrderTermOption())) + if p.order.Field != DefaultEventOrder.Field { + query = query.Order(DefaultEventOrder.Field.toTerm(direction.OrderTermOption())) + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(p.order.Field.column) + } + return query +} + +func (p *eventPager) orderExpr(query *EventQuery) sql.Querier { + direction := p.order.Direction + if p.reverse { + direction = direction.Reverse() + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(p.order.Field.column) + } + return sql.ExprFunc(func(b *sql.Builder) { + b.Ident(p.order.Field.column).Pad().WriteString(string(direction)) + if p.order.Field != DefaultEventOrder.Field { + b.Comma().Ident(DefaultEventOrder.Field.column).Pad().WriteString(string(direction)) + } + }) +} + +// Paginate executes the query and returns a relay based cursor connection to Event. +func (e *EventQuery) Paginate( + ctx context.Context, after *Cursor, first *int, + before *Cursor, last *int, opts ...EventPaginateOption, +) (*EventConnection, error) { + if err := validateFirstLast(first, last); err != nil { + return nil, err + } + pager, err := newEventPager(opts, last != nil) + if err != nil { + return nil, err + } + if e, err = pager.applyFilter(e); err != nil { + return nil, err + } + conn := &EventConnection{Edges: []*EventEdge{}} + ignoredEdges := !hasCollectedField(ctx, edgesField) + if hasCollectedField(ctx, totalCountField) || hasCollectedField(ctx, pageInfoField) { + hasPagination := after != nil || first != nil || before != nil || last != nil + if hasPagination || ignoredEdges { + c := e.Clone() + c.ctx.Fields = nil + if conn.TotalCount, err = c.Count(ctx); err != nil { + return nil, err + } + conn.PageInfo.HasNextPage = first != nil && conn.TotalCount > 0 + conn.PageInfo.HasPreviousPage = last != nil && conn.TotalCount > 0 + } + } + if ignoredEdges || (first != nil && *first == 0) || (last != nil && *last == 0) { + return conn, nil + } + if e, err = pager.applyCursors(e, after, before); err != nil { + return nil, err + } + if limit := paginateLimit(first, last); limit != 0 { + e.Limit(limit) + } + if field := collectedField(ctx, edgesField, nodeField); field != nil { + if err := e.collectField(ctx, graphql.GetOperationContext(ctx), *field, []string{edgesField, nodeField}); err != nil { + return nil, err + } + } + e = pager.applyOrder(e) + nodes, err := e.All(ctx) + if err != nil { + return nil, err + } + conn.build(nodes, pager, after, first, before, last) + return conn, nil +} + +var ( + // EventOrderFieldID orders Event by id. + EventOrderFieldID = &EventOrderField{ + Value: func(e *Event) (ent.Value, error) { + return e.ID, nil + }, + column: event.FieldID, + toTerm: event.ByID, + toCursor: func(e *Event) Cursor { + return Cursor{ + ID: e.ID, + Value: e.ID, + } + }, + } + // EventOrderFieldCreatedAt orders Event by created_at. + EventOrderFieldCreatedAt = &EventOrderField{ + Value: func(e *Event) (ent.Value, error) { + return e.CreatedAt, nil + }, + column: event.FieldCreatedAt, + toTerm: event.ByCreatedAt, + toCursor: func(e *Event) Cursor { + return Cursor{ + ID: e.ID, + Value: e.CreatedAt, + } + }, + } +) + +// String implement fmt.Stringer interface. +func (f EventOrderField) String() string { + var str string + switch f.column { + case EventOrderFieldID.column: + str = "ID" + case EventOrderFieldCreatedAt.column: + str = "CREATED_AT" + } + return str +} + +// MarshalGQL implements graphql.Marshaler interface. +func (f EventOrderField) MarshalGQL(w io.Writer) { + io.WriteString(w, strconv.Quote(f.String())) +} + +// UnmarshalGQL implements graphql.Unmarshaler interface. +func (f *EventOrderField) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("EventOrderField %T must be a string", v) + } + switch str { + case "ID": + *f = *EventOrderFieldID + case "CREATED_AT": + *f = *EventOrderFieldCreatedAt + default: + return fmt.Errorf("%s is not a valid EventOrderField", str) + } + return nil +} + +// EventOrderField defines the ordering field of Event. +type EventOrderField struct { + // Value extracts the ordering value from the given Event. + Value func(*Event) (ent.Value, error) + column string // field or computed. + toTerm func(...sql.OrderTermOption) event.OrderOption + toCursor func(*Event) Cursor +} + +// EventOrder defines the ordering of Event. +type EventOrder struct { + Direction OrderDirection `json:"direction"` + Field *EventOrderField `json:"field"` +} + +// DefaultEventOrder is the default ordering of Event. +var DefaultEventOrder = &EventOrder{ + Direction: entgql.OrderDirectionAsc, + Field: &EventOrderField{ + Value: func(e *Event) (ent.Value, error) { + return e.ID, nil + }, + column: event.FieldID, + toTerm: event.ByID, + toCursor: func(e *Event) Cursor { + return Cursor{ID: e.ID} + }, + }, +} + +// ToEdge converts Event into EventEdge. +func (e *Event) ToEdge(order *EventOrder) *EventEdge { + if order == nil { + order = DefaultEventOrder + } + return &EventEdge{ + Node: e, + Cursor: order.Field.toCursor(e), + } +} + +// ResearchEdge is the edge representation of Research. +type ResearchEdge struct { + Node *Research `json:"node"` + Cursor Cursor `json:"cursor"` +} + +// ResearchConnection is the connection containing edges to Research. +type ResearchConnection struct { + Edges []*ResearchEdge `json:"edges"` + PageInfo PageInfo `json:"pageInfo"` + TotalCount int `json:"totalCount"` +} + +func (c *ResearchConnection) build(nodes []*Research, pager *researchPager, after *Cursor, first *int, before *Cursor, last *int) { + c.PageInfo.HasNextPage = before != nil + c.PageInfo.HasPreviousPage = after != nil + if first != nil && *first+1 == len(nodes) { + c.PageInfo.HasNextPage = true + nodes = nodes[:len(nodes)-1] + } else if last != nil && *last+1 == len(nodes) { + c.PageInfo.HasPreviousPage = true + nodes = nodes[:len(nodes)-1] + } + var nodeAt func(int) *Research + if last != nil { + n := len(nodes) - 1 + nodeAt = func(i int) *Research { + return nodes[n-i] + } + } else { + nodeAt = func(i int) *Research { + return nodes[i] + } + } + c.Edges = make([]*ResearchEdge, len(nodes)) + for i := range nodes { + node := nodeAt(i) + c.Edges[i] = &ResearchEdge{ + Node: node, + Cursor: pager.toCursor(node), + } + } + if l := len(c.Edges); l > 0 { + c.PageInfo.StartCursor = &c.Edges[0].Cursor + c.PageInfo.EndCursor = &c.Edges[l-1].Cursor + } + if c.TotalCount == 0 { + c.TotalCount = len(nodes) + } +} + +// ResearchPaginateOption enables pagination customization. +type ResearchPaginateOption func(*researchPager) error + +// WithResearchOrder configures pagination ordering. +func WithResearchOrder(order *ResearchOrder) ResearchPaginateOption { + if order == nil { + order = DefaultResearchOrder + } + o := *order + return func(pager *researchPager) error { + if err := o.Direction.Validate(); err != nil { + return err + } + if o.Field == nil { + o.Field = DefaultResearchOrder.Field + } + pager.order = &o + return nil + } +} + +// WithResearchFilter configures pagination filter. +func WithResearchFilter(filter func(*ResearchQuery) (*ResearchQuery, error)) ResearchPaginateOption { + return func(pager *researchPager) error { + if filter == nil { + return errors.New("ResearchQuery filter cannot be nil") + } + pager.filter = filter + return nil + } +} + +type researchPager struct { + reverse bool + order *ResearchOrder + filter func(*ResearchQuery) (*ResearchQuery, error) +} + +func newResearchPager(opts []ResearchPaginateOption, reverse bool) (*researchPager, error) { + pager := &researchPager{reverse: reverse} + for _, opt := range opts { + if err := opt(pager); err != nil { + return nil, err + } + } + if pager.order == nil { + pager.order = DefaultResearchOrder + } + return pager, nil +} + +func (p *researchPager) applyFilter(query *ResearchQuery) (*ResearchQuery, error) { + if p.filter != nil { + return p.filter(query) + } + return query, nil +} + +func (p *researchPager) toCursor(r *Research) Cursor { + return p.order.Field.toCursor(r) +} + +func (p *researchPager) applyCursors(query *ResearchQuery, after, before *Cursor) (*ResearchQuery, error) { + direction := p.order.Direction + if p.reverse { + direction = direction.Reverse() + } + for _, predicate := range entgql.CursorsPredicate(after, before, DefaultResearchOrder.Field.column, p.order.Field.column, direction) { + query = query.Where(predicate) + } + return query, nil +} + +func (p *researchPager) applyOrder(query *ResearchQuery) *ResearchQuery { + direction := p.order.Direction + if p.reverse { + direction = direction.Reverse() + } + query = query.Order(p.order.Field.toTerm(direction.OrderTermOption())) + if p.order.Field != DefaultResearchOrder.Field { + query = query.Order(DefaultResearchOrder.Field.toTerm(direction.OrderTermOption())) + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(p.order.Field.column) + } + return query +} + +func (p *researchPager) orderExpr(query *ResearchQuery) sql.Querier { + direction := p.order.Direction + if p.reverse { + direction = direction.Reverse() + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(p.order.Field.column) + } + return sql.ExprFunc(func(b *sql.Builder) { + b.Ident(p.order.Field.column).Pad().WriteString(string(direction)) + if p.order.Field != DefaultResearchOrder.Field { + b.Comma().Ident(DefaultResearchOrder.Field.column).Pad().WriteString(string(direction)) + } + }) +} + +// Paginate executes the query and returns a relay based cursor connection to Research. +func (r *ResearchQuery) Paginate( + ctx context.Context, after *Cursor, first *int, + before *Cursor, last *int, opts ...ResearchPaginateOption, +) (*ResearchConnection, error) { + if err := validateFirstLast(first, last); err != nil { + return nil, err + } + pager, err := newResearchPager(opts, last != nil) + if err != nil { + return nil, err + } + if r, err = pager.applyFilter(r); err != nil { + return nil, err + } + conn := &ResearchConnection{Edges: []*ResearchEdge{}} + ignoredEdges := !hasCollectedField(ctx, edgesField) + if hasCollectedField(ctx, totalCountField) || hasCollectedField(ctx, pageInfoField) { + hasPagination := after != nil || first != nil || before != nil || last != nil + if hasPagination || ignoredEdges { + c := r.Clone() + c.ctx.Fields = nil + if conn.TotalCount, err = c.Count(ctx); err != nil { + return nil, err + } + conn.PageInfo.HasNextPage = first != nil && conn.TotalCount > 0 + conn.PageInfo.HasPreviousPage = last != nil && conn.TotalCount > 0 + } + } + if ignoredEdges || (first != nil && *first == 0) || (last != nil && *last == 0) { + return conn, nil + } + if r, err = pager.applyCursors(r, after, before); err != nil { + return nil, err + } + if limit := paginateLimit(first, last); limit != 0 { + r.Limit(limit) + } + if field := collectedField(ctx, edgesField, nodeField); field != nil { + if err := r.collectField(ctx, graphql.GetOperationContext(ctx), *field, []string{edgesField, nodeField}); err != nil { + return nil, err + } + } + r = pager.applyOrder(r) + nodes, err := r.All(ctx) + if err != nil { + return nil, err + } + conn.build(nodes, pager, after, first, before, last) + return conn, nil +} + +var ( + // ResearchOrderFieldID orders Research by id. + ResearchOrderFieldID = &ResearchOrderField{ + Value: func(r *Research) (ent.Value, error) { + return r.ID, nil + }, + column: research.FieldID, + toTerm: research.ByID, + toCursor: func(r *Research) Cursor { + return Cursor{ + ID: r.ID, + Value: r.ID, + } + }, + } +) + +// String implement fmt.Stringer interface. +func (f ResearchOrderField) String() string { + var str string + switch f.column { + case ResearchOrderFieldID.column: + str = "ID" + } + return str +} + +// MarshalGQL implements graphql.Marshaler interface. +func (f ResearchOrderField) MarshalGQL(w io.Writer) { + io.WriteString(w, strconv.Quote(f.String())) +} + +// UnmarshalGQL implements graphql.Unmarshaler interface. +func (f *ResearchOrderField) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("ResearchOrderField %T must be a string", v) + } + switch str { + case "ID": + *f = *ResearchOrderFieldID + default: + return fmt.Errorf("%s is not a valid ResearchOrderField", str) + } + return nil +} + +// ResearchOrderField defines the ordering field of Research. +type ResearchOrderField struct { + // Value extracts the ordering value from the given Research. + Value func(*Research) (ent.Value, error) + column string // field or computed. + toTerm func(...sql.OrderTermOption) research.OrderOption + toCursor func(*Research) Cursor +} + +// ResearchOrder defines the ordering of Research. +type ResearchOrder struct { + Direction OrderDirection `json:"direction"` + Field *ResearchOrderField `json:"field"` +} + +// DefaultResearchOrder is the default ordering of Research. +var DefaultResearchOrder = &ResearchOrder{ + Direction: entgql.OrderDirectionAsc, + Field: &ResearchOrderField{ + Value: func(r *Research) (ent.Value, error) { + return r.ID, nil + }, + column: research.FieldID, + toTerm: research.ByID, + toCursor: func(r *Research) Cursor { + return Cursor{ID: r.ID} + }, + }, +} + +// ToEdge converts Research into ResearchEdge. +func (r *Research) ToEdge(order *ResearchOrder) *ResearchEdge { + if order == nil { + order = DefaultResearchOrder + } + return &ResearchEdge{ + Node: r, + Cursor: order.Field.toCursor(r), + } +} + +// UserEdge is the edge representation of User. +type UserEdge struct { + Node *User `json:"node"` + Cursor Cursor `json:"cursor"` +} + +// UserConnection is the connection containing edges to User. +type UserConnection struct { + Edges []*UserEdge `json:"edges"` + PageInfo PageInfo `json:"pageInfo"` + TotalCount int `json:"totalCount"` +} + +func (c *UserConnection) build(nodes []*User, pager *userPager, after *Cursor, first *int, before *Cursor, last *int) { + c.PageInfo.HasNextPage = before != nil + c.PageInfo.HasPreviousPage = after != nil + if first != nil && *first+1 == len(nodes) { + c.PageInfo.HasNextPage = true + nodes = nodes[:len(nodes)-1] + } else if last != nil && *last+1 == len(nodes) { + c.PageInfo.HasPreviousPage = true + nodes = nodes[:len(nodes)-1] + } + var nodeAt func(int) *User + if last != nil { + n := len(nodes) - 1 + nodeAt = func(i int) *User { + return nodes[n-i] + } + } else { + nodeAt = func(i int) *User { + return nodes[i] + } + } + c.Edges = make([]*UserEdge, len(nodes)) + for i := range nodes { + node := nodeAt(i) + c.Edges[i] = &UserEdge{ + Node: node, + Cursor: pager.toCursor(node), + } + } + if l := len(c.Edges); l > 0 { + c.PageInfo.StartCursor = &c.Edges[0].Cursor + c.PageInfo.EndCursor = &c.Edges[l-1].Cursor + } + if c.TotalCount == 0 { + c.TotalCount = len(nodes) + } +} + +// UserPaginateOption enables pagination customization. +type UserPaginateOption func(*userPager) error + +// WithUserOrder configures pagination ordering. +func WithUserOrder(order *UserOrder) UserPaginateOption { + if order == nil { + order = DefaultUserOrder + } + o := *order + return func(pager *userPager) error { + if err := o.Direction.Validate(); err != nil { + return err + } + if o.Field == nil { + o.Field = DefaultUserOrder.Field + } + pager.order = &o + return nil + } +} + +// WithUserFilter configures pagination filter. +func WithUserFilter(filter func(*UserQuery) (*UserQuery, error)) UserPaginateOption { + return func(pager *userPager) error { + if filter == nil { + return errors.New("UserQuery filter cannot be nil") + } + pager.filter = filter + return nil + } +} + +type userPager struct { + reverse bool + order *UserOrder + filter func(*UserQuery) (*UserQuery, error) +} + +func newUserPager(opts []UserPaginateOption, reverse bool) (*userPager, error) { + pager := &userPager{reverse: reverse} + for _, opt := range opts { + if err := opt(pager); err != nil { + return nil, err + } + } + if pager.order == nil { + pager.order = DefaultUserOrder + } + return pager, nil +} + +func (p *userPager) applyFilter(query *UserQuery) (*UserQuery, error) { + if p.filter != nil { + return p.filter(query) + } + return query, nil +} + +func (p *userPager) toCursor(u *User) Cursor { + return p.order.Field.toCursor(u) +} + +func (p *userPager) applyCursors(query *UserQuery, after, before *Cursor) (*UserQuery, error) { + direction := p.order.Direction + if p.reverse { + direction = direction.Reverse() + } + for _, predicate := range entgql.CursorsPredicate(after, before, DefaultUserOrder.Field.column, p.order.Field.column, direction) { + query = query.Where(predicate) + } + return query, nil +} + +func (p *userPager) applyOrder(query *UserQuery) *UserQuery { + direction := p.order.Direction + if p.reverse { + direction = direction.Reverse() + } + query = query.Order(p.order.Field.toTerm(direction.OrderTermOption())) + if p.order.Field != DefaultUserOrder.Field { + query = query.Order(DefaultUserOrder.Field.toTerm(direction.OrderTermOption())) + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(p.order.Field.column) + } + return query +} + +func (p *userPager) orderExpr(query *UserQuery) sql.Querier { + direction := p.order.Direction + if p.reverse { + direction = direction.Reverse() + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(p.order.Field.column) + } + return sql.ExprFunc(func(b *sql.Builder) { + b.Ident(p.order.Field.column).Pad().WriteString(string(direction)) + if p.order.Field != DefaultUserOrder.Field { + b.Comma().Ident(DefaultUserOrder.Field.column).Pad().WriteString(string(direction)) + } + }) +} + +// Paginate executes the query and returns a relay based cursor connection to User. +func (u *UserQuery) Paginate( + ctx context.Context, after *Cursor, first *int, + before *Cursor, last *int, opts ...UserPaginateOption, +) (*UserConnection, error) { + if err := validateFirstLast(first, last); err != nil { + return nil, err + } + pager, err := newUserPager(opts, last != nil) + if err != nil { + return nil, err + } + if u, err = pager.applyFilter(u); err != nil { + return nil, err + } + conn := &UserConnection{Edges: []*UserEdge{}} + ignoredEdges := !hasCollectedField(ctx, edgesField) + if hasCollectedField(ctx, totalCountField) || hasCollectedField(ctx, pageInfoField) { + hasPagination := after != nil || first != nil || before != nil || last != nil + if hasPagination || ignoredEdges { + c := u.Clone() + c.ctx.Fields = nil + if conn.TotalCount, err = c.Count(ctx); err != nil { + return nil, err + } + conn.PageInfo.HasNextPage = first != nil && conn.TotalCount > 0 + conn.PageInfo.HasPreviousPage = last != nil && conn.TotalCount > 0 + } + } + if ignoredEdges || (first != nil && *first == 0) || (last != nil && *last == 0) { + return conn, nil + } + if u, err = pager.applyCursors(u, after, before); err != nil { + return nil, err + } + if limit := paginateLimit(first, last); limit != 0 { + u.Limit(limit) + } + if field := collectedField(ctx, edgesField, nodeField); field != nil { + if err := u.collectField(ctx, graphql.GetOperationContext(ctx), *field, []string{edgesField, nodeField}); err != nil { + return nil, err + } + } + u = pager.applyOrder(u) + nodes, err := u.All(ctx) + if err != nil { + return nil, err + } + conn.build(nodes, pager, after, first, before, last) + return conn, nil +} + +// UserOrderField defines the ordering field of User. +type UserOrderField struct { + // Value extracts the ordering value from the given User. + Value func(*User) (ent.Value, error) + column string // field or computed. + toTerm func(...sql.OrderTermOption) user.OrderOption + toCursor func(*User) Cursor +} + +// UserOrder defines the ordering of User. +type UserOrder struct { + Direction OrderDirection `json:"direction"` + Field *UserOrderField `json:"field"` +} + +// DefaultUserOrder is the default ordering of User. +var DefaultUserOrder = &UserOrder{ + Direction: entgql.OrderDirectionAsc, + Field: &UserOrderField{ + Value: func(u *User) (ent.Value, error) { + return u.ID, nil + }, + column: user.FieldID, + toTerm: user.ByID, + toCursor: func(u *User) Cursor { + return Cursor{ID: u.ID} + }, + }, +} + +// ToEdge converts User into UserEdge. +func (u *User) ToEdge(order *UserOrder) *UserEdge { + if order == nil { + order = DefaultUserOrder + } + return &UserEdge{ + Node: u, + Cursor: order.Field.toCursor(u), + } +} diff --git a/internal/ent/gql_transaction.go b/internal/ent/gql_transaction.go new file mode 100644 index 0000000..9611713 --- /dev/null +++ b/internal/ent/gql_transaction.go @@ -0,0 +1,30 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "database/sql/driver" + "errors" +) + +// OpenTx opens a transaction and returns a transactional +// context along with the created transaction. +func (c *Client) OpenTx(ctx context.Context) (context.Context, driver.Tx, error) { + tx, err := c.Tx(ctx) + if err != nil { + return nil, nil, err + } + ctx = NewTxContext(ctx, tx) + ctx = NewContext(ctx, tx.Client()) + return ctx, tx, nil +} + +// OpenTxFromContext open transactions from client stored in context. +func OpenTxFromContext(ctx context.Context) (context.Context, driver.Tx, error) { + client := FromContext(ctx) + if client == nil { + return nil, nil, errors.New("no client attached to context") + } + return client.OpenTx(ctx) +} diff --git a/internal/ent/hook/hook.go b/internal/ent/hook/hook.go new file mode 100644 index 0000000..c41b7d6 --- /dev/null +++ b/internal/ent/hook/hook.go @@ -0,0 +1,223 @@ +// Code generated by ent, DO NOT EDIT. + +package hook + +import ( + "context" + "fmt" + + "exusiai.dev/roguestats-backend/internal/ent" +) + +// The EventFunc type is an adapter to allow the use of ordinary +// function as Event mutator. +type EventFunc func(context.Context, *ent.EventMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f EventFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.EventMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.EventMutation", m) +} + +// The ResearchFunc type is an adapter to allow the use of ordinary +// function as Research mutator. +type ResearchFunc func(context.Context, *ent.ResearchMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f ResearchFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.ResearchMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ResearchMutation", m) +} + +// The UserFunc type is an adapter to allow the use of ordinary +// function as User mutator. +type UserFunc func(context.Context, *ent.UserMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.UserMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.UserMutation", m) +} + +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. +// +// hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) +func If(hk ent.Hook, cond Condition) ent.Hook { + return func(next ent.Mutator) ent.Mutator { + return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if cond(ctx, m) { + return hk(next).Mutate(ctx, m) + } + return next.Mutate(ctx, m) + }) + } +} + +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + +// Unless skips the given hook only for the given operation. +// +// hook.Unless(Log, ent.Update|ent.UpdateOne) +func Unless(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, Not(HasOp(op))) +} + +// FixedError is a hook returning a fixed error. +func FixedError(err error) ent.Hook { + return func(ent.Mutator) ent.Mutator { + return ent.MutateFunc(func(context.Context, ent.Mutation) (ent.Value, error) { + return nil, err + }) + } +} + +// Reject returns a hook that rejects all operations that match op. +// +// func (T) Hooks() []ent.Hook { +// return []ent.Hook{ +// Reject(ent.Delete|ent.Update), +// } +// } +func Reject(op ent.Op) ent.Hook { + hk := FixedError(fmt.Errorf("%s operation is not allowed", op)) + return On(hk, op) +} + +// Chain acts as a list of hooks and is effectively immutable. +// Once created, it will always hold the same set of hooks in the same order. +type Chain struct { + hooks []ent.Hook +} + +// NewChain creates a new chain of hooks. +func NewChain(hooks ...ent.Hook) Chain { + return Chain{append([]ent.Hook(nil), hooks...)} +} + +// Hook chains the list of hooks and returns the final hook. +func (c Chain) Hook() ent.Hook { + return func(mutator ent.Mutator) ent.Mutator { + for i := len(c.hooks) - 1; i >= 0; i-- { + mutator = c.hooks[i](mutator) + } + return mutator + } +} + +// Append extends a chain, adding the specified hook +// as the last ones in the mutation flow. +func (c Chain) Append(hooks ...ent.Hook) Chain { + newHooks := make([]ent.Hook, 0, len(c.hooks)+len(hooks)) + newHooks = append(newHooks, c.hooks...) + newHooks = append(newHooks, hooks...) + return Chain{newHooks} +} + +// Extend extends a chain, adding the specified chain +// as the last ones in the mutation flow. +func (c Chain) Extend(chain Chain) Chain { + return c.Append(chain.hooks...) +} diff --git a/internal/ent/migrate/migrate.go b/internal/ent/migrate/migrate.go new file mode 100644 index 0000000..1956a6b --- /dev/null +++ b/internal/ent/migrate/migrate.go @@ -0,0 +1,64 @@ +// Code generated by ent, DO NOT EDIT. + +package migrate + +import ( + "context" + "fmt" + "io" + + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql/schema" +) + +var ( + // WithGlobalUniqueID sets the universal ids options to the migration. + // If this option is enabled, ent migration will allocate a 1<<32 range + // for the ids of each entity (table). + // Note that this option cannot be applied on tables that already exist. + WithGlobalUniqueID = schema.WithGlobalUniqueID + // WithDropColumn sets the drop column option to the migration. + // If this option is enabled, ent migration will drop old columns + // that were used for both fields and edges. This defaults to false. + WithDropColumn = schema.WithDropColumn + // WithDropIndex sets the drop index option to the migration. + // If this option is enabled, ent migration will drop old indexes + // that were defined in the schema. This defaults to false. + // Note that unique constraints are defined using `UNIQUE INDEX`, + // and therefore, it's recommended to enable this option to get more + // flexibility in the schema changes. + WithDropIndex = schema.WithDropIndex + // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. + WithForeignKeys = schema.WithForeignKeys +) + +// Schema is the API for creating, migrating and dropping a schema. +type Schema struct { + drv dialect.Driver +} + +// NewSchema creates a new schema client. +func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } + +// Create creates all schema resources. +func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { + return Create(ctx, s, Tables, opts...) +} + +// Create creates all table resources using the given schema driver. +func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error { + migrate, err := schema.NewMigrate(s.drv, opts...) + if err != nil { + return fmt.Errorf("ent/migrate: %w", err) + } + return migrate.Create(ctx, tables...) +} + +// WriteTo writes the schema changes to w instead of running them against the database. +// +// if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { +// log.Fatal(err) +// } +func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { + return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...) +} diff --git a/internal/ent/migrate/schema.go b/internal/ent/migrate/schema.go new file mode 100644 index 0000000..6562ac9 --- /dev/null +++ b/internal/ent/migrate/schema.go @@ -0,0 +1,99 @@ +// Code generated by ent, DO NOT EDIT. + +package migrate + +import ( + "entgo.io/ent/dialect/sql/schema" + "entgo.io/ent/schema/field" +) + +var ( + // EventsColumns holds the columns for the "events" table. + EventsColumns = []*schema.Column{ + {Name: "event_id", Type: field.TypeString, Unique: true}, + {Name: "created_at", Type: field.TypeTime}, + {Name: "user_agent", Type: field.TypeString}, + {Name: "content", Type: field.TypeJSON}, + {Name: "research_events", Type: field.TypeString, Nullable: true}, + {Name: "user_events", Type: field.TypeString, Nullable: true}, + } + // EventsTable holds the schema information for the "events" table. + EventsTable = &schema.Table{ + Name: "events", + Columns: EventsColumns, + PrimaryKey: []*schema.Column{EventsColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "events_researches_events", + Columns: []*schema.Column{EventsColumns[4]}, + RefColumns: []*schema.Column{ResearchesColumns[0]}, + OnDelete: schema.NoAction, + }, + { + Symbol: "events_users_events", + Columns: []*schema.Column{EventsColumns[5]}, + RefColumns: []*schema.Column{UsersColumns[0]}, + OnDelete: schema.NoAction, + }, + }, + Indexes: []*schema.Index{ + { + Name: "event_created_at", + Unique: false, + Columns: []*schema.Column{EventsColumns[1]}, + }, + { + Name: "event_user_agent", + Unique: false, + Columns: []*schema.Column{EventsColumns[2]}, + }, + { + Name: "event_user_events", + Unique: false, + Columns: []*schema.Column{EventsColumns[5]}, + }, + { + Name: "event_research_events", + Unique: false, + Columns: []*schema.Column{EventsColumns[4]}, + }, + }, + } + // ResearchesColumns holds the columns for the "researches" table. + ResearchesColumns = []*schema.Column{ + {Name: "research_id", Type: field.TypeString, Unique: true}, + {Name: "name", Type: field.TypeString, Size: 64}, + {Name: "schema", Type: field.TypeJSON}, + } + // ResearchesTable holds the schema information for the "researches" table. + ResearchesTable = &schema.Table{ + Name: "researches", + Columns: ResearchesColumns, + PrimaryKey: []*schema.Column{ResearchesColumns[0]}, + } + // UsersColumns holds the columns for the "users" table. + UsersColumns = []*schema.Column{ + {Name: "user_id", Type: field.TypeString, Unique: true}, + {Name: "name", Type: field.TypeString, Size: 64}, + {Name: "email", Type: field.TypeString, Unique: true}, + {Name: "credential", Type: field.TypeString, Size: 64}, + {Name: "attributes", Type: field.TypeJSON, Nullable: true}, + } + // UsersTable holds the schema information for the "users" table. + UsersTable = &schema.Table{ + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, + } + // Tables holds all the tables in the schema. + Tables = []*schema.Table{ + EventsTable, + ResearchesTable, + UsersTable, + } +) + +func init() { + EventsTable.ForeignKeys[0].RefTable = ResearchesTable + EventsTable.ForeignKeys[1].RefTable = UsersTable +} diff --git a/internal/ent/mutation.go b/internal/ent/mutation.go new file mode 100644 index 0000000..9af2d0d --- /dev/null +++ b/internal/ent/mutation.go @@ -0,0 +1,1686 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/predicate" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +const ( + // Operation types. + OpCreate = ent.OpCreate + OpDelete = ent.OpDelete + OpDeleteOne = ent.OpDeleteOne + OpUpdate = ent.OpUpdate + OpUpdateOne = ent.OpUpdateOne + + // Node types. + TypeEvent = "Event" + TypeResearch = "Research" + TypeUser = "User" +) + +// EventMutation represents an operation that mutates the Event nodes in the graph. +type EventMutation struct { + config + op Op + typ string + id *string + created_at *time.Time + user_agent *string + content *map[string]interface{} + clearedFields map[string]struct{} + user *string + cleareduser bool + research *string + clearedresearch bool + done bool + oldValue func(context.Context) (*Event, error) + predicates []predicate.Event +} + +var _ ent.Mutation = (*EventMutation)(nil) + +// eventOption allows management of the mutation configuration using functional options. +type eventOption func(*EventMutation) + +// newEventMutation creates new mutation for the Event entity. +func newEventMutation(c config, op Op, opts ...eventOption) *EventMutation { + m := &EventMutation{ + config: c, + op: op, + typ: TypeEvent, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withEventID sets the ID field of the mutation. +func withEventID(id string) eventOption { + return func(m *EventMutation) { + var ( + err error + once sync.Once + value *Event + ) + m.oldValue = func(ctx context.Context) (*Event, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().Event.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withEvent sets the old Event of the mutation. +func withEvent(node *Event) eventOption { + return func(m *EventMutation) { + m.oldValue = func(context.Context) (*Event, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m EventMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m EventMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// SetID sets the value of the id field. Note that this +// operation is only accepted on creation of Event entities. +func (m *EventMutation) SetID(id string) { + m.id = &id +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *EventMutation) ID() (id string, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *EventMutation) IDs(ctx context.Context) ([]string, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []string{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().Event.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetCreatedAt sets the "created_at" field. +func (m *EventMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *EventMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the Event entity. +// If the Event object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *EventMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *EventMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUserAgent sets the "user_agent" field. +func (m *EventMutation) SetUserAgent(s string) { + m.user_agent = &s +} + +// UserAgent returns the value of the "user_agent" field in the mutation. +func (m *EventMutation) UserAgent() (r string, exists bool) { + v := m.user_agent + if v == nil { + return + } + return *v, true +} + +// OldUserAgent returns the old "user_agent" field's value of the Event entity. +// If the Event object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *EventMutation) OldUserAgent(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUserAgent is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUserAgent requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUserAgent: %w", err) + } + return oldValue.UserAgent, nil +} + +// ResetUserAgent resets all changes to the "user_agent" field. +func (m *EventMutation) ResetUserAgent() { + m.user_agent = nil +} + +// SetContent sets the "content" field. +func (m *EventMutation) SetContent(value map[string]interface{}) { + m.content = &value +} + +// Content returns the value of the "content" field in the mutation. +func (m *EventMutation) Content() (r map[string]interface{}, exists bool) { + v := m.content + if v == nil { + return + } + return *v, true +} + +// OldContent returns the old "content" field's value of the Event entity. +// If the Event object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *EventMutation) OldContent(ctx context.Context) (v map[string]interface{}, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldContent is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldContent requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldContent: %w", err) + } + return oldValue.Content, nil +} + +// ResetContent resets all changes to the "content" field. +func (m *EventMutation) ResetContent() { + m.content = nil +} + +// SetUserID sets the "user" edge to the User entity by id. +func (m *EventMutation) SetUserID(id string) { + m.user = &id +} + +// ClearUser clears the "user" edge to the User entity. +func (m *EventMutation) ClearUser() { + m.cleareduser = true +} + +// UserCleared reports if the "user" edge to the User entity was cleared. +func (m *EventMutation) UserCleared() bool { + return m.cleareduser +} + +// UserID returns the "user" edge ID in the mutation. +func (m *EventMutation) UserID() (id string, exists bool) { + if m.user != nil { + return *m.user, true + } + return +} + +// UserIDs returns the "user" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// UserID instead. It exists only for internal usage by the builders. +func (m *EventMutation) UserIDs() (ids []string) { + if id := m.user; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetUser resets all changes to the "user" edge. +func (m *EventMutation) ResetUser() { + m.user = nil + m.cleareduser = false +} + +// SetResearchID sets the "research" edge to the Research entity by id. +func (m *EventMutation) SetResearchID(id string) { + m.research = &id +} + +// ClearResearch clears the "research" edge to the Research entity. +func (m *EventMutation) ClearResearch() { + m.clearedresearch = true +} + +// ResearchCleared reports if the "research" edge to the Research entity was cleared. +func (m *EventMutation) ResearchCleared() bool { + return m.clearedresearch +} + +// ResearchID returns the "research" edge ID in the mutation. +func (m *EventMutation) ResearchID() (id string, exists bool) { + if m.research != nil { + return *m.research, true + } + return +} + +// ResearchIDs returns the "research" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// ResearchID instead. It exists only for internal usage by the builders. +func (m *EventMutation) ResearchIDs() (ids []string) { + if id := m.research; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetResearch resets all changes to the "research" edge. +func (m *EventMutation) ResetResearch() { + m.research = nil + m.clearedresearch = false +} + +// Where appends a list predicates to the EventMutation builder. +func (m *EventMutation) Where(ps ...predicate.Event) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the EventMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *EventMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.Event, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *EventMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *EventMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (Event). +func (m *EventMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *EventMutation) Fields() []string { + fields := make([]string, 0, 3) + if m.created_at != nil { + fields = append(fields, event.FieldCreatedAt) + } + if m.user_agent != nil { + fields = append(fields, event.FieldUserAgent) + } + if m.content != nil { + fields = append(fields, event.FieldContent) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *EventMutation) Field(name string) (ent.Value, bool) { + switch name { + case event.FieldCreatedAt: + return m.CreatedAt() + case event.FieldUserAgent: + return m.UserAgent() + case event.FieldContent: + return m.Content() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *EventMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case event.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case event.FieldUserAgent: + return m.OldUserAgent(ctx) + case event.FieldContent: + return m.OldContent(ctx) + } + return nil, fmt.Errorf("unknown Event field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *EventMutation) SetField(name string, value ent.Value) error { + switch name { + case event.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case event.FieldUserAgent: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUserAgent(v) + return nil + case event.FieldContent: + v, ok := value.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetContent(v) + return nil + } + return fmt.Errorf("unknown Event field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *EventMutation) AddedFields() []string { + return nil +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *EventMutation) AddedField(name string) (ent.Value, bool) { + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *EventMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown Event numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *EventMutation) ClearedFields() []string { + return nil +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *EventMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *EventMutation) ClearField(name string) error { + return fmt.Errorf("unknown Event nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *EventMutation) ResetField(name string) error { + switch name { + case event.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case event.FieldUserAgent: + m.ResetUserAgent() + return nil + case event.FieldContent: + m.ResetContent() + return nil + } + return fmt.Errorf("unknown Event field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *EventMutation) AddedEdges() []string { + edges := make([]string, 0, 2) + if m.user != nil { + edges = append(edges, event.EdgeUser) + } + if m.research != nil { + edges = append(edges, event.EdgeResearch) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *EventMutation) AddedIDs(name string) []ent.Value { + switch name { + case event.EdgeUser: + if id := m.user; id != nil { + return []ent.Value{*id} + } + case event.EdgeResearch: + if id := m.research; id != nil { + return []ent.Value{*id} + } + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *EventMutation) RemovedEdges() []string { + edges := make([]string, 0, 2) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *EventMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *EventMutation) ClearedEdges() []string { + edges := make([]string, 0, 2) + if m.cleareduser { + edges = append(edges, event.EdgeUser) + } + if m.clearedresearch { + edges = append(edges, event.EdgeResearch) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *EventMutation) EdgeCleared(name string) bool { + switch name { + case event.EdgeUser: + return m.cleareduser + case event.EdgeResearch: + return m.clearedresearch + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *EventMutation) ClearEdge(name string) error { + switch name { + case event.EdgeUser: + m.ClearUser() + return nil + case event.EdgeResearch: + m.ClearResearch() + return nil + } + return fmt.Errorf("unknown Event unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *EventMutation) ResetEdge(name string) error { + switch name { + case event.EdgeUser: + m.ResetUser() + return nil + case event.EdgeResearch: + m.ResetResearch() + return nil + } + return fmt.Errorf("unknown Event edge %s", name) +} + +// ResearchMutation represents an operation that mutates the Research nodes in the graph. +type ResearchMutation struct { + config + op Op + typ string + id *string + name *string + schema *map[string]interface{} + clearedFields map[string]struct{} + events map[string]struct{} + removedevents map[string]struct{} + clearedevents bool + done bool + oldValue func(context.Context) (*Research, error) + predicates []predicate.Research +} + +var _ ent.Mutation = (*ResearchMutation)(nil) + +// researchOption allows management of the mutation configuration using functional options. +type researchOption func(*ResearchMutation) + +// newResearchMutation creates new mutation for the Research entity. +func newResearchMutation(c config, op Op, opts ...researchOption) *ResearchMutation { + m := &ResearchMutation{ + config: c, + op: op, + typ: TypeResearch, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withResearchID sets the ID field of the mutation. +func withResearchID(id string) researchOption { + return func(m *ResearchMutation) { + var ( + err error + once sync.Once + value *Research + ) + m.oldValue = func(ctx context.Context) (*Research, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().Research.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withResearch sets the old Research of the mutation. +func withResearch(node *Research) researchOption { + return func(m *ResearchMutation) { + m.oldValue = func(context.Context) (*Research, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m ResearchMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m ResearchMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// SetID sets the value of the id field. Note that this +// operation is only accepted on creation of Research entities. +func (m *ResearchMutation) SetID(id string) { + m.id = &id +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *ResearchMutation) ID() (id string, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *ResearchMutation) IDs(ctx context.Context) ([]string, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []string{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().Research.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetName sets the "name" field. +func (m *ResearchMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *ResearchMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the Research entity. +// If the Research object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ResearchMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *ResearchMutation) ResetName() { + m.name = nil +} + +// SetSchema sets the "schema" field. +func (m *ResearchMutation) SetSchema(value map[string]interface{}) { + m.schema = &value +} + +// Schema returns the value of the "schema" field in the mutation. +func (m *ResearchMutation) Schema() (r map[string]interface{}, exists bool) { + v := m.schema + if v == nil { + return + } + return *v, true +} + +// OldSchema returns the old "schema" field's value of the Research entity. +// If the Research object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ResearchMutation) OldSchema(ctx context.Context) (v map[string]interface{}, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSchema is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSchema requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSchema: %w", err) + } + return oldValue.Schema, nil +} + +// ResetSchema resets all changes to the "schema" field. +func (m *ResearchMutation) ResetSchema() { + m.schema = nil +} + +// AddEventIDs adds the "events" edge to the Event entity by ids. +func (m *ResearchMutation) AddEventIDs(ids ...string) { + if m.events == nil { + m.events = make(map[string]struct{}) + } + for i := range ids { + m.events[ids[i]] = struct{}{} + } +} + +// ClearEvents clears the "events" edge to the Event entity. +func (m *ResearchMutation) ClearEvents() { + m.clearedevents = true +} + +// EventsCleared reports if the "events" edge to the Event entity was cleared. +func (m *ResearchMutation) EventsCleared() bool { + return m.clearedevents +} + +// RemoveEventIDs removes the "events" edge to the Event entity by IDs. +func (m *ResearchMutation) RemoveEventIDs(ids ...string) { + if m.removedevents == nil { + m.removedevents = make(map[string]struct{}) + } + for i := range ids { + delete(m.events, ids[i]) + m.removedevents[ids[i]] = struct{}{} + } +} + +// RemovedEvents returns the removed IDs of the "events" edge to the Event entity. +func (m *ResearchMutation) RemovedEventsIDs() (ids []string) { + for id := range m.removedevents { + ids = append(ids, id) + } + return +} + +// EventsIDs returns the "events" edge IDs in the mutation. +func (m *ResearchMutation) EventsIDs() (ids []string) { + for id := range m.events { + ids = append(ids, id) + } + return +} + +// ResetEvents resets all changes to the "events" edge. +func (m *ResearchMutation) ResetEvents() { + m.events = nil + m.clearedevents = false + m.removedevents = nil +} + +// Where appends a list predicates to the ResearchMutation builder. +func (m *ResearchMutation) Where(ps ...predicate.Research) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the ResearchMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *ResearchMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.Research, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *ResearchMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *ResearchMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (Research). +func (m *ResearchMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *ResearchMutation) Fields() []string { + fields := make([]string, 0, 2) + if m.name != nil { + fields = append(fields, research.FieldName) + } + if m.schema != nil { + fields = append(fields, research.FieldSchema) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *ResearchMutation) Field(name string) (ent.Value, bool) { + switch name { + case research.FieldName: + return m.Name() + case research.FieldSchema: + return m.Schema() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *ResearchMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case research.FieldName: + return m.OldName(ctx) + case research.FieldSchema: + return m.OldSchema(ctx) + } + return nil, fmt.Errorf("unknown Research field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ResearchMutation) SetField(name string, value ent.Value) error { + switch name { + case research.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case research.FieldSchema: + v, ok := value.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSchema(v) + return nil + } + return fmt.Errorf("unknown Research field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *ResearchMutation) AddedFields() []string { + return nil +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *ResearchMutation) AddedField(name string) (ent.Value, bool) { + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ResearchMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown Research numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *ResearchMutation) ClearedFields() []string { + return nil +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *ResearchMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *ResearchMutation) ClearField(name string) error { + return fmt.Errorf("unknown Research nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *ResearchMutation) ResetField(name string) error { + switch name { + case research.FieldName: + m.ResetName() + return nil + case research.FieldSchema: + m.ResetSchema() + return nil + } + return fmt.Errorf("unknown Research field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *ResearchMutation) AddedEdges() []string { + edges := make([]string, 0, 1) + if m.events != nil { + edges = append(edges, research.EdgeEvents) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *ResearchMutation) AddedIDs(name string) []ent.Value { + switch name { + case research.EdgeEvents: + ids := make([]ent.Value, 0, len(m.events)) + for id := range m.events { + ids = append(ids, id) + } + return ids + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *ResearchMutation) RemovedEdges() []string { + edges := make([]string, 0, 1) + if m.removedevents != nil { + edges = append(edges, research.EdgeEvents) + } + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *ResearchMutation) RemovedIDs(name string) []ent.Value { + switch name { + case research.EdgeEvents: + ids := make([]ent.Value, 0, len(m.removedevents)) + for id := range m.removedevents { + ids = append(ids, id) + } + return ids + } + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *ResearchMutation) ClearedEdges() []string { + edges := make([]string, 0, 1) + if m.clearedevents { + edges = append(edges, research.EdgeEvents) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *ResearchMutation) EdgeCleared(name string) bool { + switch name { + case research.EdgeEvents: + return m.clearedevents + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *ResearchMutation) ClearEdge(name string) error { + switch name { + } + return fmt.Errorf("unknown Research unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *ResearchMutation) ResetEdge(name string) error { + switch name { + case research.EdgeEvents: + m.ResetEvents() + return nil + } + return fmt.Errorf("unknown Research edge %s", name) +} + +// UserMutation represents an operation that mutates the User nodes in the graph. +type UserMutation struct { + config + op Op + typ string + id *string + name *string + email *string + credential *string + attributes *map[string]interface{} + clearedFields map[string]struct{} + events map[string]struct{} + removedevents map[string]struct{} + clearedevents bool + done bool + oldValue func(context.Context) (*User, error) + predicates []predicate.User +} + +var _ ent.Mutation = (*UserMutation)(nil) + +// userOption allows management of the mutation configuration using functional options. +type userOption func(*UserMutation) + +// newUserMutation creates new mutation for the User entity. +func newUserMutation(c config, op Op, opts ...userOption) *UserMutation { + m := &UserMutation{ + config: c, + op: op, + typ: TypeUser, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withUserID sets the ID field of the mutation. +func withUserID(id string) userOption { + return func(m *UserMutation) { + var ( + err error + once sync.Once + value *User + ) + m.oldValue = func(ctx context.Context) (*User, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().User.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withUser sets the old User of the mutation. +func withUser(node *User) userOption { + return func(m *UserMutation) { + m.oldValue = func(context.Context) (*User, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m UserMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m UserMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// SetID sets the value of the id field. Note that this +// operation is only accepted on creation of User entities. +func (m *UserMutation) SetID(id string) { + m.id = &id +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *UserMutation) ID() (id string, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *UserMutation) IDs(ctx context.Context) ([]string, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []string{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().User.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetName sets the "name" field. +func (m *UserMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *UserMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the User entity. +// If the User object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *UserMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *UserMutation) ResetName() { + m.name = nil +} + +// SetEmail sets the "email" field. +func (m *UserMutation) SetEmail(s string) { + m.email = &s +} + +// Email returns the value of the "email" field in the mutation. +func (m *UserMutation) Email() (r string, exists bool) { + v := m.email + if v == nil { + return + } + return *v, true +} + +// OldEmail returns the old "email" field's value of the User entity. +// If the User object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *UserMutation) OldEmail(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldEmail is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldEmail requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldEmail: %w", err) + } + return oldValue.Email, nil +} + +// ResetEmail resets all changes to the "email" field. +func (m *UserMutation) ResetEmail() { + m.email = nil +} + +// SetCredential sets the "credential" field. +func (m *UserMutation) SetCredential(s string) { + m.credential = &s +} + +// Credential returns the value of the "credential" field in the mutation. +func (m *UserMutation) Credential() (r string, exists bool) { + v := m.credential + if v == nil { + return + } + return *v, true +} + +// OldCredential returns the old "credential" field's value of the User entity. +// If the User object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *UserMutation) OldCredential(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCredential is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCredential requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCredential: %w", err) + } + return oldValue.Credential, nil +} + +// ResetCredential resets all changes to the "credential" field. +func (m *UserMutation) ResetCredential() { + m.credential = nil +} + +// SetAttributes sets the "attributes" field. +func (m *UserMutation) SetAttributes(value map[string]interface{}) { + m.attributes = &value +} + +// Attributes returns the value of the "attributes" field in the mutation. +func (m *UserMutation) Attributes() (r map[string]interface{}, exists bool) { + v := m.attributes + if v == nil { + return + } + return *v, true +} + +// OldAttributes returns the old "attributes" field's value of the User entity. +// If the User object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *UserMutation) OldAttributes(ctx context.Context) (v map[string]interface{}, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldAttributes is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldAttributes requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldAttributes: %w", err) + } + return oldValue.Attributes, nil +} + +// ClearAttributes clears the value of the "attributes" field. +func (m *UserMutation) ClearAttributes() { + m.attributes = nil + m.clearedFields[user.FieldAttributes] = struct{}{} +} + +// AttributesCleared returns if the "attributes" field was cleared in this mutation. +func (m *UserMutation) AttributesCleared() bool { + _, ok := m.clearedFields[user.FieldAttributes] + return ok +} + +// ResetAttributes resets all changes to the "attributes" field. +func (m *UserMutation) ResetAttributes() { + m.attributes = nil + delete(m.clearedFields, user.FieldAttributes) +} + +// AddEventIDs adds the "events" edge to the Event entity by ids. +func (m *UserMutation) AddEventIDs(ids ...string) { + if m.events == nil { + m.events = make(map[string]struct{}) + } + for i := range ids { + m.events[ids[i]] = struct{}{} + } +} + +// ClearEvents clears the "events" edge to the Event entity. +func (m *UserMutation) ClearEvents() { + m.clearedevents = true +} + +// EventsCleared reports if the "events" edge to the Event entity was cleared. +func (m *UserMutation) EventsCleared() bool { + return m.clearedevents +} + +// RemoveEventIDs removes the "events" edge to the Event entity by IDs. +func (m *UserMutation) RemoveEventIDs(ids ...string) { + if m.removedevents == nil { + m.removedevents = make(map[string]struct{}) + } + for i := range ids { + delete(m.events, ids[i]) + m.removedevents[ids[i]] = struct{}{} + } +} + +// RemovedEvents returns the removed IDs of the "events" edge to the Event entity. +func (m *UserMutation) RemovedEventsIDs() (ids []string) { + for id := range m.removedevents { + ids = append(ids, id) + } + return +} + +// EventsIDs returns the "events" edge IDs in the mutation. +func (m *UserMutation) EventsIDs() (ids []string) { + for id := range m.events { + ids = append(ids, id) + } + return +} + +// ResetEvents resets all changes to the "events" edge. +func (m *UserMutation) ResetEvents() { + m.events = nil + m.clearedevents = false + m.removedevents = nil +} + +// Where appends a list predicates to the UserMutation builder. +func (m *UserMutation) Where(ps ...predicate.User) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the UserMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *UserMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.User, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *UserMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *UserMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (User). +func (m *UserMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *UserMutation) Fields() []string { + fields := make([]string, 0, 4) + if m.name != nil { + fields = append(fields, user.FieldName) + } + if m.email != nil { + fields = append(fields, user.FieldEmail) + } + if m.credential != nil { + fields = append(fields, user.FieldCredential) + } + if m.attributes != nil { + fields = append(fields, user.FieldAttributes) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *UserMutation) Field(name string) (ent.Value, bool) { + switch name { + case user.FieldName: + return m.Name() + case user.FieldEmail: + return m.Email() + case user.FieldCredential: + return m.Credential() + case user.FieldAttributes: + return m.Attributes() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case user.FieldName: + return m.OldName(ctx) + case user.FieldEmail: + return m.OldEmail(ctx) + case user.FieldCredential: + return m.OldCredential(ctx) + case user.FieldAttributes: + return m.OldAttributes(ctx) + } + return nil, fmt.Errorf("unknown User field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *UserMutation) SetField(name string, value ent.Value) error { + switch name { + case user.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case user.FieldEmail: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetEmail(v) + return nil + case user.FieldCredential: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCredential(v) + return nil + case user.FieldAttributes: + v, ok := value.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetAttributes(v) + return nil + } + return fmt.Errorf("unknown User field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *UserMutation) AddedFields() []string { + return nil +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *UserMutation) AddedField(name string) (ent.Value, bool) { + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *UserMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown User numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *UserMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(user.FieldAttributes) { + fields = append(fields, user.FieldAttributes) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *UserMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *UserMutation) ClearField(name string) error { + switch name { + case user.FieldAttributes: + m.ClearAttributes() + return nil + } + return fmt.Errorf("unknown User nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *UserMutation) ResetField(name string) error { + switch name { + case user.FieldName: + m.ResetName() + return nil + case user.FieldEmail: + m.ResetEmail() + return nil + case user.FieldCredential: + m.ResetCredential() + return nil + case user.FieldAttributes: + m.ResetAttributes() + return nil + } + return fmt.Errorf("unknown User field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *UserMutation) AddedEdges() []string { + edges := make([]string, 0, 1) + if m.events != nil { + edges = append(edges, user.EdgeEvents) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *UserMutation) AddedIDs(name string) []ent.Value { + switch name { + case user.EdgeEvents: + ids := make([]ent.Value, 0, len(m.events)) + for id := range m.events { + ids = append(ids, id) + } + return ids + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *UserMutation) RemovedEdges() []string { + edges := make([]string, 0, 1) + if m.removedevents != nil { + edges = append(edges, user.EdgeEvents) + } + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *UserMutation) RemovedIDs(name string) []ent.Value { + switch name { + case user.EdgeEvents: + ids := make([]ent.Value, 0, len(m.removedevents)) + for id := range m.removedevents { + ids = append(ids, id) + } + return ids + } + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *UserMutation) ClearedEdges() []string { + edges := make([]string, 0, 1) + if m.clearedevents { + edges = append(edges, user.EdgeEvents) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *UserMutation) EdgeCleared(name string) bool { + switch name { + case user.EdgeEvents: + return m.clearedevents + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *UserMutation) ClearEdge(name string) error { + switch name { + } + return fmt.Errorf("unknown User unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *UserMutation) ResetEdge(name string) error { + switch name { + case user.EdgeEvents: + m.ResetEvents() + return nil + } + return fmt.Errorf("unknown User edge %s", name) +} diff --git a/internal/ent/predicate/predicate.go b/internal/ent/predicate/predicate.go new file mode 100644 index 0000000..b2380e5 --- /dev/null +++ b/internal/ent/predicate/predicate.go @@ -0,0 +1,16 @@ +// Code generated by ent, DO NOT EDIT. + +package predicate + +import ( + "entgo.io/ent/dialect/sql" +) + +// Event is the predicate function for event builders. +type Event func(*sql.Selector) + +// Research is the predicate function for research builders. +type Research func(*sql.Selector) + +// User is the predicate function for user builders. +type User func(*sql.Selector) diff --git a/internal/ent/research.go b/internal/ent/research.go new file mode 100644 index 0000000..8401c68 --- /dev/null +++ b/internal/ent/research.go @@ -0,0 +1,171 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "encoding/json" + "fmt" + "strings" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "exusiai.dev/roguestats-backend/internal/ent/research" +) + +// Research is the model entity for the Research schema. +type Research struct { + config `json:"-"` + // ID of the ent. + ID string `json:"id,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` + // Schema holds the value of the "schema" field. + Schema map[string]interface{} `json:"schema,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the ResearchQuery when eager-loading is set. + Edges ResearchEdges `json:"edges"` + selectValues sql.SelectValues +} + +// ResearchEdges holds the relations/edges for other nodes in the graph. +type ResearchEdges struct { + // Events holds the value of the events edge. + Events []*Event `json:"events,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [1]bool + // totalCount holds the count of the edges above. + totalCount [1]map[string]int + + namedEvents map[string][]*Event +} + +// EventsOrErr returns the Events value or an error if the edge +// was not loaded in eager-loading. +func (e ResearchEdges) EventsOrErr() ([]*Event, error) { + if e.loadedTypes[0] { + return e.Events, nil + } + return nil, &NotLoadedError{edge: "events"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*Research) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case research.FieldSchema: + values[i] = new([]byte) + case research.FieldID, research.FieldName: + values[i] = new(sql.NullString) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the Research fields. +func (r *Research) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case research.FieldID: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field id", values[i]) + } else if value.Valid { + r.ID = value.String + } + case research.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + r.Name = value.String + } + case research.FieldSchema: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field schema", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &r.Schema); err != nil { + return fmt.Errorf("unmarshal field schema: %w", err) + } + } + default: + r.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the Research. +// This includes values selected through modifiers, order, etc. +func (r *Research) Value(name string) (ent.Value, error) { + return r.selectValues.Get(name) +} + +// QueryEvents queries the "events" edge of the Research entity. +func (r *Research) QueryEvents() *EventQuery { + return NewResearchClient(r.config).QueryEvents(r) +} + +// Update returns a builder for updating this Research. +// Note that you need to call Research.Unwrap() before calling this method if this Research +// was returned from a transaction, and the transaction was committed or rolled back. +func (r *Research) Update() *ResearchUpdateOne { + return NewResearchClient(r.config).UpdateOne(r) +} + +// Unwrap unwraps the Research entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (r *Research) Unwrap() *Research { + _tx, ok := r.config.driver.(*txDriver) + if !ok { + panic("ent: Research is not a transactional entity") + } + r.config.driver = _tx.drv + return r +} + +// String implements the fmt.Stringer. +func (r *Research) String() string { + var builder strings.Builder + builder.WriteString("Research(") + builder.WriteString(fmt.Sprintf("id=%v, ", r.ID)) + builder.WriteString("name=") + builder.WriteString(r.Name) + builder.WriteString(", ") + builder.WriteString("schema=") + builder.WriteString(fmt.Sprintf("%v", r.Schema)) + builder.WriteByte(')') + return builder.String() +} + +// NamedEvents returns the Events named value or an error if the edge was not +// loaded in eager-loading with this name. +func (r *Research) NamedEvents(name string) ([]*Event, error) { + if r.Edges.namedEvents == nil { + return nil, &NotLoadedError{edge: name} + } + nodes, ok := r.Edges.namedEvents[name] + if !ok { + return nil, &NotLoadedError{edge: name} + } + return nodes, nil +} + +func (r *Research) appendNamedEvents(name string, edges ...*Event) { + if r.Edges.namedEvents == nil { + r.Edges.namedEvents = make(map[string][]*Event) + } + if len(edges) == 0 { + r.Edges.namedEvents[name] = []*Event{} + } else { + r.Edges.namedEvents[name] = append(r.Edges.namedEvents[name], edges...) + } +} + +// Researches is a parsable slice of Research. +type Researches []*Research diff --git a/internal/ent/research/research.go b/internal/ent/research/research.go new file mode 100644 index 0000000..ff345ed --- /dev/null +++ b/internal/ent/research/research.go @@ -0,0 +1,90 @@ +// Code generated by ent, DO NOT EDIT. + +package research + +import ( + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +const ( + // Label holds the string label denoting the research type in the database. + Label = "research" + // FieldID holds the string denoting the id field in the database. + FieldID = "research_id" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" + // FieldSchema holds the string denoting the schema field in the database. + FieldSchema = "schema" + // EdgeEvents holds the string denoting the events edge name in mutations. + EdgeEvents = "events" + // EventFieldID holds the string denoting the ID field of the Event. + EventFieldID = "event_id" + // Table holds the table name of the research in the database. + Table = "researches" + // EventsTable is the table that holds the events relation/edge. + EventsTable = "events" + // EventsInverseTable is the table name for the Event entity. + // It exists in this package in order to avoid circular dependency with the "event" package. + EventsInverseTable = "events" + // EventsColumn is the table column denoting the events relation/edge. + EventsColumn = "research_events" +) + +// Columns holds all SQL columns for research fields. +var Columns = []string{ + FieldID, + FieldName, + FieldSchema, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // NameValidator is a validator for the "name" field. It is called by the builders before save. + NameValidator func(string) error + // DefaultID holds the default value on creation for the "id" field. + DefaultID func() string +) + +// OrderOption defines the ordering options for the Research queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByName orders the results by the name field. +func ByName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldName, opts...).ToFunc() +} + +// ByEventsCount orders the results by events count. +func ByEventsCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newEventsStep(), opts...) + } +} + +// ByEvents orders the results by events terms. +func ByEvents(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newEventsStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} +func newEventsStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(EventsInverseTable, EventFieldID), + sqlgraph.Edge(sqlgraph.O2M, false, EventsTable, EventsColumn), + ) +} diff --git a/internal/ent/research/where.go b/internal/ent/research/where.go new file mode 100644 index 0000000..414cda7 --- /dev/null +++ b/internal/ent/research/where.go @@ -0,0 +1,189 @@ +// Code generated by ent, DO NOT EDIT. + +package research + +import ( + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "exusiai.dev/roguestats-backend/internal/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id string) predicate.Research { + return predicate.Research(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id string) predicate.Research { + return predicate.Research(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id string) predicate.Research { + return predicate.Research(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...string) predicate.Research { + return predicate.Research(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...string) predicate.Research { + return predicate.Research(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id string) predicate.Research { + return predicate.Research(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id string) predicate.Research { + return predicate.Research(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id string) predicate.Research { + return predicate.Research(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id string) predicate.Research { + return predicate.Research(sql.FieldLTE(FieldID, id)) +} + +// IDEqualFold applies the EqualFold predicate on the ID field. +func IDEqualFold(id string) predicate.Research { + return predicate.Research(sql.FieldEqualFold(FieldID, id)) +} + +// IDContainsFold applies the ContainsFold predicate on the ID field. +func IDContainsFold(id string) predicate.Research { + return predicate.Research(sql.FieldContainsFold(FieldID, id)) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.Research { + return predicate.Research(sql.FieldEQ(FieldName, v)) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.Research { + return predicate.Research(sql.FieldEQ(FieldName, v)) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.Research { + return predicate.Research(sql.FieldNEQ(FieldName, v)) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.Research { + return predicate.Research(sql.FieldIn(FieldName, vs...)) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.Research { + return predicate.Research(sql.FieldNotIn(FieldName, vs...)) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.Research { + return predicate.Research(sql.FieldGT(FieldName, v)) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.Research { + return predicate.Research(sql.FieldGTE(FieldName, v)) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.Research { + return predicate.Research(sql.FieldLT(FieldName, v)) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.Research { + return predicate.Research(sql.FieldLTE(FieldName, v)) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.Research { + return predicate.Research(sql.FieldContains(FieldName, v)) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.Research { + return predicate.Research(sql.FieldHasPrefix(FieldName, v)) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.Research { + return predicate.Research(sql.FieldHasSuffix(FieldName, v)) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.Research { + return predicate.Research(sql.FieldEqualFold(FieldName, v)) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.Research { + return predicate.Research(sql.FieldContainsFold(FieldName, v)) +} + +// HasEvents applies the HasEdge predicate on the "events" edge. +func HasEvents() predicate.Research { + return predicate.Research(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, EventsTable, EventsColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasEventsWith applies the HasEdge predicate on the "events" edge with a given conditions (other predicates). +func HasEventsWith(preds ...predicate.Event) predicate.Research { + return predicate.Research(func(s *sql.Selector) { + step := newEventsStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.Research) predicate.Research { + return predicate.Research(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.Research) predicate.Research { + return predicate.Research(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.Research) predicate.Research { + return predicate.Research(func(s *sql.Selector) { + p(s.Not()) + }) +} diff --git a/internal/ent/research_create.go b/internal/ent/research_create.go new file mode 100644 index 0000000..b854009 --- /dev/null +++ b/internal/ent/research_create.go @@ -0,0 +1,261 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/research" +) + +// ResearchCreate is the builder for creating a Research entity. +type ResearchCreate struct { + config + mutation *ResearchMutation + hooks []Hook +} + +// SetName sets the "name" field. +func (rc *ResearchCreate) SetName(s string) *ResearchCreate { + rc.mutation.SetName(s) + return rc +} + +// SetSchema sets the "schema" field. +func (rc *ResearchCreate) SetSchema(m map[string]interface{}) *ResearchCreate { + rc.mutation.SetSchema(m) + return rc +} + +// SetID sets the "id" field. +func (rc *ResearchCreate) SetID(s string) *ResearchCreate { + rc.mutation.SetID(s) + return rc +} + +// SetNillableID sets the "id" field if the given value is not nil. +func (rc *ResearchCreate) SetNillableID(s *string) *ResearchCreate { + if s != nil { + rc.SetID(*s) + } + return rc +} + +// AddEventIDs adds the "events" edge to the Event entity by IDs. +func (rc *ResearchCreate) AddEventIDs(ids ...string) *ResearchCreate { + rc.mutation.AddEventIDs(ids...) + return rc +} + +// AddEvents adds the "events" edges to the Event entity. +func (rc *ResearchCreate) AddEvents(e ...*Event) *ResearchCreate { + ids := make([]string, len(e)) + for i := range e { + ids[i] = e[i].ID + } + return rc.AddEventIDs(ids...) +} + +// Mutation returns the ResearchMutation object of the builder. +func (rc *ResearchCreate) Mutation() *ResearchMutation { + return rc.mutation +} + +// Save creates the Research in the database. +func (rc *ResearchCreate) Save(ctx context.Context) (*Research, error) { + rc.defaults() + return withHooks(ctx, rc.sqlSave, rc.mutation, rc.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (rc *ResearchCreate) SaveX(ctx context.Context) *Research { + v, err := rc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (rc *ResearchCreate) Exec(ctx context.Context) error { + _, err := rc.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (rc *ResearchCreate) ExecX(ctx context.Context) { + if err := rc.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (rc *ResearchCreate) defaults() { + if _, ok := rc.mutation.ID(); !ok { + v := research.DefaultID() + rc.mutation.SetID(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (rc *ResearchCreate) check() error { + if _, ok := rc.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "Research.name"`)} + } + if v, ok := rc.mutation.Name(); ok { + if err := research.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Research.name": %w`, err)} + } + } + if _, ok := rc.mutation.Schema(); !ok { + return &ValidationError{Name: "schema", err: errors.New(`ent: missing required field "Research.schema"`)} + } + if len(rc.mutation.EventsIDs()) == 0 { + return &ValidationError{Name: "events", err: errors.New(`ent: missing required edge "Research.events"`)} + } + return nil +} + +func (rc *ResearchCreate) sqlSave(ctx context.Context) (*Research, error) { + if err := rc.check(); err != nil { + return nil, err + } + _node, _spec := rc.createSpec() + if err := sqlgraph.CreateNode(ctx, rc.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + if _spec.ID.Value != nil { + if id, ok := _spec.ID.Value.(string); ok { + _node.ID = id + } else { + return nil, fmt.Errorf("unexpected Research.ID type: %T", _spec.ID.Value) + } + } + rc.mutation.id = &_node.ID + rc.mutation.done = true + return _node, nil +} + +func (rc *ResearchCreate) createSpec() (*Research, *sqlgraph.CreateSpec) { + var ( + _node = &Research{config: rc.config} + _spec = sqlgraph.NewCreateSpec(research.Table, sqlgraph.NewFieldSpec(research.FieldID, field.TypeString)) + ) + if id, ok := rc.mutation.ID(); ok { + _node.ID = id + _spec.ID.Value = id + } + if value, ok := rc.mutation.Name(); ok { + _spec.SetField(research.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := rc.mutation.Schema(); ok { + _spec.SetField(research.FieldSchema, field.TypeJSON, value) + _node.Schema = value + } + if nodes := rc.mutation.EventsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: research.EventsTable, + Columns: []string{research.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// ResearchCreateBulk is the builder for creating many Research entities in bulk. +type ResearchCreateBulk struct { + config + builders []*ResearchCreate +} + +// Save creates the Research entities in the database. +func (rcb *ResearchCreateBulk) Save(ctx context.Context) ([]*Research, error) { + specs := make([]*sqlgraph.CreateSpec, len(rcb.builders)) + nodes := make([]*Research, len(rcb.builders)) + mutators := make([]Mutator, len(rcb.builders)) + for i := range rcb.builders { + func(i int, root context.Context) { + builder := rcb.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*ResearchMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, rcb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, rcb.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, rcb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (rcb *ResearchCreateBulk) SaveX(ctx context.Context) []*Research { + v, err := rcb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (rcb *ResearchCreateBulk) Exec(ctx context.Context) error { + _, err := rcb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (rcb *ResearchCreateBulk) ExecX(ctx context.Context) { + if err := rcb.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/internal/ent/research_delete.go b/internal/ent/research_delete.go new file mode 100644 index 0000000..33d6d81 --- /dev/null +++ b/internal/ent/research_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/predicate" + "exusiai.dev/roguestats-backend/internal/ent/research" +) + +// ResearchDelete is the builder for deleting a Research entity. +type ResearchDelete struct { + config + hooks []Hook + mutation *ResearchMutation +} + +// Where appends a list predicates to the ResearchDelete builder. +func (rd *ResearchDelete) Where(ps ...predicate.Research) *ResearchDelete { + rd.mutation.Where(ps...) + return rd +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (rd *ResearchDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, rd.sqlExec, rd.mutation, rd.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (rd *ResearchDelete) ExecX(ctx context.Context) int { + n, err := rd.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (rd *ResearchDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(research.Table, sqlgraph.NewFieldSpec(research.FieldID, field.TypeString)) + if ps := rd.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, rd.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + rd.mutation.done = true + return affected, err +} + +// ResearchDeleteOne is the builder for deleting a single Research entity. +type ResearchDeleteOne struct { + rd *ResearchDelete +} + +// Where appends a list predicates to the ResearchDelete builder. +func (rdo *ResearchDeleteOne) Where(ps ...predicate.Research) *ResearchDeleteOne { + rdo.rd.mutation.Where(ps...) + return rdo +} + +// Exec executes the deletion query. +func (rdo *ResearchDeleteOne) Exec(ctx context.Context) error { + n, err := rdo.rd.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{research.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (rdo *ResearchDeleteOne) ExecX(ctx context.Context) { + if err := rdo.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/internal/ent/research_query.go b/internal/ent/research_query.go new file mode 100644 index 0000000..49b1584 --- /dev/null +++ b/internal/ent/research_query.go @@ -0,0 +1,641 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "database/sql/driver" + "fmt" + "math" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/predicate" + "exusiai.dev/roguestats-backend/internal/ent/research" +) + +// ResearchQuery is the builder for querying Research entities. +type ResearchQuery struct { + config + ctx *QueryContext + order []research.OrderOption + inters []Interceptor + predicates []predicate.Research + withEvents *EventQuery + modifiers []func(*sql.Selector) + loadTotal []func(context.Context, []*Research) error + withNamedEvents map[string]*EventQuery + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the ResearchQuery builder. +func (rq *ResearchQuery) Where(ps ...predicate.Research) *ResearchQuery { + rq.predicates = append(rq.predicates, ps...) + return rq +} + +// Limit the number of records to be returned by this query. +func (rq *ResearchQuery) Limit(limit int) *ResearchQuery { + rq.ctx.Limit = &limit + return rq +} + +// Offset to start from. +func (rq *ResearchQuery) Offset(offset int) *ResearchQuery { + rq.ctx.Offset = &offset + return rq +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (rq *ResearchQuery) Unique(unique bool) *ResearchQuery { + rq.ctx.Unique = &unique + return rq +} + +// Order specifies how the records should be ordered. +func (rq *ResearchQuery) Order(o ...research.OrderOption) *ResearchQuery { + rq.order = append(rq.order, o...) + return rq +} + +// QueryEvents chains the current query on the "events" edge. +func (rq *ResearchQuery) QueryEvents() *EventQuery { + query := (&EventClient{config: rq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := rq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := rq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(research.Table, research.FieldID, selector), + sqlgraph.To(event.Table, event.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, research.EventsTable, research.EventsColumn), + ) + fromU = sqlgraph.SetNeighbors(rq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first Research entity from the query. +// Returns a *NotFoundError when no Research was found. +func (rq *ResearchQuery) First(ctx context.Context) (*Research, error) { + nodes, err := rq.Limit(1).All(setContextOp(ctx, rq.ctx, "First")) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{research.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (rq *ResearchQuery) FirstX(ctx context.Context) *Research { + node, err := rq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first Research ID from the query. +// Returns a *NotFoundError when no Research ID was found. +func (rq *ResearchQuery) FirstID(ctx context.Context) (id string, err error) { + var ids []string + if ids, err = rq.Limit(1).IDs(setContextOp(ctx, rq.ctx, "FirstID")); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{research.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (rq *ResearchQuery) FirstIDX(ctx context.Context) string { + id, err := rq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single Research entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one Research entity is found. +// Returns a *NotFoundError when no Research entities are found. +func (rq *ResearchQuery) Only(ctx context.Context) (*Research, error) { + nodes, err := rq.Limit(2).All(setContextOp(ctx, rq.ctx, "Only")) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{research.Label} + default: + return nil, &NotSingularError{research.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (rq *ResearchQuery) OnlyX(ctx context.Context) *Research { + node, err := rq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only Research ID in the query. +// Returns a *NotSingularError when more than one Research ID is found. +// Returns a *NotFoundError when no entities are found. +func (rq *ResearchQuery) OnlyID(ctx context.Context) (id string, err error) { + var ids []string + if ids, err = rq.Limit(2).IDs(setContextOp(ctx, rq.ctx, "OnlyID")); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{research.Label} + default: + err = &NotSingularError{research.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (rq *ResearchQuery) OnlyIDX(ctx context.Context) string { + id, err := rq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of Researches. +func (rq *ResearchQuery) All(ctx context.Context) ([]*Research, error) { + ctx = setContextOp(ctx, rq.ctx, "All") + if err := rq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*Research, *ResearchQuery]() + return withInterceptors[[]*Research](ctx, rq, qr, rq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (rq *ResearchQuery) AllX(ctx context.Context) []*Research { + nodes, err := rq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of Research IDs. +func (rq *ResearchQuery) IDs(ctx context.Context) (ids []string, err error) { + if rq.ctx.Unique == nil && rq.path != nil { + rq.Unique(true) + } + ctx = setContextOp(ctx, rq.ctx, "IDs") + if err = rq.Select(research.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (rq *ResearchQuery) IDsX(ctx context.Context) []string { + ids, err := rq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (rq *ResearchQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, rq.ctx, "Count") + if err := rq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, rq, querierCount[*ResearchQuery](), rq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (rq *ResearchQuery) CountX(ctx context.Context) int { + count, err := rq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (rq *ResearchQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, rq.ctx, "Exist") + switch _, err := rq.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (rq *ResearchQuery) ExistX(ctx context.Context) bool { + exist, err := rq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the ResearchQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (rq *ResearchQuery) Clone() *ResearchQuery { + if rq == nil { + return nil + } + return &ResearchQuery{ + config: rq.config, + ctx: rq.ctx.Clone(), + order: append([]research.OrderOption{}, rq.order...), + inters: append([]Interceptor{}, rq.inters...), + predicates: append([]predicate.Research{}, rq.predicates...), + withEvents: rq.withEvents.Clone(), + // clone intermediate query. + sql: rq.sql.Clone(), + path: rq.path, + } +} + +// WithEvents tells the query-builder to eager-load the nodes that are connected to +// the "events" edge. The optional arguments are used to configure the query builder of the edge. +func (rq *ResearchQuery) WithEvents(opts ...func(*EventQuery)) *ResearchQuery { + query := (&EventClient{config: rq.config}).Query() + for _, opt := range opts { + opt(query) + } + rq.withEvents = query + return rq +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Research.Query(). +// GroupBy(research.FieldName). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (rq *ResearchQuery) GroupBy(field string, fields ...string) *ResearchGroupBy { + rq.ctx.Fields = append([]string{field}, fields...) + grbuild := &ResearchGroupBy{build: rq} + grbuild.flds = &rq.ctx.Fields + grbuild.label = research.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// } +// +// client.Research.Query(). +// Select(research.FieldName). +// Scan(ctx, &v) +func (rq *ResearchQuery) Select(fields ...string) *ResearchSelect { + rq.ctx.Fields = append(rq.ctx.Fields, fields...) + sbuild := &ResearchSelect{ResearchQuery: rq} + sbuild.label = research.Label + sbuild.flds, sbuild.scan = &rq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a ResearchSelect configured with the given aggregations. +func (rq *ResearchQuery) Aggregate(fns ...AggregateFunc) *ResearchSelect { + return rq.Select().Aggregate(fns...) +} + +func (rq *ResearchQuery) prepareQuery(ctx context.Context) error { + for _, inter := range rq.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, rq); err != nil { + return err + } + } + } + for _, f := range rq.ctx.Fields { + if !research.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if rq.path != nil { + prev, err := rq.path(ctx) + if err != nil { + return err + } + rq.sql = prev + } + return nil +} + +func (rq *ResearchQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Research, error) { + var ( + nodes = []*Research{} + _spec = rq.querySpec() + loadedTypes = [1]bool{ + rq.withEvents != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*Research).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &Research{config: rq.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + if len(rq.modifiers) > 0 { + _spec.Modifiers = rq.modifiers + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, rq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := rq.withEvents; query != nil { + if err := rq.loadEvents(ctx, query, nodes, + func(n *Research) { n.Edges.Events = []*Event{} }, + func(n *Research, e *Event) { n.Edges.Events = append(n.Edges.Events, e) }); err != nil { + return nil, err + } + } + for name, query := range rq.withNamedEvents { + if err := rq.loadEvents(ctx, query, nodes, + func(n *Research) { n.appendNamedEvents(name) }, + func(n *Research, e *Event) { n.appendNamedEvents(name, e) }); err != nil { + return nil, err + } + } + for i := range rq.loadTotal { + if err := rq.loadTotal[i](ctx, nodes); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (rq *ResearchQuery) loadEvents(ctx context.Context, query *EventQuery, nodes []*Research, init func(*Research), assign func(*Research, *Event)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[string]*Research) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + query.withFKs = true + query.Where(predicate.Event(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(research.EventsColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.research_events + if fk == nil { + return fmt.Errorf(`foreign-key "research_events" is nil for node %v`, n.ID) + } + node, ok := nodeids[*fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "research_events" returned %v for node %v`, *fk, n.ID) + } + assign(node, n) + } + return nil +} + +func (rq *ResearchQuery) sqlCount(ctx context.Context) (int, error) { + _spec := rq.querySpec() + if len(rq.modifiers) > 0 { + _spec.Modifiers = rq.modifiers + } + _spec.Node.Columns = rq.ctx.Fields + if len(rq.ctx.Fields) > 0 { + _spec.Unique = rq.ctx.Unique != nil && *rq.ctx.Unique + } + return sqlgraph.CountNodes(ctx, rq.driver, _spec) +} + +func (rq *ResearchQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(research.Table, research.Columns, sqlgraph.NewFieldSpec(research.FieldID, field.TypeString)) + _spec.From = rq.sql + if unique := rq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if rq.path != nil { + _spec.Unique = true + } + if fields := rq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, research.FieldID) + for i := range fields { + if fields[i] != research.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := rq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := rq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := rq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := rq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (rq *ResearchQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(rq.driver.Dialect()) + t1 := builder.Table(research.Table) + columns := rq.ctx.Fields + if len(columns) == 0 { + columns = research.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if rq.sql != nil { + selector = rq.sql + selector.Select(selector.Columns(columns...)...) + } + if rq.ctx.Unique != nil && *rq.ctx.Unique { + selector.Distinct() + } + for _, p := range rq.predicates { + p(selector) + } + for _, p := range rq.order { + p(selector) + } + if offset := rq.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := rq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// WithNamedEvents tells the query-builder to eager-load the nodes that are connected to the "events" +// edge with the given name. The optional arguments are used to configure the query builder of the edge. +func (rq *ResearchQuery) WithNamedEvents(name string, opts ...func(*EventQuery)) *ResearchQuery { + query := (&EventClient{config: rq.config}).Query() + for _, opt := range opts { + opt(query) + } + if rq.withNamedEvents == nil { + rq.withNamedEvents = make(map[string]*EventQuery) + } + rq.withNamedEvents[name] = query + return rq +} + +// ResearchGroupBy is the group-by builder for Research entities. +type ResearchGroupBy struct { + selector + build *ResearchQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (rgb *ResearchGroupBy) Aggregate(fns ...AggregateFunc) *ResearchGroupBy { + rgb.fns = append(rgb.fns, fns...) + return rgb +} + +// Scan applies the selector query and scans the result into the given value. +func (rgb *ResearchGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, rgb.build.ctx, "GroupBy") + if err := rgb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ResearchQuery, *ResearchGroupBy](ctx, rgb.build, rgb, rgb.build.inters, v) +} + +func (rgb *ResearchGroupBy) sqlScan(ctx context.Context, root *ResearchQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(rgb.fns)) + for _, fn := range rgb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*rgb.flds)+len(rgb.fns)) + for _, f := range *rgb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*rgb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := rgb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// ResearchSelect is the builder for selecting fields of Research entities. +type ResearchSelect struct { + *ResearchQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (rs *ResearchSelect) Aggregate(fns ...AggregateFunc) *ResearchSelect { + rs.fns = append(rs.fns, fns...) + return rs +} + +// Scan applies the selector query and scans the result into the given value. +func (rs *ResearchSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, rs.ctx, "Select") + if err := rs.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ResearchQuery, *ResearchSelect](ctx, rs.ResearchQuery, rs, rs.inters, v) +} + +func (rs *ResearchSelect) sqlScan(ctx context.Context, root *ResearchQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(rs.fns)) + for _, fn := range rs.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*rs.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := rs.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/internal/ent/research_update.go b/internal/ent/research_update.go new file mode 100644 index 0000000..3a75c48 --- /dev/null +++ b/internal/ent/research_update.go @@ -0,0 +1,400 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/predicate" + "exusiai.dev/roguestats-backend/internal/ent/research" +) + +// ResearchUpdate is the builder for updating Research entities. +type ResearchUpdate struct { + config + hooks []Hook + mutation *ResearchMutation +} + +// Where appends a list predicates to the ResearchUpdate builder. +func (ru *ResearchUpdate) Where(ps ...predicate.Research) *ResearchUpdate { + ru.mutation.Where(ps...) + return ru +} + +// SetName sets the "name" field. +func (ru *ResearchUpdate) SetName(s string) *ResearchUpdate { + ru.mutation.SetName(s) + return ru +} + +// SetSchema sets the "schema" field. +func (ru *ResearchUpdate) SetSchema(m map[string]interface{}) *ResearchUpdate { + ru.mutation.SetSchema(m) + return ru +} + +// AddEventIDs adds the "events" edge to the Event entity by IDs. +func (ru *ResearchUpdate) AddEventIDs(ids ...string) *ResearchUpdate { + ru.mutation.AddEventIDs(ids...) + return ru +} + +// AddEvents adds the "events" edges to the Event entity. +func (ru *ResearchUpdate) AddEvents(e ...*Event) *ResearchUpdate { + ids := make([]string, len(e)) + for i := range e { + ids[i] = e[i].ID + } + return ru.AddEventIDs(ids...) +} + +// Mutation returns the ResearchMutation object of the builder. +func (ru *ResearchUpdate) Mutation() *ResearchMutation { + return ru.mutation +} + +// ClearEvents clears all "events" edges to the Event entity. +func (ru *ResearchUpdate) ClearEvents() *ResearchUpdate { + ru.mutation.ClearEvents() + return ru +} + +// RemoveEventIDs removes the "events" edge to Event entities by IDs. +func (ru *ResearchUpdate) RemoveEventIDs(ids ...string) *ResearchUpdate { + ru.mutation.RemoveEventIDs(ids...) + return ru +} + +// RemoveEvents removes "events" edges to Event entities. +func (ru *ResearchUpdate) RemoveEvents(e ...*Event) *ResearchUpdate { + ids := make([]string, len(e)) + for i := range e { + ids[i] = e[i].ID + } + return ru.RemoveEventIDs(ids...) +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (ru *ResearchUpdate) Save(ctx context.Context) (int, error) { + return withHooks(ctx, ru.sqlSave, ru.mutation, ru.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (ru *ResearchUpdate) SaveX(ctx context.Context) int { + affected, err := ru.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (ru *ResearchUpdate) Exec(ctx context.Context) error { + _, err := ru.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (ru *ResearchUpdate) ExecX(ctx context.Context) { + if err := ru.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (ru *ResearchUpdate) check() error { + if v, ok := ru.mutation.Name(); ok { + if err := research.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Research.name": %w`, err)} + } + } + return nil +} + +func (ru *ResearchUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := ru.check(); err != nil { + return n, err + } + _spec := sqlgraph.NewUpdateSpec(research.Table, research.Columns, sqlgraph.NewFieldSpec(research.FieldID, field.TypeString)) + if ps := ru.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := ru.mutation.Name(); ok { + _spec.SetField(research.FieldName, field.TypeString, value) + } + if value, ok := ru.mutation.Schema(); ok { + _spec.SetField(research.FieldSchema, field.TypeJSON, value) + } + if ru.mutation.EventsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: research.EventsTable, + Columns: []string{research.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := ru.mutation.RemovedEventsIDs(); len(nodes) > 0 && !ru.mutation.EventsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: research.EventsTable, + Columns: []string{research.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := ru.mutation.EventsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: research.EventsTable, + Columns: []string{research.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if n, err = sqlgraph.UpdateNodes(ctx, ru.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{research.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + ru.mutation.done = true + return n, nil +} + +// ResearchUpdateOne is the builder for updating a single Research entity. +type ResearchUpdateOne struct { + config + fields []string + hooks []Hook + mutation *ResearchMutation +} + +// SetName sets the "name" field. +func (ruo *ResearchUpdateOne) SetName(s string) *ResearchUpdateOne { + ruo.mutation.SetName(s) + return ruo +} + +// SetSchema sets the "schema" field. +func (ruo *ResearchUpdateOne) SetSchema(m map[string]interface{}) *ResearchUpdateOne { + ruo.mutation.SetSchema(m) + return ruo +} + +// AddEventIDs adds the "events" edge to the Event entity by IDs. +func (ruo *ResearchUpdateOne) AddEventIDs(ids ...string) *ResearchUpdateOne { + ruo.mutation.AddEventIDs(ids...) + return ruo +} + +// AddEvents adds the "events" edges to the Event entity. +func (ruo *ResearchUpdateOne) AddEvents(e ...*Event) *ResearchUpdateOne { + ids := make([]string, len(e)) + for i := range e { + ids[i] = e[i].ID + } + return ruo.AddEventIDs(ids...) +} + +// Mutation returns the ResearchMutation object of the builder. +func (ruo *ResearchUpdateOne) Mutation() *ResearchMutation { + return ruo.mutation +} + +// ClearEvents clears all "events" edges to the Event entity. +func (ruo *ResearchUpdateOne) ClearEvents() *ResearchUpdateOne { + ruo.mutation.ClearEvents() + return ruo +} + +// RemoveEventIDs removes the "events" edge to Event entities by IDs. +func (ruo *ResearchUpdateOne) RemoveEventIDs(ids ...string) *ResearchUpdateOne { + ruo.mutation.RemoveEventIDs(ids...) + return ruo +} + +// RemoveEvents removes "events" edges to Event entities. +func (ruo *ResearchUpdateOne) RemoveEvents(e ...*Event) *ResearchUpdateOne { + ids := make([]string, len(e)) + for i := range e { + ids[i] = e[i].ID + } + return ruo.RemoveEventIDs(ids...) +} + +// Where appends a list predicates to the ResearchUpdate builder. +func (ruo *ResearchUpdateOne) Where(ps ...predicate.Research) *ResearchUpdateOne { + ruo.mutation.Where(ps...) + return ruo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (ruo *ResearchUpdateOne) Select(field string, fields ...string) *ResearchUpdateOne { + ruo.fields = append([]string{field}, fields...) + return ruo +} + +// Save executes the query and returns the updated Research entity. +func (ruo *ResearchUpdateOne) Save(ctx context.Context) (*Research, error) { + return withHooks(ctx, ruo.sqlSave, ruo.mutation, ruo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (ruo *ResearchUpdateOne) SaveX(ctx context.Context) *Research { + node, err := ruo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (ruo *ResearchUpdateOne) Exec(ctx context.Context) error { + _, err := ruo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (ruo *ResearchUpdateOne) ExecX(ctx context.Context) { + if err := ruo.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (ruo *ResearchUpdateOne) check() error { + if v, ok := ruo.mutation.Name(); ok { + if err := research.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Research.name": %w`, err)} + } + } + return nil +} + +func (ruo *ResearchUpdateOne) sqlSave(ctx context.Context) (_node *Research, err error) { + if err := ruo.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(research.Table, research.Columns, sqlgraph.NewFieldSpec(research.FieldID, field.TypeString)) + id, ok := ruo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Research.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := ruo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, research.FieldID) + for _, f := range fields { + if !research.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != research.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := ruo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := ruo.mutation.Name(); ok { + _spec.SetField(research.FieldName, field.TypeString, value) + } + if value, ok := ruo.mutation.Schema(); ok { + _spec.SetField(research.FieldSchema, field.TypeJSON, value) + } + if ruo.mutation.EventsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: research.EventsTable, + Columns: []string{research.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := ruo.mutation.RemovedEventsIDs(); len(nodes) > 0 && !ruo.mutation.EventsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: research.EventsTable, + Columns: []string{research.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := ruo.mutation.EventsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: research.EventsTable, + Columns: []string{research.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &Research{config: ruo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, ruo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{research.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + ruo.mutation.done = true + return _node, nil +} diff --git a/internal/ent/runtime.go b/internal/ent/runtime.go new file mode 100644 index 0000000..e38f9b1 --- /dev/null +++ b/internal/ent/runtime.go @@ -0,0 +1,52 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "time" + + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/research" + "exusiai.dev/roguestats-backend/internal/ent/schema" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// The init function reads all schema descriptors with runtime code +// (default values, validators, hooks and policies) and stitches it +// to their package variables. +func init() { + eventFields := schema.Event{}.Fields() + _ = eventFields + // eventDescCreatedAt is the schema descriptor for created_at field. + eventDescCreatedAt := eventFields[1].Descriptor() + // event.DefaultCreatedAt holds the default value on creation for the created_at field. + event.DefaultCreatedAt = eventDescCreatedAt.Default.(func() time.Time) + // eventDescID is the schema descriptor for id field. + eventDescID := eventFields[0].Descriptor() + // event.DefaultID holds the default value on creation for the id field. + event.DefaultID = eventDescID.Default.(func() string) + researchFields := schema.Research{}.Fields() + _ = researchFields + // researchDescName is the schema descriptor for name field. + researchDescName := researchFields[1].Descriptor() + // research.NameValidator is a validator for the "name" field. It is called by the builders before save. + research.NameValidator = researchDescName.Validators[0].(func(string) error) + // researchDescID is the schema descriptor for id field. + researchDescID := researchFields[0].Descriptor() + // research.DefaultID holds the default value on creation for the id field. + research.DefaultID = researchDescID.Default.(func() string) + userFields := schema.User{}.Fields() + _ = userFields + // userDescName is the schema descriptor for name field. + userDescName := userFields[1].Descriptor() + // user.NameValidator is a validator for the "name" field. It is called by the builders before save. + user.NameValidator = userDescName.Validators[0].(func(string) error) + // userDescCredential is the schema descriptor for credential field. + userDescCredential := userFields[3].Descriptor() + // user.CredentialValidator is a validator for the "credential" field. It is called by the builders before save. + user.CredentialValidator = userDescCredential.Validators[0].(func(string) error) + // userDescID is the schema descriptor for id field. + userDescID := userFields[0].Descriptor() + // user.DefaultID holds the default value on creation for the id field. + user.DefaultID = userDescID.Default.(func() string) +} diff --git a/internal/ent/runtime/runtime.go b/internal/ent/runtime/runtime.go new file mode 100644 index 0000000..1d25d31 --- /dev/null +++ b/internal/ent/runtime/runtime.go @@ -0,0 +1,10 @@ +// Code generated by ent, DO NOT EDIT. + +package runtime + +// The schema-stitching logic is generated in exusiai.dev/roguestats-backend/internal/ent/runtime.go + +const ( + Version = "v0.12.3" // Version of ent codegen. + Sum = "h1:N5lO2EOrHpCH5HYfiMOCHYbo+oh5M8GjT0/cx5x6xkk=" // Sum of ent codegen. +) diff --git a/internal/ent/schema/event.go b/internal/ent/schema/event.go new file mode 100644 index 0000000..5067c09 --- /dev/null +++ b/internal/ent/schema/event.go @@ -0,0 +1,77 @@ +package schema + +import ( + "time" + + "entgo.io/contrib/entgql" + "entgo.io/ent" + "entgo.io/ent/schema" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "entgo.io/ent/schema/index" + "exusiai.dev/roguestats-backend/internal/x/entid" +) + +// Event holds the schema definition for the Event entity. +type Event struct { + ent.Schema +} + +// Fields of the Event. +func (Event) Fields() []ent.Field { + return []ent.Field{ + field.String("id"). + StorageKey("event_id"). + Unique(). + Immutable(). + DefaultFunc(entid.NewGenerator("evt")). + Annotations( + entgql.OrderField("ID"), + ), + field.Time("created_at"). + Immutable(). + Default(time.Now). + Annotations( + entgql.OrderField("CREATED_AT"), + ), + field.String("user_id"), + field.String("research_id"), + field.String("user_agent"), + field.JSON("content", map[string]any{}), + } +} + +// Edges of the Event. +func (Event) Edges() []ent.Edge { + return []ent.Edge{ + edge.From("user", User.Type). + Ref("events"). + Field("user_id"). + Required(). + Unique(), + edge.From("research", Research.Type). + Ref("events"). + Field("research_id"). + Required(). + Unique(), + } +} + +// Indexes of the Event. +func (Event) Indexes() []ent.Index { + return []ent.Index{ + index.Fields("created_at"), + index.Fields("user_agent"), + index.Edges("user"), + index.Edges("research"), + } +} + +// Annotations of the Event. +func (Event) Annotations() []schema.Annotation { + return []schema.Annotation{ + entgql.RelayConnection(), + entgql.QueryField(), + // entgql.Mutations(entgql.MutationCreate()), + } +} diff --git a/internal/ent/schema/research.go b/internal/ent/schema/research.go new file mode 100644 index 0000000..7bf6fc2 --- /dev/null +++ b/internal/ent/schema/research.go @@ -0,0 +1,50 @@ +package schema + +import ( + "entgo.io/contrib/entgql" + "entgo.io/ent" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + + "exusiai.dev/roguestats-backend/internal/x/entid" +) + +// Research holds the schema definition for the Research entity. +type Research struct { + ent.Schema +} + +// Fields of the Research. +func (Research) Fields() []ent.Field { + return []ent.Field{ + field.String("id"). + StorageKey("research_id"). + Unique(). + DefaultFunc(entid.NewGenerator("rsc")). + Immutable(). + Annotations( + entgql.OrderField("ID"), + ), + field.String("name").MaxLen(64), + field.JSON("schema", map[string]any{}), + } +} + +// Edges of the Research. +func (Research) Edges() []ent.Edge { + return []ent.Edge{ + edge.To("events", Event.Type). + // Required(). + Annotations(entsql.OnDelete(entsql.NoAction)), + } +} + +// Annotations of the Research. +func (Research) Annotations() []schema.Annotation { + return []schema.Annotation{ + entgql.RelayConnection(), + entgql.QueryField(), + } +} diff --git a/internal/ent/schema/user.go b/internal/ent/schema/user.go new file mode 100644 index 0000000..5915573 --- /dev/null +++ b/internal/ent/schema/user.go @@ -0,0 +1,47 @@ +package schema + +import ( + "entgo.io/ent" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + + "exusiai.dev/roguestats-backend/internal/x/entid" +) + +// User holds the schema definition for the User entity. +type User struct { + ent.Schema +} + +// Fields of the User. +func (User) Fields() []ent.Field { + return []ent.Field{ + field.String("id"). + StorageKey("user_id"). + Unique(). + DefaultFunc(entid.NewGenerator("usr")). + Immutable(), + field.String("name").MaxLen(64), + field.String("email").Unique().Immutable(), + field.String("credential").MaxLen(64), + field.JSON("attributes", map[string]any{}).Optional(), + } +} + +// Edges of the User. +func (User) Edges() []ent.Edge { + return []ent.Edge{ + edge.To("events", Event.Type). + // Required(). + Annotations(entsql.OnDelete(entsql.NoAction)), + } +} + +// Annotations of the User. +func (User) Annotations() []schema.Annotation { + return []schema.Annotation{ + // entgql.Mutations(entgql.MutationCreate()), + } +} diff --git a/internal/ent/tx.go b/internal/ent/tx.go new file mode 100644 index 0000000..0bf85bd --- /dev/null +++ b/internal/ent/tx.go @@ -0,0 +1,216 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "sync" + + "entgo.io/ent/dialect" +) + +// Tx is a transactional client that is created by calling Client.Tx(). +type Tx struct { + config + // Event is the client for interacting with the Event builders. + Event *EventClient + // Research is the client for interacting with the Research builders. + Research *ResearchClient + // User is the client for interacting with the User builders. + User *UserClient + + // lazily loaded. + client *Client + clientOnce sync.Once + // ctx lives for the life of the transaction. It is + // the same context used by the underlying connection. + ctx context.Context +} + +type ( + // Committer is the interface that wraps the Commit method. + Committer interface { + Commit(context.Context, *Tx) error + } + + // The CommitFunc type is an adapter to allow the use of ordinary + // function as a Committer. If f is a function with the appropriate + // signature, CommitFunc(f) is a Committer that calls f. + CommitFunc func(context.Context, *Tx) error + + // CommitHook defines the "commit middleware". A function that gets a Committer + // and returns a Committer. For example: + // + // hook := func(next ent.Committer) ent.Committer { + // return ent.CommitFunc(func(ctx context.Context, tx *ent.Tx) error { + // // Do some stuff before. + // if err := next.Commit(ctx, tx); err != nil { + // return err + // } + // // Do some stuff after. + // return nil + // }) + // } + // + CommitHook func(Committer) Committer +) + +// Commit calls f(ctx, m). +func (f CommitFunc) Commit(ctx context.Context, tx *Tx) error { + return f(ctx, tx) +} + +// Commit commits the transaction. +func (tx *Tx) Commit() error { + txDriver := tx.config.driver.(*txDriver) + var fn Committer = CommitFunc(func(context.Context, *Tx) error { + return txDriver.tx.Commit() + }) + txDriver.mu.Lock() + hooks := append([]CommitHook(nil), txDriver.onCommit...) + txDriver.mu.Unlock() + for i := len(hooks) - 1; i >= 0; i-- { + fn = hooks[i](fn) + } + return fn.Commit(tx.ctx, tx) +} + +// OnCommit adds a hook to call on commit. +func (tx *Tx) OnCommit(f CommitHook) { + txDriver := tx.config.driver.(*txDriver) + txDriver.mu.Lock() + txDriver.onCommit = append(txDriver.onCommit, f) + txDriver.mu.Unlock() +} + +type ( + // Rollbacker is the interface that wraps the Rollback method. + Rollbacker interface { + Rollback(context.Context, *Tx) error + } + + // The RollbackFunc type is an adapter to allow the use of ordinary + // function as a Rollbacker. If f is a function with the appropriate + // signature, RollbackFunc(f) is a Rollbacker that calls f. + RollbackFunc func(context.Context, *Tx) error + + // RollbackHook defines the "rollback middleware". A function that gets a Rollbacker + // and returns a Rollbacker. For example: + // + // hook := func(next ent.Rollbacker) ent.Rollbacker { + // return ent.RollbackFunc(func(ctx context.Context, tx *ent.Tx) error { + // // Do some stuff before. + // if err := next.Rollback(ctx, tx); err != nil { + // return err + // } + // // Do some stuff after. + // return nil + // }) + // } + // + RollbackHook func(Rollbacker) Rollbacker +) + +// Rollback calls f(ctx, m). +func (f RollbackFunc) Rollback(ctx context.Context, tx *Tx) error { + return f(ctx, tx) +} + +// Rollback rollbacks the transaction. +func (tx *Tx) Rollback() error { + txDriver := tx.config.driver.(*txDriver) + var fn Rollbacker = RollbackFunc(func(context.Context, *Tx) error { + return txDriver.tx.Rollback() + }) + txDriver.mu.Lock() + hooks := append([]RollbackHook(nil), txDriver.onRollback...) + txDriver.mu.Unlock() + for i := len(hooks) - 1; i >= 0; i-- { + fn = hooks[i](fn) + } + return fn.Rollback(tx.ctx, tx) +} + +// OnRollback adds a hook to call on rollback. +func (tx *Tx) OnRollback(f RollbackHook) { + txDriver := tx.config.driver.(*txDriver) + txDriver.mu.Lock() + txDriver.onRollback = append(txDriver.onRollback, f) + txDriver.mu.Unlock() +} + +// Client returns a Client that binds to current transaction. +func (tx *Tx) Client() *Client { + tx.clientOnce.Do(func() { + tx.client = &Client{config: tx.config} + tx.client.init() + }) + return tx.client +} + +func (tx *Tx) init() { + tx.Event = NewEventClient(tx.config) + tx.Research = NewResearchClient(tx.config) + tx.User = NewUserClient(tx.config) +} + +// txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation. +// The idea is to support transactions without adding any extra code to the builders. +// When a builder calls to driver.Tx(), it gets the same dialect.Tx instance. +// Commit and Rollback are nop for the internal builders and the user must call one +// of them in order to commit or rollback the transaction. +// +// If a closed transaction is embedded in one of the generated entities, and the entity +// applies a query, for example: Event.QueryXXX(), the query will be executed +// through the driver which created this transaction. +// +// Note that txDriver is not goroutine safe. +type txDriver struct { + // the driver we started the transaction from. + drv dialect.Driver + // tx is the underlying transaction. + tx dialect.Tx + // completion hooks. + mu sync.Mutex + onCommit []CommitHook + onRollback []RollbackHook +} + +// newTx creates a new transactional driver. +func newTx(ctx context.Context, drv dialect.Driver) (*txDriver, error) { + tx, err := drv.Tx(ctx) + if err != nil { + return nil, err + } + return &txDriver{tx: tx, drv: drv}, nil +} + +// Tx returns the transaction wrapper (txDriver) to avoid Commit or Rollback calls +// from the internal builders. Should be called only by the internal builders. +func (tx *txDriver) Tx(context.Context) (dialect.Tx, error) { return tx, nil } + +// Dialect returns the dialect of the driver we started the transaction from. +func (tx *txDriver) Dialect() string { return tx.drv.Dialect() } + +// Close is a nop close. +func (*txDriver) Close() error { return nil } + +// Commit is a nop commit for the internal builders. +// User must call `Tx.Commit` in order to commit the transaction. +func (*txDriver) Commit() error { return nil } + +// Rollback is a nop rollback for the internal builders. +// User must call `Tx.Rollback` in order to rollback the transaction. +func (*txDriver) Rollback() error { return nil } + +// Exec calls tx.Exec. +func (tx *txDriver) Exec(ctx context.Context, query string, args, v any) error { + return tx.tx.Exec(ctx, query, args, v) +} + +// Query calls tx.Query. +func (tx *txDriver) Query(ctx context.Context, query string, args, v any) error { + return tx.tx.Query(ctx, query, args, v) +} + +var _ dialect.Driver = (*txDriver)(nil) diff --git a/internal/ent/user.go b/internal/ent/user.go new file mode 100644 index 0000000..593de9c --- /dev/null +++ b/internal/ent/user.go @@ -0,0 +1,193 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "encoding/json" + "fmt" + "strings" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// User is the model entity for the User schema. +type User struct { + config `json:"-"` + // ID of the ent. + ID string `json:"id,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` + // Email holds the value of the "email" field. + Email string `json:"email,omitempty"` + // Credential holds the value of the "credential" field. + Credential string `json:"credential,omitempty"` + // Attributes holds the value of the "attributes" field. + Attributes map[string]interface{} `json:"attributes,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the UserQuery when eager-loading is set. + Edges UserEdges `json:"edges"` + selectValues sql.SelectValues +} + +// UserEdges holds the relations/edges for other nodes in the graph. +type UserEdges struct { + // Events holds the value of the events edge. + Events []*Event `json:"events,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [1]bool + // totalCount holds the count of the edges above. + totalCount [1]map[string]int + + namedEvents map[string][]*Event +} + +// EventsOrErr returns the Events value or an error if the edge +// was not loaded in eager-loading. +func (e UserEdges) EventsOrErr() ([]*Event, error) { + if e.loadedTypes[0] { + return e.Events, nil + } + return nil, &NotLoadedError{edge: "events"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*User) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case user.FieldAttributes: + values[i] = new([]byte) + case user.FieldID, user.FieldName, user.FieldEmail, user.FieldCredential: + values[i] = new(sql.NullString) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the User fields. +func (u *User) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case user.FieldID: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field id", values[i]) + } else if value.Valid { + u.ID = value.String + } + case user.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + u.Name = value.String + } + case user.FieldEmail: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field email", values[i]) + } else if value.Valid { + u.Email = value.String + } + case user.FieldCredential: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field credential", values[i]) + } else if value.Valid { + u.Credential = value.String + } + case user.FieldAttributes: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field attributes", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &u.Attributes); err != nil { + return fmt.Errorf("unmarshal field attributes: %w", err) + } + } + default: + u.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the User. +// This includes values selected through modifiers, order, etc. +func (u *User) Value(name string) (ent.Value, error) { + return u.selectValues.Get(name) +} + +// QueryEvents queries the "events" edge of the User entity. +func (u *User) QueryEvents() *EventQuery { + return NewUserClient(u.config).QueryEvents(u) +} + +// Update returns a builder for updating this User. +// Note that you need to call User.Unwrap() before calling this method if this User +// was returned from a transaction, and the transaction was committed or rolled back. +func (u *User) Update() *UserUpdateOne { + return NewUserClient(u.config).UpdateOne(u) +} + +// Unwrap unwraps the User entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (u *User) Unwrap() *User { + _tx, ok := u.config.driver.(*txDriver) + if !ok { + panic("ent: User is not a transactional entity") + } + u.config.driver = _tx.drv + return u +} + +// String implements the fmt.Stringer. +func (u *User) String() string { + var builder strings.Builder + builder.WriteString("User(") + builder.WriteString(fmt.Sprintf("id=%v, ", u.ID)) + builder.WriteString("name=") + builder.WriteString(u.Name) + builder.WriteString(", ") + builder.WriteString("email=") + builder.WriteString(u.Email) + builder.WriteString(", ") + builder.WriteString("credential=") + builder.WriteString(u.Credential) + builder.WriteString(", ") + builder.WriteString("attributes=") + builder.WriteString(fmt.Sprintf("%v", u.Attributes)) + builder.WriteByte(')') + return builder.String() +} + +// NamedEvents returns the Events named value or an error if the edge was not +// loaded in eager-loading with this name. +func (u *User) NamedEvents(name string) ([]*Event, error) { + if u.Edges.namedEvents == nil { + return nil, &NotLoadedError{edge: name} + } + nodes, ok := u.Edges.namedEvents[name] + if !ok { + return nil, &NotLoadedError{edge: name} + } + return nodes, nil +} + +func (u *User) appendNamedEvents(name string, edges ...*Event) { + if u.Edges.namedEvents == nil { + u.Edges.namedEvents = make(map[string][]*Event) + } + if len(edges) == 0 { + u.Edges.namedEvents[name] = []*Event{} + } else { + u.Edges.namedEvents[name] = append(u.Edges.namedEvents[name], edges...) + } +} + +// Users is a parsable slice of User. +type Users []*User diff --git a/internal/ent/user/user.go b/internal/ent/user/user.go new file mode 100644 index 0000000..7ed9510 --- /dev/null +++ b/internal/ent/user/user.go @@ -0,0 +1,108 @@ +// Code generated by ent, DO NOT EDIT. + +package user + +import ( + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +const ( + // Label holds the string label denoting the user type in the database. + Label = "user" + // FieldID holds the string denoting the id field in the database. + FieldID = "user_id" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" + // FieldEmail holds the string denoting the email field in the database. + FieldEmail = "email" + // FieldCredential holds the string denoting the credential field in the database. + FieldCredential = "credential" + // FieldAttributes holds the string denoting the attributes field in the database. + FieldAttributes = "attributes" + // EdgeEvents holds the string denoting the events edge name in mutations. + EdgeEvents = "events" + // EventFieldID holds the string denoting the ID field of the Event. + EventFieldID = "event_id" + // Table holds the table name of the user in the database. + Table = "users" + // EventsTable is the table that holds the events relation/edge. + EventsTable = "events" + // EventsInverseTable is the table name for the Event entity. + // It exists in this package in order to avoid circular dependency with the "event" package. + EventsInverseTable = "events" + // EventsColumn is the table column denoting the events relation/edge. + EventsColumn = "user_events" +) + +// Columns holds all SQL columns for user fields. +var Columns = []string{ + FieldID, + FieldName, + FieldEmail, + FieldCredential, + FieldAttributes, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // NameValidator is a validator for the "name" field. It is called by the builders before save. + NameValidator func(string) error + // CredentialValidator is a validator for the "credential" field. It is called by the builders before save. + CredentialValidator func(string) error + // DefaultID holds the default value on creation for the "id" field. + DefaultID func() string +) + +// OrderOption defines the ordering options for the User queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByName orders the results by the name field. +func ByName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldName, opts...).ToFunc() +} + +// ByEmail orders the results by the email field. +func ByEmail(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldEmail, opts...).ToFunc() +} + +// ByCredential orders the results by the credential field. +func ByCredential(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCredential, opts...).ToFunc() +} + +// ByEventsCount orders the results by events count. +func ByEventsCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newEventsStep(), opts...) + } +} + +// ByEvents orders the results by events terms. +func ByEvents(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newEventsStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} +func newEventsStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(EventsInverseTable, EventFieldID), + sqlgraph.Edge(sqlgraph.O2M, false, EventsTable, EventsColumn), + ) +} diff --git a/internal/ent/user/where.go b/internal/ent/user/where.go new file mode 100644 index 0000000..d7542c3 --- /dev/null +++ b/internal/ent/user/where.go @@ -0,0 +1,339 @@ +// Code generated by ent, DO NOT EDIT. + +package user + +import ( + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "exusiai.dev/roguestats-backend/internal/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id string) predicate.User { + return predicate.User(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id string) predicate.User { + return predicate.User(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id string) predicate.User { + return predicate.User(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...string) predicate.User { + return predicate.User(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...string) predicate.User { + return predicate.User(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id string) predicate.User { + return predicate.User(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id string) predicate.User { + return predicate.User(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id string) predicate.User { + return predicate.User(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id string) predicate.User { + return predicate.User(sql.FieldLTE(FieldID, id)) +} + +// IDEqualFold applies the EqualFold predicate on the ID field. +func IDEqualFold(id string) predicate.User { + return predicate.User(sql.FieldEqualFold(FieldID, id)) +} + +// IDContainsFold applies the ContainsFold predicate on the ID field. +func IDContainsFold(id string) predicate.User { + return predicate.User(sql.FieldContainsFold(FieldID, id)) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldName, v)) +} + +// Email applies equality check predicate on the "email" field. It's identical to EmailEQ. +func Email(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldEmail, v)) +} + +// Credential applies equality check predicate on the "credential" field. It's identical to CredentialEQ. +func Credential(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldCredential, v)) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldName, v)) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.User { + return predicate.User(sql.FieldNEQ(FieldName, v)) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.User { + return predicate.User(sql.FieldIn(FieldName, vs...)) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.User { + return predicate.User(sql.FieldNotIn(FieldName, vs...)) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.User { + return predicate.User(sql.FieldGT(FieldName, v)) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.User { + return predicate.User(sql.FieldGTE(FieldName, v)) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.User { + return predicate.User(sql.FieldLT(FieldName, v)) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.User { + return predicate.User(sql.FieldLTE(FieldName, v)) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.User { + return predicate.User(sql.FieldContains(FieldName, v)) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.User { + return predicate.User(sql.FieldHasPrefix(FieldName, v)) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.User { + return predicate.User(sql.FieldHasSuffix(FieldName, v)) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.User { + return predicate.User(sql.FieldEqualFold(FieldName, v)) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.User { + return predicate.User(sql.FieldContainsFold(FieldName, v)) +} + +// EmailEQ applies the EQ predicate on the "email" field. +func EmailEQ(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldEmail, v)) +} + +// EmailNEQ applies the NEQ predicate on the "email" field. +func EmailNEQ(v string) predicate.User { + return predicate.User(sql.FieldNEQ(FieldEmail, v)) +} + +// EmailIn applies the In predicate on the "email" field. +func EmailIn(vs ...string) predicate.User { + return predicate.User(sql.FieldIn(FieldEmail, vs...)) +} + +// EmailNotIn applies the NotIn predicate on the "email" field. +func EmailNotIn(vs ...string) predicate.User { + return predicate.User(sql.FieldNotIn(FieldEmail, vs...)) +} + +// EmailGT applies the GT predicate on the "email" field. +func EmailGT(v string) predicate.User { + return predicate.User(sql.FieldGT(FieldEmail, v)) +} + +// EmailGTE applies the GTE predicate on the "email" field. +func EmailGTE(v string) predicate.User { + return predicate.User(sql.FieldGTE(FieldEmail, v)) +} + +// EmailLT applies the LT predicate on the "email" field. +func EmailLT(v string) predicate.User { + return predicate.User(sql.FieldLT(FieldEmail, v)) +} + +// EmailLTE applies the LTE predicate on the "email" field. +func EmailLTE(v string) predicate.User { + return predicate.User(sql.FieldLTE(FieldEmail, v)) +} + +// EmailContains applies the Contains predicate on the "email" field. +func EmailContains(v string) predicate.User { + return predicate.User(sql.FieldContains(FieldEmail, v)) +} + +// EmailHasPrefix applies the HasPrefix predicate on the "email" field. +func EmailHasPrefix(v string) predicate.User { + return predicate.User(sql.FieldHasPrefix(FieldEmail, v)) +} + +// EmailHasSuffix applies the HasSuffix predicate on the "email" field. +func EmailHasSuffix(v string) predicate.User { + return predicate.User(sql.FieldHasSuffix(FieldEmail, v)) +} + +// EmailEqualFold applies the EqualFold predicate on the "email" field. +func EmailEqualFold(v string) predicate.User { + return predicate.User(sql.FieldEqualFold(FieldEmail, v)) +} + +// EmailContainsFold applies the ContainsFold predicate on the "email" field. +func EmailContainsFold(v string) predicate.User { + return predicate.User(sql.FieldContainsFold(FieldEmail, v)) +} + +// CredentialEQ applies the EQ predicate on the "credential" field. +func CredentialEQ(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldCredential, v)) +} + +// CredentialNEQ applies the NEQ predicate on the "credential" field. +func CredentialNEQ(v string) predicate.User { + return predicate.User(sql.FieldNEQ(FieldCredential, v)) +} + +// CredentialIn applies the In predicate on the "credential" field. +func CredentialIn(vs ...string) predicate.User { + return predicate.User(sql.FieldIn(FieldCredential, vs...)) +} + +// CredentialNotIn applies the NotIn predicate on the "credential" field. +func CredentialNotIn(vs ...string) predicate.User { + return predicate.User(sql.FieldNotIn(FieldCredential, vs...)) +} + +// CredentialGT applies the GT predicate on the "credential" field. +func CredentialGT(v string) predicate.User { + return predicate.User(sql.FieldGT(FieldCredential, v)) +} + +// CredentialGTE applies the GTE predicate on the "credential" field. +func CredentialGTE(v string) predicate.User { + return predicate.User(sql.FieldGTE(FieldCredential, v)) +} + +// CredentialLT applies the LT predicate on the "credential" field. +func CredentialLT(v string) predicate.User { + return predicate.User(sql.FieldLT(FieldCredential, v)) +} + +// CredentialLTE applies the LTE predicate on the "credential" field. +func CredentialLTE(v string) predicate.User { + return predicate.User(sql.FieldLTE(FieldCredential, v)) +} + +// CredentialContains applies the Contains predicate on the "credential" field. +func CredentialContains(v string) predicate.User { + return predicate.User(sql.FieldContains(FieldCredential, v)) +} + +// CredentialHasPrefix applies the HasPrefix predicate on the "credential" field. +func CredentialHasPrefix(v string) predicate.User { + return predicate.User(sql.FieldHasPrefix(FieldCredential, v)) +} + +// CredentialHasSuffix applies the HasSuffix predicate on the "credential" field. +func CredentialHasSuffix(v string) predicate.User { + return predicate.User(sql.FieldHasSuffix(FieldCredential, v)) +} + +// CredentialEqualFold applies the EqualFold predicate on the "credential" field. +func CredentialEqualFold(v string) predicate.User { + return predicate.User(sql.FieldEqualFold(FieldCredential, v)) +} + +// CredentialContainsFold applies the ContainsFold predicate on the "credential" field. +func CredentialContainsFold(v string) predicate.User { + return predicate.User(sql.FieldContainsFold(FieldCredential, v)) +} + +// AttributesIsNil applies the IsNil predicate on the "attributes" field. +func AttributesIsNil() predicate.User { + return predicate.User(sql.FieldIsNull(FieldAttributes)) +} + +// AttributesNotNil applies the NotNil predicate on the "attributes" field. +func AttributesNotNil() predicate.User { + return predicate.User(sql.FieldNotNull(FieldAttributes)) +} + +// HasEvents applies the HasEdge predicate on the "events" edge. +func HasEvents() predicate.User { + return predicate.User(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, EventsTable, EventsColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasEventsWith applies the HasEdge predicate on the "events" edge with a given conditions (other predicates). +func HasEventsWith(preds ...predicate.Event) predicate.User { + return predicate.User(func(s *sql.Selector) { + step := newEventsStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.User) predicate.User { + return predicate.User(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.User) predicate.User { + return predicate.User(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.User) predicate.User { + return predicate.User(func(s *sql.Selector) { + p(s.Not()) + }) +} diff --git a/internal/ent/user_create.go b/internal/ent/user_create.go new file mode 100644 index 0000000..e042fc9 --- /dev/null +++ b/internal/ent/user_create.go @@ -0,0 +1,289 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// UserCreate is the builder for creating a User entity. +type UserCreate struct { + config + mutation *UserMutation + hooks []Hook +} + +// SetName sets the "name" field. +func (uc *UserCreate) SetName(s string) *UserCreate { + uc.mutation.SetName(s) + return uc +} + +// SetEmail sets the "email" field. +func (uc *UserCreate) SetEmail(s string) *UserCreate { + uc.mutation.SetEmail(s) + return uc +} + +// SetCredential sets the "credential" field. +func (uc *UserCreate) SetCredential(s string) *UserCreate { + uc.mutation.SetCredential(s) + return uc +} + +// SetAttributes sets the "attributes" field. +func (uc *UserCreate) SetAttributes(m map[string]interface{}) *UserCreate { + uc.mutation.SetAttributes(m) + return uc +} + +// SetID sets the "id" field. +func (uc *UserCreate) SetID(s string) *UserCreate { + uc.mutation.SetID(s) + return uc +} + +// SetNillableID sets the "id" field if the given value is not nil. +func (uc *UserCreate) SetNillableID(s *string) *UserCreate { + if s != nil { + uc.SetID(*s) + } + return uc +} + +// AddEventIDs adds the "events" edge to the Event entity by IDs. +func (uc *UserCreate) AddEventIDs(ids ...string) *UserCreate { + uc.mutation.AddEventIDs(ids...) + return uc +} + +// AddEvents adds the "events" edges to the Event entity. +func (uc *UserCreate) AddEvents(e ...*Event) *UserCreate { + ids := make([]string, len(e)) + for i := range e { + ids[i] = e[i].ID + } + return uc.AddEventIDs(ids...) +} + +// Mutation returns the UserMutation object of the builder. +func (uc *UserCreate) Mutation() *UserMutation { + return uc.mutation +} + +// Save creates the User in the database. +func (uc *UserCreate) Save(ctx context.Context) (*User, error) { + uc.defaults() + return withHooks(ctx, uc.sqlSave, uc.mutation, uc.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (uc *UserCreate) SaveX(ctx context.Context) *User { + v, err := uc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (uc *UserCreate) Exec(ctx context.Context) error { + _, err := uc.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (uc *UserCreate) ExecX(ctx context.Context) { + if err := uc.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (uc *UserCreate) defaults() { + if _, ok := uc.mutation.ID(); !ok { + v := user.DefaultID() + uc.mutation.SetID(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (uc *UserCreate) check() error { + if _, ok := uc.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "User.name"`)} + } + if v, ok := uc.mutation.Name(); ok { + if err := user.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "User.name": %w`, err)} + } + } + if _, ok := uc.mutation.Email(); !ok { + return &ValidationError{Name: "email", err: errors.New(`ent: missing required field "User.email"`)} + } + if _, ok := uc.mutation.Credential(); !ok { + return &ValidationError{Name: "credential", err: errors.New(`ent: missing required field "User.credential"`)} + } + if v, ok := uc.mutation.Credential(); ok { + if err := user.CredentialValidator(v); err != nil { + return &ValidationError{Name: "credential", err: fmt.Errorf(`ent: validator failed for field "User.credential": %w`, err)} + } + } + if len(uc.mutation.EventsIDs()) == 0 { + return &ValidationError{Name: "events", err: errors.New(`ent: missing required edge "User.events"`)} + } + return nil +} + +func (uc *UserCreate) sqlSave(ctx context.Context) (*User, error) { + if err := uc.check(); err != nil { + return nil, err + } + _node, _spec := uc.createSpec() + if err := sqlgraph.CreateNode(ctx, uc.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + if _spec.ID.Value != nil { + if id, ok := _spec.ID.Value.(string); ok { + _node.ID = id + } else { + return nil, fmt.Errorf("unexpected User.ID type: %T", _spec.ID.Value) + } + } + uc.mutation.id = &_node.ID + uc.mutation.done = true + return _node, nil +} + +func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { + var ( + _node = &User{config: uc.config} + _spec = sqlgraph.NewCreateSpec(user.Table, sqlgraph.NewFieldSpec(user.FieldID, field.TypeString)) + ) + if id, ok := uc.mutation.ID(); ok { + _node.ID = id + _spec.ID.Value = id + } + if value, ok := uc.mutation.Name(); ok { + _spec.SetField(user.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := uc.mutation.Email(); ok { + _spec.SetField(user.FieldEmail, field.TypeString, value) + _node.Email = value + } + if value, ok := uc.mutation.Credential(); ok { + _spec.SetField(user.FieldCredential, field.TypeString, value) + _node.Credential = value + } + if value, ok := uc.mutation.Attributes(); ok { + _spec.SetField(user.FieldAttributes, field.TypeJSON, value) + _node.Attributes = value + } + if nodes := uc.mutation.EventsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: user.EventsTable, + Columns: []string{user.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// UserCreateBulk is the builder for creating many User entities in bulk. +type UserCreateBulk struct { + config + builders []*UserCreate +} + +// Save creates the User entities in the database. +func (ucb *UserCreateBulk) Save(ctx context.Context) ([]*User, error) { + specs := make([]*sqlgraph.CreateSpec, len(ucb.builders)) + nodes := make([]*User, len(ucb.builders)) + mutators := make([]Mutator, len(ucb.builders)) + for i := range ucb.builders { + func(i int, root context.Context) { + builder := ucb.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*UserMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, ucb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, ucb.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, ucb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (ucb *UserCreateBulk) SaveX(ctx context.Context) []*User { + v, err := ucb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (ucb *UserCreateBulk) Exec(ctx context.Context) error { + _, err := ucb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (ucb *UserCreateBulk) ExecX(ctx context.Context) { + if err := ucb.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/internal/ent/user_delete.go b/internal/ent/user_delete.go new file mode 100644 index 0000000..7b35d61 --- /dev/null +++ b/internal/ent/user_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/predicate" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// UserDelete is the builder for deleting a User entity. +type UserDelete struct { + config + hooks []Hook + mutation *UserMutation +} + +// Where appends a list predicates to the UserDelete builder. +func (ud *UserDelete) Where(ps ...predicate.User) *UserDelete { + ud.mutation.Where(ps...) + return ud +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (ud *UserDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, ud.sqlExec, ud.mutation, ud.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (ud *UserDelete) ExecX(ctx context.Context) int { + n, err := ud.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (ud *UserDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(user.Table, sqlgraph.NewFieldSpec(user.FieldID, field.TypeString)) + if ps := ud.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, ud.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + ud.mutation.done = true + return affected, err +} + +// UserDeleteOne is the builder for deleting a single User entity. +type UserDeleteOne struct { + ud *UserDelete +} + +// Where appends a list predicates to the UserDelete builder. +func (udo *UserDeleteOne) Where(ps ...predicate.User) *UserDeleteOne { + udo.ud.mutation.Where(ps...) + return udo +} + +// Exec executes the deletion query. +func (udo *UserDeleteOne) Exec(ctx context.Context) error { + n, err := udo.ud.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{user.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (udo *UserDeleteOne) ExecX(ctx context.Context) { + if err := udo.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/internal/ent/user_query.go b/internal/ent/user_query.go new file mode 100644 index 0000000..74404cd --- /dev/null +++ b/internal/ent/user_query.go @@ -0,0 +1,641 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "database/sql/driver" + "fmt" + "math" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/predicate" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// UserQuery is the builder for querying User entities. +type UserQuery struct { + config + ctx *QueryContext + order []user.OrderOption + inters []Interceptor + predicates []predicate.User + withEvents *EventQuery + modifiers []func(*sql.Selector) + loadTotal []func(context.Context, []*User) error + withNamedEvents map[string]*EventQuery + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the UserQuery builder. +func (uq *UserQuery) Where(ps ...predicate.User) *UserQuery { + uq.predicates = append(uq.predicates, ps...) + return uq +} + +// Limit the number of records to be returned by this query. +func (uq *UserQuery) Limit(limit int) *UserQuery { + uq.ctx.Limit = &limit + return uq +} + +// Offset to start from. +func (uq *UserQuery) Offset(offset int) *UserQuery { + uq.ctx.Offset = &offset + return uq +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (uq *UserQuery) Unique(unique bool) *UserQuery { + uq.ctx.Unique = &unique + return uq +} + +// Order specifies how the records should be ordered. +func (uq *UserQuery) Order(o ...user.OrderOption) *UserQuery { + uq.order = append(uq.order, o...) + return uq +} + +// QueryEvents chains the current query on the "events" edge. +func (uq *UserQuery) QueryEvents() *EventQuery { + query := (&EventClient{config: uq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := uq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := uq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(user.Table, user.FieldID, selector), + sqlgraph.To(event.Table, event.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, user.EventsTable, user.EventsColumn), + ) + fromU = sqlgraph.SetNeighbors(uq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first User entity from the query. +// Returns a *NotFoundError when no User was found. +func (uq *UserQuery) First(ctx context.Context) (*User, error) { + nodes, err := uq.Limit(1).All(setContextOp(ctx, uq.ctx, "First")) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{user.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (uq *UserQuery) FirstX(ctx context.Context) *User { + node, err := uq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first User ID from the query. +// Returns a *NotFoundError when no User ID was found. +func (uq *UserQuery) FirstID(ctx context.Context) (id string, err error) { + var ids []string + if ids, err = uq.Limit(1).IDs(setContextOp(ctx, uq.ctx, "FirstID")); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{user.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (uq *UserQuery) FirstIDX(ctx context.Context) string { + id, err := uq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single User entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one User entity is found. +// Returns a *NotFoundError when no User entities are found. +func (uq *UserQuery) Only(ctx context.Context) (*User, error) { + nodes, err := uq.Limit(2).All(setContextOp(ctx, uq.ctx, "Only")) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{user.Label} + default: + return nil, &NotSingularError{user.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (uq *UserQuery) OnlyX(ctx context.Context) *User { + node, err := uq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only User ID in the query. +// Returns a *NotSingularError when more than one User ID is found. +// Returns a *NotFoundError when no entities are found. +func (uq *UserQuery) OnlyID(ctx context.Context) (id string, err error) { + var ids []string + if ids, err = uq.Limit(2).IDs(setContextOp(ctx, uq.ctx, "OnlyID")); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{user.Label} + default: + err = &NotSingularError{user.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (uq *UserQuery) OnlyIDX(ctx context.Context) string { + id, err := uq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of Users. +func (uq *UserQuery) All(ctx context.Context) ([]*User, error) { + ctx = setContextOp(ctx, uq.ctx, "All") + if err := uq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*User, *UserQuery]() + return withInterceptors[[]*User](ctx, uq, qr, uq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (uq *UserQuery) AllX(ctx context.Context) []*User { + nodes, err := uq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of User IDs. +func (uq *UserQuery) IDs(ctx context.Context) (ids []string, err error) { + if uq.ctx.Unique == nil && uq.path != nil { + uq.Unique(true) + } + ctx = setContextOp(ctx, uq.ctx, "IDs") + if err = uq.Select(user.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (uq *UserQuery) IDsX(ctx context.Context) []string { + ids, err := uq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (uq *UserQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, uq.ctx, "Count") + if err := uq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, uq, querierCount[*UserQuery](), uq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (uq *UserQuery) CountX(ctx context.Context) int { + count, err := uq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (uq *UserQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, uq.ctx, "Exist") + switch _, err := uq.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (uq *UserQuery) ExistX(ctx context.Context) bool { + exist, err := uq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the UserQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (uq *UserQuery) Clone() *UserQuery { + if uq == nil { + return nil + } + return &UserQuery{ + config: uq.config, + ctx: uq.ctx.Clone(), + order: append([]user.OrderOption{}, uq.order...), + inters: append([]Interceptor{}, uq.inters...), + predicates: append([]predicate.User{}, uq.predicates...), + withEvents: uq.withEvents.Clone(), + // clone intermediate query. + sql: uq.sql.Clone(), + path: uq.path, + } +} + +// WithEvents tells the query-builder to eager-load the nodes that are connected to +// the "events" edge. The optional arguments are used to configure the query builder of the edge. +func (uq *UserQuery) WithEvents(opts ...func(*EventQuery)) *UserQuery { + query := (&EventClient{config: uq.config}).Query() + for _, opt := range opts { + opt(query) + } + uq.withEvents = query + return uq +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.User.Query(). +// GroupBy(user.FieldName). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (uq *UserQuery) GroupBy(field string, fields ...string) *UserGroupBy { + uq.ctx.Fields = append([]string{field}, fields...) + grbuild := &UserGroupBy{build: uq} + grbuild.flds = &uq.ctx.Fields + grbuild.label = user.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// } +// +// client.User.Query(). +// Select(user.FieldName). +// Scan(ctx, &v) +func (uq *UserQuery) Select(fields ...string) *UserSelect { + uq.ctx.Fields = append(uq.ctx.Fields, fields...) + sbuild := &UserSelect{UserQuery: uq} + sbuild.label = user.Label + sbuild.flds, sbuild.scan = &uq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a UserSelect configured with the given aggregations. +func (uq *UserQuery) Aggregate(fns ...AggregateFunc) *UserSelect { + return uq.Select().Aggregate(fns...) +} + +func (uq *UserQuery) prepareQuery(ctx context.Context) error { + for _, inter := range uq.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, uq); err != nil { + return err + } + } + } + for _, f := range uq.ctx.Fields { + if !user.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if uq.path != nil { + prev, err := uq.path(ctx) + if err != nil { + return err + } + uq.sql = prev + } + return nil +} + +func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, error) { + var ( + nodes = []*User{} + _spec = uq.querySpec() + loadedTypes = [1]bool{ + uq.withEvents != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*User).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &User{config: uq.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + if len(uq.modifiers) > 0 { + _spec.Modifiers = uq.modifiers + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, uq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := uq.withEvents; query != nil { + if err := uq.loadEvents(ctx, query, nodes, + func(n *User) { n.Edges.Events = []*Event{} }, + func(n *User, e *Event) { n.Edges.Events = append(n.Edges.Events, e) }); err != nil { + return nil, err + } + } + for name, query := range uq.withNamedEvents { + if err := uq.loadEvents(ctx, query, nodes, + func(n *User) { n.appendNamedEvents(name) }, + func(n *User, e *Event) { n.appendNamedEvents(name, e) }); err != nil { + return nil, err + } + } + for i := range uq.loadTotal { + if err := uq.loadTotal[i](ctx, nodes); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (uq *UserQuery) loadEvents(ctx context.Context, query *EventQuery, nodes []*User, init func(*User), assign func(*User, *Event)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[string]*User) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + query.withFKs = true + query.Where(predicate.Event(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(user.EventsColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.user_events + if fk == nil { + return fmt.Errorf(`foreign-key "user_events" is nil for node %v`, n.ID) + } + node, ok := nodeids[*fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "user_events" returned %v for node %v`, *fk, n.ID) + } + assign(node, n) + } + return nil +} + +func (uq *UserQuery) sqlCount(ctx context.Context) (int, error) { + _spec := uq.querySpec() + if len(uq.modifiers) > 0 { + _spec.Modifiers = uq.modifiers + } + _spec.Node.Columns = uq.ctx.Fields + if len(uq.ctx.Fields) > 0 { + _spec.Unique = uq.ctx.Unique != nil && *uq.ctx.Unique + } + return sqlgraph.CountNodes(ctx, uq.driver, _spec) +} + +func (uq *UserQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(user.Table, user.Columns, sqlgraph.NewFieldSpec(user.FieldID, field.TypeString)) + _spec.From = uq.sql + if unique := uq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if uq.path != nil { + _spec.Unique = true + } + if fields := uq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, user.FieldID) + for i := range fields { + if fields[i] != user.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := uq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := uq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := uq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := uq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (uq *UserQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(uq.driver.Dialect()) + t1 := builder.Table(user.Table) + columns := uq.ctx.Fields + if len(columns) == 0 { + columns = user.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if uq.sql != nil { + selector = uq.sql + selector.Select(selector.Columns(columns...)...) + } + if uq.ctx.Unique != nil && *uq.ctx.Unique { + selector.Distinct() + } + for _, p := range uq.predicates { + p(selector) + } + for _, p := range uq.order { + p(selector) + } + if offset := uq.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := uq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// WithNamedEvents tells the query-builder to eager-load the nodes that are connected to the "events" +// edge with the given name. The optional arguments are used to configure the query builder of the edge. +func (uq *UserQuery) WithNamedEvents(name string, opts ...func(*EventQuery)) *UserQuery { + query := (&EventClient{config: uq.config}).Query() + for _, opt := range opts { + opt(query) + } + if uq.withNamedEvents == nil { + uq.withNamedEvents = make(map[string]*EventQuery) + } + uq.withNamedEvents[name] = query + return uq +} + +// UserGroupBy is the group-by builder for User entities. +type UserGroupBy struct { + selector + build *UserQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (ugb *UserGroupBy) Aggregate(fns ...AggregateFunc) *UserGroupBy { + ugb.fns = append(ugb.fns, fns...) + return ugb +} + +// Scan applies the selector query and scans the result into the given value. +func (ugb *UserGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, ugb.build.ctx, "GroupBy") + if err := ugb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*UserQuery, *UserGroupBy](ctx, ugb.build, ugb, ugb.build.inters, v) +} + +func (ugb *UserGroupBy) sqlScan(ctx context.Context, root *UserQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(ugb.fns)) + for _, fn := range ugb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*ugb.flds)+len(ugb.fns)) + for _, f := range *ugb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*ugb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := ugb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// UserSelect is the builder for selecting fields of User entities. +type UserSelect struct { + *UserQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (us *UserSelect) Aggregate(fns ...AggregateFunc) *UserSelect { + us.fns = append(us.fns, fns...) + return us +} + +// Scan applies the selector query and scans the result into the given value. +func (us *UserSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, us.ctx, "Select") + if err := us.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*UserQuery, *UserSelect](ctx, us.UserQuery, us, us.inters, v) +} + +func (us *UserSelect) sqlScan(ctx context.Context, root *UserQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(us.fns)) + for _, fn := range us.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*us.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := us.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/internal/ent/user_update.go b/internal/ent/user_update.go new file mode 100644 index 0000000..54795ae --- /dev/null +++ b/internal/ent/user_update.go @@ -0,0 +1,446 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/predicate" + "exusiai.dev/roguestats-backend/internal/ent/user" +) + +// UserUpdate is the builder for updating User entities. +type UserUpdate struct { + config + hooks []Hook + mutation *UserMutation +} + +// Where appends a list predicates to the UserUpdate builder. +func (uu *UserUpdate) Where(ps ...predicate.User) *UserUpdate { + uu.mutation.Where(ps...) + return uu +} + +// SetName sets the "name" field. +func (uu *UserUpdate) SetName(s string) *UserUpdate { + uu.mutation.SetName(s) + return uu +} + +// SetCredential sets the "credential" field. +func (uu *UserUpdate) SetCredential(s string) *UserUpdate { + uu.mutation.SetCredential(s) + return uu +} + +// SetAttributes sets the "attributes" field. +func (uu *UserUpdate) SetAttributes(m map[string]interface{}) *UserUpdate { + uu.mutation.SetAttributes(m) + return uu +} + +// ClearAttributes clears the value of the "attributes" field. +func (uu *UserUpdate) ClearAttributes() *UserUpdate { + uu.mutation.ClearAttributes() + return uu +} + +// AddEventIDs adds the "events" edge to the Event entity by IDs. +func (uu *UserUpdate) AddEventIDs(ids ...string) *UserUpdate { + uu.mutation.AddEventIDs(ids...) + return uu +} + +// AddEvents adds the "events" edges to the Event entity. +func (uu *UserUpdate) AddEvents(e ...*Event) *UserUpdate { + ids := make([]string, len(e)) + for i := range e { + ids[i] = e[i].ID + } + return uu.AddEventIDs(ids...) +} + +// Mutation returns the UserMutation object of the builder. +func (uu *UserUpdate) Mutation() *UserMutation { + return uu.mutation +} + +// ClearEvents clears all "events" edges to the Event entity. +func (uu *UserUpdate) ClearEvents() *UserUpdate { + uu.mutation.ClearEvents() + return uu +} + +// RemoveEventIDs removes the "events" edge to Event entities by IDs. +func (uu *UserUpdate) RemoveEventIDs(ids ...string) *UserUpdate { + uu.mutation.RemoveEventIDs(ids...) + return uu +} + +// RemoveEvents removes "events" edges to Event entities. +func (uu *UserUpdate) RemoveEvents(e ...*Event) *UserUpdate { + ids := make([]string, len(e)) + for i := range e { + ids[i] = e[i].ID + } + return uu.RemoveEventIDs(ids...) +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (uu *UserUpdate) Save(ctx context.Context) (int, error) { + return withHooks(ctx, uu.sqlSave, uu.mutation, uu.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (uu *UserUpdate) SaveX(ctx context.Context) int { + affected, err := uu.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (uu *UserUpdate) Exec(ctx context.Context) error { + _, err := uu.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (uu *UserUpdate) ExecX(ctx context.Context) { + if err := uu.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (uu *UserUpdate) check() error { + if v, ok := uu.mutation.Name(); ok { + if err := user.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "User.name": %w`, err)} + } + } + if v, ok := uu.mutation.Credential(); ok { + if err := user.CredentialValidator(v); err != nil { + return &ValidationError{Name: "credential", err: fmt.Errorf(`ent: validator failed for field "User.credential": %w`, err)} + } + } + return nil +} + +func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := uu.check(); err != nil { + return n, err + } + _spec := sqlgraph.NewUpdateSpec(user.Table, user.Columns, sqlgraph.NewFieldSpec(user.FieldID, field.TypeString)) + if ps := uu.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := uu.mutation.Name(); ok { + _spec.SetField(user.FieldName, field.TypeString, value) + } + if value, ok := uu.mutation.Credential(); ok { + _spec.SetField(user.FieldCredential, field.TypeString, value) + } + if value, ok := uu.mutation.Attributes(); ok { + _spec.SetField(user.FieldAttributes, field.TypeJSON, value) + } + if uu.mutation.AttributesCleared() { + _spec.ClearField(user.FieldAttributes, field.TypeJSON) + } + if uu.mutation.EventsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: user.EventsTable, + Columns: []string{user.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uu.mutation.RemovedEventsIDs(); len(nodes) > 0 && !uu.mutation.EventsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: user.EventsTable, + Columns: []string{user.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uu.mutation.EventsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: user.EventsTable, + Columns: []string{user.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if n, err = sqlgraph.UpdateNodes(ctx, uu.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{user.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + uu.mutation.done = true + return n, nil +} + +// UserUpdateOne is the builder for updating a single User entity. +type UserUpdateOne struct { + config + fields []string + hooks []Hook + mutation *UserMutation +} + +// SetName sets the "name" field. +func (uuo *UserUpdateOne) SetName(s string) *UserUpdateOne { + uuo.mutation.SetName(s) + return uuo +} + +// SetCredential sets the "credential" field. +func (uuo *UserUpdateOne) SetCredential(s string) *UserUpdateOne { + uuo.mutation.SetCredential(s) + return uuo +} + +// SetAttributes sets the "attributes" field. +func (uuo *UserUpdateOne) SetAttributes(m map[string]interface{}) *UserUpdateOne { + uuo.mutation.SetAttributes(m) + return uuo +} + +// ClearAttributes clears the value of the "attributes" field. +func (uuo *UserUpdateOne) ClearAttributes() *UserUpdateOne { + uuo.mutation.ClearAttributes() + return uuo +} + +// AddEventIDs adds the "events" edge to the Event entity by IDs. +func (uuo *UserUpdateOne) AddEventIDs(ids ...string) *UserUpdateOne { + uuo.mutation.AddEventIDs(ids...) + return uuo +} + +// AddEvents adds the "events" edges to the Event entity. +func (uuo *UserUpdateOne) AddEvents(e ...*Event) *UserUpdateOne { + ids := make([]string, len(e)) + for i := range e { + ids[i] = e[i].ID + } + return uuo.AddEventIDs(ids...) +} + +// Mutation returns the UserMutation object of the builder. +func (uuo *UserUpdateOne) Mutation() *UserMutation { + return uuo.mutation +} + +// ClearEvents clears all "events" edges to the Event entity. +func (uuo *UserUpdateOne) ClearEvents() *UserUpdateOne { + uuo.mutation.ClearEvents() + return uuo +} + +// RemoveEventIDs removes the "events" edge to Event entities by IDs. +func (uuo *UserUpdateOne) RemoveEventIDs(ids ...string) *UserUpdateOne { + uuo.mutation.RemoveEventIDs(ids...) + return uuo +} + +// RemoveEvents removes "events" edges to Event entities. +func (uuo *UserUpdateOne) RemoveEvents(e ...*Event) *UserUpdateOne { + ids := make([]string, len(e)) + for i := range e { + ids[i] = e[i].ID + } + return uuo.RemoveEventIDs(ids...) +} + +// Where appends a list predicates to the UserUpdate builder. +func (uuo *UserUpdateOne) Where(ps ...predicate.User) *UserUpdateOne { + uuo.mutation.Where(ps...) + return uuo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (uuo *UserUpdateOne) Select(field string, fields ...string) *UserUpdateOne { + uuo.fields = append([]string{field}, fields...) + return uuo +} + +// Save executes the query and returns the updated User entity. +func (uuo *UserUpdateOne) Save(ctx context.Context) (*User, error) { + return withHooks(ctx, uuo.sqlSave, uuo.mutation, uuo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (uuo *UserUpdateOne) SaveX(ctx context.Context) *User { + node, err := uuo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (uuo *UserUpdateOne) Exec(ctx context.Context) error { + _, err := uuo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (uuo *UserUpdateOne) ExecX(ctx context.Context) { + if err := uuo.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (uuo *UserUpdateOne) check() error { + if v, ok := uuo.mutation.Name(); ok { + if err := user.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "User.name": %w`, err)} + } + } + if v, ok := uuo.mutation.Credential(); ok { + if err := user.CredentialValidator(v); err != nil { + return &ValidationError{Name: "credential", err: fmt.Errorf(`ent: validator failed for field "User.credential": %w`, err)} + } + } + return nil +} + +func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) { + if err := uuo.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(user.Table, user.Columns, sqlgraph.NewFieldSpec(user.FieldID, field.TypeString)) + id, ok := uuo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "User.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := uuo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, user.FieldID) + for _, f := range fields { + if !user.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != user.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := uuo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := uuo.mutation.Name(); ok { + _spec.SetField(user.FieldName, field.TypeString, value) + } + if value, ok := uuo.mutation.Credential(); ok { + _spec.SetField(user.FieldCredential, field.TypeString, value) + } + if value, ok := uuo.mutation.Attributes(); ok { + _spec.SetField(user.FieldAttributes, field.TypeJSON, value) + } + if uuo.mutation.AttributesCleared() { + _spec.ClearField(user.FieldAttributes, field.TypeJSON) + } + if uuo.mutation.EventsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: user.EventsTable, + Columns: []string{user.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uuo.mutation.RemovedEventsIDs(); len(nodes) > 0 && !uuo.mutation.EventsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: user.EventsTable, + Columns: []string{user.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uuo.mutation.EventsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: user.EventsTable, + Columns: []string{user.EventsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(event.FieldID, field.TypeString), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &User{config: uuo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, uuo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{user.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + uuo.mutation.done = true + return _node, nil +} diff --git a/internal/exprutils/functions.go b/internal/exprutils/functions.go index c7e3823..937674e 100644 --- a/internal/exprutils/functions.go +++ b/internal/exprutils/functions.go @@ -4,12 +4,11 @@ import ( "errors" ) -type ExprFunction struct { -} +type ExprFunction struct{} -// Public methods here will be available in the expression environment. Return type must be interface{} and error. +// Public methods here will be available in the expression environment. Return type must be any and error. -func (e ExprFunction) FlattenDropTickets(dropRecruitTickets interface{}) (interface{}, error) { +func (e ExprFunction) FlattenDropTickets(dropRecruitTickets any) (any, error) { if dropRecruitTickets == nil { return nil, nil } @@ -19,7 +18,7 @@ func (e ExprFunction) FlattenDropTickets(dropRecruitTickets interface{}) (interf return nil, err } - elements := make([]interface{}, 0) + elements := make([]any, 0) for _, el := range ticketsArray { for _, s := range el { elements = append(elements, s) @@ -28,13 +27,13 @@ func (e ExprFunction) FlattenDropTickets(dropRecruitTickets interface{}) (interf return elements, nil } -func (e ExprFunction) MapTotemArrayToValues(totemArray interface{}) (interface{}, error) { +func (e ExprFunction) MapTotemArrayToValues(totemArray any) (any, error) { if totemArray == nil { return nil, nil } - results := make([]interface{}, 0) - for _, totemInterface := range totemArray.([]interface{}) { + results := make([]any, 0) + for _, totemInterface := range totemArray.([]any) { totem := totemInterface.(string) lastChar := totem[len(totem)-1:] var value int @@ -50,30 +49,30 @@ func (e ExprFunction) MapTotemArrayToValues(totemArray interface{}) (interface{} return results, nil } -func (e ExprFunction) MapTotemArrayToColors(totemArray interface{}) (interface{}, error) { +func (e ExprFunction) MapTotemArrayToColors(totemArray any) (any, error) { if totemArray == nil { return nil, nil } - results := make([]interface{}, 0) - for _, totemInterface := range totemArray.([]interface{}) { + results := make([]any, 0) + for _, totemInterface := range totemArray.([]any) { totem := totemInterface.(string) results = append(results, totem[len(totem)-4:len(totem)-3]) } return results, nil } -func (e ExprFunction) MapRecruitTicketsToOperatorClasses(dropRecruitTickets interface{}) (interface{}, error) { +func (e ExprFunction) MapRecruitTicketsToOperatorClasses(dropRecruitTickets any) (any, error) { if dropRecruitTickets == nil { return nil, nil } mapping := GetExprCommonData().GetRecruitTicketOperatorClassMap() - classes := make([]interface{}, 0) - slice, _ := dropRecruitTickets.([]interface{}) + classes := make([]any, 0) + slice, _ := dropRecruitTickets.([]any) for _, ticketsForOneDropBox := range slice { - classSet := make(map[string]interface{}) - innerSlice, _ := ticketsForOneDropBox.([]interface{}) + classSet := make(map[string]any) + innerSlice, _ := ticketsForOneDropBox.([]any) for _, ticket := range innerSlice { classNames := mapping[ticket.(string)] for _, className := range classNames { @@ -87,7 +86,7 @@ func (e ExprFunction) MapRecruitTicketsToOperatorClasses(dropRecruitTickets inte return classes, nil } -func (e ExprFunction) MapIncidentTypeToName(incidentType interface{}) (interface{}, error) { +func (e ExprFunction) MapIncidentTypeToName(incidentType any) (any, error) { if incidentType == nil { return nil, nil } @@ -95,19 +94,19 @@ func (e ExprFunction) MapIncidentTypeToName(incidentType interface{}) (interface return mapping[incidentType.(string)], nil } -func (e ExprFunction) MapRestChoicesToNames(restChoices interface{}) (interface{}, error) { +func (e ExprFunction) MapRestChoicesToNames(restChoices any) (any, error) { if restChoices == nil { return nil, nil } mapping := GetExprCommonData().GetRestChoicesNameMap() - results := make([]interface{}, 0) - for _, choice := range restChoices.([]interface{}) { + results := make([]any, 0) + for _, choice := range restChoices.([]any) { results = append(results, mapping[choice.(string)]) } return results, nil } -func (e ExprFunction) MapVariationToName(variation interface{}) (interface{}, error) { +func (e ExprFunction) MapVariationToName(variation any) (any, error) { if variation == nil { return nil, nil } @@ -115,12 +114,12 @@ func (e ExprFunction) MapVariationToName(variation interface{}) (interface{}, er return mapping[variation.(string)], nil } -func convertToSliceOfSliceString(input interface{}) ([][]string, error) { +func convertToSliceOfSliceString(input any) ([][]string, error) { result := [][]string{} - if slice, ok := input.([]interface{}); ok { + if slice, ok := input.([]any); ok { result = make([][]string, len(slice)) for i, v := range slice { - if innerSlice, ok := v.([]interface{}); ok { + if innerSlice, ok := v.([]any); ok { result[i] = make([]string, len(innerSlice)) for j, s := range innerSlice { if str, ok := s.(string); ok { diff --git a/internal/exprutils/runner.go b/internal/exprutils/runner.go index 81b24ad..8eba520 100644 --- a/internal/exprutils/runner.go +++ b/internal/exprutils/runner.go @@ -7,21 +7,23 @@ import ( "github.com/antonmedv/expr" "github.com/antonmedv/expr/vm" - "exusiai.dev/roguestats-backend/internal/model" + "exusiai.dev/roguestats-backend/internal/ent" ) type ExprRunner struct { - methodEnv map[string]interface{} + methodEnv map[string]any v vm.VM } -var exprRunnerInstance *ExprRunner -var exprRunnerOnce sync.Once +var ( + exprRunnerInstance *ExprRunner + exprRunnerOnce sync.Once +) func GetExprRunner() *ExprRunner { exprRunnerOnce.Do(func() { methods := getMethods(reflect.TypeOf(ExprFunction{})) - methodEnv := make(map[string]interface{}) + methodEnv := make(map[string]any) exprFunction := ExprFunction{} for _, method := range methods { methodEnv[method] = reflect.ValueOf(exprFunction).MethodByName(method).Interface() @@ -34,8 +36,8 @@ func GetExprRunner() *ExprRunner { return exprRunnerInstance } -func (e ExprRunner) PrepareEnv(event *model.Event) map[string]interface{} { - env := map[string]interface{}{ +func (e ExprRunner) PrepareEnv(event *ent.Event) map[string]any { + env := map[string]any{ "content": event.Content, } for k, v := range e.methodEnv { @@ -44,8 +46,8 @@ func (e ExprRunner) PrepareEnv(event *model.Event) map[string]interface{} { return env } -func (e ExprRunner) RunCode(code string, env map[string]interface{}) (interface{}, error) { - program, err := expr.Compile(code, expr.Env(env)) +func (e ExprRunner) RunCode(code string, env map[string]any) (any, error) { + program, err := expr.Compile(code) if err != nil { return nil, err } diff --git a/internal/graph/defs/schema.graphqls b/internal/graph/defs/schema.graphqls index 3fff433..048f189 100644 --- a/internal/graph/defs/schema.graphqls +++ b/internal/graph/defs/schema.graphqls @@ -1,54 +1,23 @@ -### Scalars ### - +""" +The builtin Map type +""" scalar Map + +""" +Define a Relay Cursor type: +https://relay.dev/graphql/connections.htm#sec-Cursor +""" +scalar Cursor scalar Time scalar Any -### Directives ### - -directive @admin on FIELD_DEFINITION -directive @private(userIdFieldName: String = "userId") on FIELD_DEFINITION - -### Interfaces ### - -interface Node { - id: ID! -} - -### Queries ### - -type User implements Node { - id: ID! @goTag(key: "bun", value: "user_id") - name: String! - email: String @private(userIdFieldName: "id") - attributes: Map -} - type Event implements Node { - id: ID! @goTag(key: "bun", value: "event_id") - researchId: ID! @goTag(key: "bun", value: "research_id") - content: Map! - userId: ID! @goTag(key: "bun", value: "user_id") + id: ID! createdAt: Time! - userAgent: String -} - -type Research implements Node { - id: ID! @goTag(key: "bun", value: "research_id") - name: String! - schema: Map! - event(input: ID!): Event! - @goTag(key: "bun", value: "-") - @goField(forceResolver: true) - events(first: Int = 10, after: ID): EventsConnection - @goTag(key: "bun", value: "-") - @goField(forceResolver: true) -} - -type Topic implements Node { - id: ID! @goTag(key: "bun", value: "topic_id") - filterInput: String! - resultMappingInput: String! + userAgent: String! + content: Map! + user: User + research: Research } type CategoryCount { @@ -67,43 +36,267 @@ input GroupCountInput { resultMappingInput: String! } -type EventsConnection { - edges: [EventsEdge!]! +""" +A connection to a list of items. +""" +type EventConnection { + """ + A list of edges. + """ + edges: [EventEdge!]! + """ + Information to aid in pagination. + """ pageInfo: PageInfo! + """ + Identifies the total count of items in the connection. + """ + totalCount: Int! } -type EventsEdge { +""" +An edge in a connection. +""" +type EventEdge { + """ + The item at the end of the edge. + """ node: Event! - cursor: ID! + """ + A cursor for use in pagination. + """ + cursor: Cursor! +} + +""" +Ordering options for Event connections +""" +input EventOrder { + """ + The ordering direction. + """ + direction: OrderDirection! = ASC + """ + The field by which to order Events. + """ + field: EventOrderField! +} + +""" +Properties by which Event connections can be ordered. +""" +enum EventOrderField { + ID + CREATED_AT +} + +""" +An object with an ID. +Follows the [Relay Global Object Identification Specification](https://relay.dev/graphql/objectidentification.htm) +""" +interface Node + @goModel(model: "exusiai.dev/roguestats-backend/internal/ent.Noder") { + """ + The id of the object. + """ + id: ID! } +""" +Possible directions in which to order a list of items when provided an `orderBy` argument. +""" +enum OrderDirection { + """ + Specifies an ascending order for a given `orderBy` argument. + """ + ASC + """ + Specifies a descending order for a given `orderBy` argument. + """ + DESC +} + +""" +Information about pagination in a connection. +https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo +""" type PageInfo { - hasNextPage: Boolean - hasPreviousPage: Boolean - startCursor: ID! - endCursor: ID! + """ + When paginating forwards, are there more items? + """ + hasNextPage: Boolean! + """ + When paginating backwards, are there more items? + """ + hasPreviousPage: Boolean! + """ + When paginating backwards, the cursor to continue. + """ + startCursor: Cursor + """ + When paginating forwards, the cursor to continue. + """ + endCursor: Cursor +} + +type Research implements Node { + id: ID! + name: String! + schema: Map! +} + +""" +A connection to a list of items. +""" +type ResearchConnection { + """ + A list of edges. + """ + edges: [ResearchEdge!]! + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + """ + Identifies the total count of items in the connection. + """ + totalCount: Int! +} + +""" +An edge in a connection. +""" +type ResearchEdge { + """ + The item at the end of the edge. + """ + node: Research! + """ + A cursor for use in pagination. + """ + cursor: Cursor! +} + +""" +Ordering options for Research connections +""" +input ResearchOrder { + """ + The ordering direction. + """ + direction: OrderDirection! = ASC + """ + The field by which to order Researches. + """ + field: ResearchOrderField! +} + +""" +Properties by which Research connections can be ordered. +""" +enum ResearchOrderField { + ID +} + +type User implements Node { + id: ID! + name: String! + email: String @private(userIdFieldName: "id") + attributes: Map @private(userIdFieldName: "id") } type Query { - me: User! - research(id: ID!): Research! - researches: [Research!]! - events(researchId: ID, first: Int = 10, after: ID): EventsConnection! + """ + Returns the current authenticated user. + If the user is not authenticated, this returns null. + """ + me: User + + """ + Fetches an object given its ID. + """ + node( + """ + ID of the object. + """ + id: ID! + ): Node + + """ + Lookup nodes by a list of IDs. + """ + nodes( + """ + The list of node IDs. + """ + ids: [ID!]! + ): [Node]! + groupCount(input: GroupCountInput!): GroupCountResult! -} -### Mutations ### + event(id: ID!): Event -input LoginInput { - email: String! - password: String! - turnstileResponse: String! + events( + """ + Returns the elements in the list that come after the specified cursor. + """ + after: Cursor + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Returns the elements in the list that come before the specified cursor. + """ + before: Cursor + + """ + Returns the last _n_ elements from the list. + """ + last: Int + + """ + Ordering options for Events returned from the connection. + """ + orderBy: EventOrder + ): EventConnection! + + research(id: ID!): Research + + researches( + """ + Returns the elements in the list that come after the specified cursor. + """ + after: Cursor + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Returns the elements in the list that come before the specified cursor. + """ + before: Cursor + + """ + Returns the last _n_ elements from the list. + """ + last: Int + + """ + Ordering options for Researches returned from the connection. + """ + orderBy: ResearchOrder + ): ResearchConnection! } -input NewEvent { +input CreateEventInput { + userAgent: String! content: Map! - researchId: String! - userAgent: String + researchID: ID! } input CreateUserInput { @@ -112,27 +305,26 @@ input CreateUserInput { attributes: Map } +input LoginInput { + email: String! + password: String! + turnstileResponse: String! +} + type Mutation { login(input: LoginInput!): User! - createEvent(input: NewEvent!): Event! + createEvent(input: CreateEventInput!): Event! createUser(input: CreateUserInput!): User! @admin } -### gqlgen Directives ### - +directive @goField( + forceResolver: Boolean + name: String +) on FIELD_DEFINITION | INPUT_FIELD_DEFINITION directive @goModel( model: String models: [String!] ) on OBJECT | INPUT_OBJECT | SCALAR | ENUM | INTERFACE | UNION - -directive @goField( - forceResolver: Boolean - name: String - omittable: Boolean -) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION - -directive @goTag( - key: String! - value: String -) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION +directive @admin on FIELD_DEFINITION +directive @private(userIdFieldName: String = "userId") on FIELD_DEFINITION diff --git a/internal/graph/generated.go b/internal/graph/generated.go index 9c03abd..aeb4510 100644 --- a/internal/graph/generated.go +++ b/internal/graph/generated.go @@ -13,6 +13,8 @@ import ( "sync/atomic" "time" + "entgo.io/contrib/entgql" + "exusiai.dev/roguestats-backend/internal/ent" "exusiai.dev/roguestats-backend/internal/model" "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/introspection" @@ -40,7 +42,6 @@ type Config struct { type ResolverRoot interface { Mutation() MutationResolver Query() QueryResolver - Research() ResearchResolver } type DirectiveRoot struct { @@ -55,20 +56,21 @@ type ComplexityRoot struct { } Event struct { - Content func(childComplexity int) int - CreatedAt func(childComplexity int) int - ID func(childComplexity int) int - ResearchID func(childComplexity int) int - UserAgent func(childComplexity int) int - UserID func(childComplexity int) int + Content func(childComplexity int) int + CreatedAt func(childComplexity int) int + ID func(childComplexity int) int + Research func(childComplexity int) int + User func(childComplexity int) int + UserAgent func(childComplexity int) int } - EventsConnection struct { - Edges func(childComplexity int) int - PageInfo func(childComplexity int) int + EventConnection struct { + Edges func(childComplexity int) int + PageInfo func(childComplexity int) int + TotalCount func(childComplexity int) int } - EventsEdge struct { + EventEdge struct { Cursor func(childComplexity int) int Node func(childComplexity int) int } @@ -79,7 +81,7 @@ type ComplexityRoot struct { } Mutation struct { - CreateEvent func(childComplexity int, input model.NewEvent) int + CreateEvent func(childComplexity int, input model.CreateEventInput) int CreateUser func(childComplexity int, input model.CreateUserInput) int Login func(childComplexity int, input model.LoginInput) int } @@ -92,25 +94,31 @@ type ComplexityRoot struct { } Query struct { - Events func(childComplexity int, researchID *string, first *int, after *string) int + Event func(childComplexity int, id string) int + Events func(childComplexity int, after *entgql.Cursor[string], first *int, before *entgql.Cursor[string], last *int, orderBy *ent.EventOrder) int GroupCount func(childComplexity int, input model.GroupCountInput) int Me func(childComplexity int) int + Node func(childComplexity int, id string) int + Nodes func(childComplexity int, ids []string) int Research func(childComplexity int, id string) int - Researches func(childComplexity int) int + Researches func(childComplexity int, after *entgql.Cursor[string], first *int, before *entgql.Cursor[string], last *int, orderBy *ent.ResearchOrder) int } Research struct { - Event func(childComplexity int, input string) int - Events func(childComplexity int, first *int, after *string) int ID func(childComplexity int) int Name func(childComplexity int) int Schema func(childComplexity int) int } - Topic struct { - FilterInput func(childComplexity int) int - ID func(childComplexity int) int - ResultMappingInput func(childComplexity int) int + ResearchConnection struct { + Edges func(childComplexity int) int + PageInfo func(childComplexity int) int + TotalCount func(childComplexity int) int + } + + ResearchEdge struct { + Cursor func(childComplexity int) int + Node func(childComplexity int) int } User struct { @@ -122,20 +130,19 @@ type ComplexityRoot struct { } type MutationResolver interface { - Login(ctx context.Context, input model.LoginInput) (*model.User, error) - CreateEvent(ctx context.Context, input model.NewEvent) (*model.Event, error) - CreateUser(ctx context.Context, input model.CreateUserInput) (*model.User, error) + Login(ctx context.Context, input model.LoginInput) (*ent.User, error) + CreateEvent(ctx context.Context, input model.CreateEventInput) (*ent.Event, error) + CreateUser(ctx context.Context, input model.CreateUserInput) (*ent.User, error) } type QueryResolver interface { - Me(ctx context.Context) (*model.User, error) - Research(ctx context.Context, id string) (*model.Research, error) - Researches(ctx context.Context) ([]*model.Research, error) - Events(ctx context.Context, researchID *string, first *int, after *string) (*model.EventsConnection, error) + Me(ctx context.Context) (*ent.User, error) + Node(ctx context.Context, id string) (ent.Noder, error) + Nodes(ctx context.Context, ids []string) ([]ent.Noder, error) GroupCount(ctx context.Context, input model.GroupCountInput) (*model.GroupCountResult, error) -} -type ResearchResolver interface { - Event(ctx context.Context, obj *model.Research, input string) (*model.Event, error) - Events(ctx context.Context, obj *model.Research, first *int, after *string) (*model.EventsConnection, error) + Event(ctx context.Context, id string) (*ent.Event, error) + Events(ctx context.Context, after *entgql.Cursor[string], first *int, before *entgql.Cursor[string], last *int, orderBy *ent.EventOrder) (*ent.EventConnection, error) + Research(ctx context.Context, id string) (*ent.Research, error) + Researches(ctx context.Context, after *entgql.Cursor[string], first *int, before *entgql.Cursor[string], last *int, orderBy *ent.ResearchOrder) (*ent.ResearchConnection, error) } type executableSchema struct { @@ -188,12 +195,19 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Event.ID(childComplexity), true - case "Event.researchId": - if e.complexity.Event.ResearchID == nil { + case "Event.research": + if e.complexity.Event.Research == nil { + break + } + + return e.complexity.Event.Research(childComplexity), true + + case "Event.user": + if e.complexity.Event.User == nil { break } - return e.complexity.Event.ResearchID(childComplexity), true + return e.complexity.Event.User(childComplexity), true case "Event.userAgent": if e.complexity.Event.UserAgent == nil { @@ -202,40 +216,40 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Event.UserAgent(childComplexity), true - case "Event.userId": - if e.complexity.Event.UserID == nil { + case "EventConnection.edges": + if e.complexity.EventConnection.Edges == nil { break } - return e.complexity.Event.UserID(childComplexity), true + return e.complexity.EventConnection.Edges(childComplexity), true - case "EventsConnection.edges": - if e.complexity.EventsConnection.Edges == nil { + case "EventConnection.pageInfo": + if e.complexity.EventConnection.PageInfo == nil { break } - return e.complexity.EventsConnection.Edges(childComplexity), true + return e.complexity.EventConnection.PageInfo(childComplexity), true - case "EventsConnection.pageInfo": - if e.complexity.EventsConnection.PageInfo == nil { + case "EventConnection.totalCount": + if e.complexity.EventConnection.TotalCount == nil { break } - return e.complexity.EventsConnection.PageInfo(childComplexity), true + return e.complexity.EventConnection.TotalCount(childComplexity), true - case "EventsEdge.cursor": - if e.complexity.EventsEdge.Cursor == nil { + case "EventEdge.cursor": + if e.complexity.EventEdge.Cursor == nil { break } - return e.complexity.EventsEdge.Cursor(childComplexity), true + return e.complexity.EventEdge.Cursor(childComplexity), true - case "EventsEdge.node": - if e.complexity.EventsEdge.Node == nil { + case "EventEdge.node": + if e.complexity.EventEdge.Node == nil { break } - return e.complexity.EventsEdge.Node(childComplexity), true + return e.complexity.EventEdge.Node(childComplexity), true case "GroupCountResult.results": if e.complexity.GroupCountResult.Results == nil { @@ -261,7 +275,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Mutation.CreateEvent(childComplexity, args["input"].(model.NewEvent)), true + return e.complexity.Mutation.CreateEvent(childComplexity, args["input"].(model.CreateEventInput)), true case "Mutation.createUser": if e.complexity.Mutation.CreateUser == nil { @@ -315,6 +329,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.PageInfo.StartCursor(childComplexity), true + case "Query.event": + if e.complexity.Query.Event == nil { + break + } + + args, err := ec.field_Query_event_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Event(childComplexity, args["id"].(string)), true + case "Query.events": if e.complexity.Query.Events == nil { break @@ -325,7 +351,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Query.Events(childComplexity, args["researchId"].(*string), args["first"].(*int), args["after"].(*string)), true + return e.complexity.Query.Events(childComplexity, args["after"].(*entgql.Cursor[string]), args["first"].(*int), args["before"].(*entgql.Cursor[string]), args["last"].(*int), args["orderBy"].(*ent.EventOrder)), true case "Query.groupCount": if e.complexity.Query.GroupCount == nil { @@ -346,48 +372,53 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.Me(childComplexity), true - case "Query.research": - if e.complexity.Query.Research == nil { + case "Query.node": + if e.complexity.Query.Node == nil { break } - args, err := ec.field_Query_research_args(context.TODO(), rawArgs) + args, err := ec.field_Query_node_args(context.TODO(), rawArgs) if err != nil { return 0, false } - return e.complexity.Query.Research(childComplexity, args["id"].(string)), true + return e.complexity.Query.Node(childComplexity, args["id"].(string)), true - case "Query.researches": - if e.complexity.Query.Researches == nil { + case "Query.nodes": + if e.complexity.Query.Nodes == nil { break } - return e.complexity.Query.Researches(childComplexity), true + args, err := ec.field_Query_nodes_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Nodes(childComplexity, args["ids"].([]string)), true - case "Research.event": - if e.complexity.Research.Event == nil { + case "Query.research": + if e.complexity.Query.Research == nil { break } - args, err := ec.field_Research_event_args(context.TODO(), rawArgs) + args, err := ec.field_Query_research_args(context.TODO(), rawArgs) if err != nil { return 0, false } - return e.complexity.Research.Event(childComplexity, args["input"].(string)), true + return e.complexity.Query.Research(childComplexity, args["id"].(string)), true - case "Research.events": - if e.complexity.Research.Events == nil { + case "Query.researches": + if e.complexity.Query.Researches == nil { break } - args, err := ec.field_Research_events_args(context.TODO(), rawArgs) + args, err := ec.field_Query_researches_args(context.TODO(), rawArgs) if err != nil { return 0, false } - return e.complexity.Research.Events(childComplexity, args["first"].(*int), args["after"].(*string)), true + return e.complexity.Query.Researches(childComplexity, args["after"].(*entgql.Cursor[string]), args["first"].(*int), args["before"].(*entgql.Cursor[string]), args["last"].(*int), args["orderBy"].(*ent.ResearchOrder)), true case "Research.id": if e.complexity.Research.ID == nil { @@ -410,26 +441,40 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Research.Schema(childComplexity), true - case "Topic.filterInput": - if e.complexity.Topic.FilterInput == nil { + case "ResearchConnection.edges": + if e.complexity.ResearchConnection.Edges == nil { + break + } + + return e.complexity.ResearchConnection.Edges(childComplexity), true + + case "ResearchConnection.pageInfo": + if e.complexity.ResearchConnection.PageInfo == nil { + break + } + + return e.complexity.ResearchConnection.PageInfo(childComplexity), true + + case "ResearchConnection.totalCount": + if e.complexity.ResearchConnection.TotalCount == nil { break } - return e.complexity.Topic.FilterInput(childComplexity), true + return e.complexity.ResearchConnection.TotalCount(childComplexity), true - case "Topic.id": - if e.complexity.Topic.ID == nil { + case "ResearchEdge.cursor": + if e.complexity.ResearchEdge.Cursor == nil { break } - return e.complexity.Topic.ID(childComplexity), true + return e.complexity.ResearchEdge.Cursor(childComplexity), true - case "Topic.resultMappingInput": - if e.complexity.Topic.ResultMappingInput == nil { + case "ResearchEdge.node": + if e.complexity.ResearchEdge.Node == nil { break } - return e.complexity.Topic.ResultMappingInput(childComplexity), true + return e.complexity.ResearchEdge.Node(childComplexity), true case "User.attributes": if e.complexity.User.Attributes == nil { @@ -467,10 +512,12 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { rc := graphql.GetOperationContext(ctx) ec := executionContext{rc, e, 0, 0, make(chan graphql.DeferredResult)} inputUnmarshalMap := graphql.BuildUnmarshalerMap( + ec.unmarshalInputCreateEventInput, ec.unmarshalInputCreateUserInput, + ec.unmarshalInputEventOrder, ec.unmarshalInputGroupCountInput, ec.unmarshalInputLoginInput, - ec.unmarshalInputNewEvent, + ec.unmarshalInputResearchOrder, ) first := true @@ -605,10 +652,10 @@ func (ec *executionContext) dir_private_args(ctx context.Context, rawArgs map[st func (ec *executionContext) field_Mutation_createEvent_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 model.NewEvent + var arg0 model.CreateEventInput if tmp, ok := rawArgs["input"]; ok { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) - arg0, err = ec.unmarshalNNewEvent2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐNewEvent(ctx, tmp) + arg0, err = ec.unmarshalNCreateEventInput2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐCreateEventInput(ctx, tmp) if err != nil { return nil, err } @@ -662,18 +709,33 @@ func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs return args, nil } +func (ec *executionContext) field_Query_event_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + func (ec *executionContext) field_Query_events_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *string - if tmp, ok := rawArgs["researchId"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("researchId")) - arg0, err = ec.unmarshalOID2ᚖstring(ctx, tmp) + var arg0 *entgql.Cursor[string] + if tmp, ok := rawArgs["after"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) + arg0, err = ec.unmarshalOCursor2ᚖentgoᚗioᚋcontribᚋentgqlᚐCursor(ctx, tmp) if err != nil { return nil, err } } - args["researchId"] = arg0 + args["after"] = arg0 var arg1 *int if tmp, ok := rawArgs["first"]; ok { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) @@ -683,15 +745,33 @@ func (ec *executionContext) field_Query_events_args(ctx context.Context, rawArgs } } args["first"] = arg1 - var arg2 *string - if tmp, ok := rawArgs["after"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) - arg2, err = ec.unmarshalOID2ᚖstring(ctx, tmp) + var arg2 *entgql.Cursor[string] + if tmp, ok := rawArgs["before"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("before")) + arg2, err = ec.unmarshalOCursor2ᚖentgoᚗioᚋcontribᚋentgqlᚐCursor(ctx, tmp) + if err != nil { + return nil, err + } + } + args["before"] = arg2 + var arg3 *int + if tmp, ok := rawArgs["last"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("last")) + arg3, err = ec.unmarshalOInt2ᚖint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["last"] = arg3 + var arg4 *ent.EventOrder + if tmp, ok := rawArgs["orderBy"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("orderBy")) + arg4, err = ec.unmarshalOEventOrder2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventOrder(ctx, tmp) if err != nil { return nil, err } } - args["after"] = arg2 + args["orderBy"] = arg4 return args, nil } @@ -710,7 +790,7 @@ func (ec *executionContext) field_Query_groupCount_args(ctx context.Context, raw return args, nil } -func (ec *executionContext) field_Query_research_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Query_node_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} var arg0 string @@ -725,42 +805,84 @@ func (ec *executionContext) field_Query_research_args(ctx context.Context, rawAr return args, nil } -func (ec *executionContext) field_Research_event_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Query_nodes_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 []string + if tmp, ok := rawArgs["ids"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ids")) + arg0, err = ec.unmarshalNID2ᚕstringᚄ(ctx, tmp) + if err != nil { + return nil, err + } + } + args["ids"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_research_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} var arg0 string - if tmp, ok := rawArgs["input"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) arg0, err = ec.unmarshalNID2string(ctx, tmp) if err != nil { return nil, err } } - args["input"] = arg0 + args["id"] = arg0 return args, nil } -func (ec *executionContext) field_Research_events_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Query_researches_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *int + var arg0 *entgql.Cursor[string] + if tmp, ok := rawArgs["after"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) + arg0, err = ec.unmarshalOCursor2ᚖentgoᚗioᚋcontribᚋentgqlᚐCursor(ctx, tmp) + if err != nil { + return nil, err + } + } + args["after"] = arg0 + var arg1 *int if tmp, ok := rawArgs["first"]; ok { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) - arg0, err = ec.unmarshalOInt2ᚖint(ctx, tmp) + arg1, err = ec.unmarshalOInt2ᚖint(ctx, tmp) if err != nil { return nil, err } } - args["first"] = arg0 - var arg1 *string - if tmp, ok := rawArgs["after"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) - arg1, err = ec.unmarshalOID2ᚖstring(ctx, tmp) + args["first"] = arg1 + var arg2 *entgql.Cursor[string] + if tmp, ok := rawArgs["before"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("before")) + arg2, err = ec.unmarshalOCursor2ᚖentgoᚗioᚋcontribᚋentgqlᚐCursor(ctx, tmp) + if err != nil { + return nil, err + } + } + args["before"] = arg2 + var arg3 *int + if tmp, ok := rawArgs["last"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("last")) + arg3, err = ec.unmarshalOInt2ᚖint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["last"] = arg3 + var arg4 *ent.ResearchOrder + if tmp, ok := rawArgs["orderBy"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("orderBy")) + arg4, err = ec.unmarshalOResearchOrder2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchOrder(ctx, tmp) if err != nil { return nil, err } } - args["after"] = arg1 + args["orderBy"] = arg4 return args, nil } @@ -890,7 +1012,7 @@ func (ec *executionContext) fieldContext_CategoryCount_count(ctx context.Context return fc, nil } -func (ec *executionContext) _Event_id(ctx context.Context, field graphql.CollectedField, obj *model.Event) (ret graphql.Marshaler) { +func (ec *executionContext) _Event_id(ctx context.Context, field graphql.CollectedField, obj *ent.Event) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Event_id(ctx, field) if err != nil { return graphql.Null @@ -934,8 +1056,8 @@ func (ec *executionContext) fieldContext_Event_id(ctx context.Context, field gra return fc, nil } -func (ec *executionContext) _Event_researchId(ctx context.Context, field graphql.CollectedField, obj *model.Event) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Event_researchId(ctx, field) +func (ec *executionContext) _Event_createdAt(ctx context.Context, field graphql.CollectedField, obj *ent.Event) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Event_createdAt(ctx, field) if err != nil { return graphql.Null } @@ -948,7 +1070,7 @@ func (ec *executionContext) _Event_researchId(ctx context.Context, field graphql }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.ResearchID, nil + return obj.CreatedAt, nil }) if err != nil { ec.Error(ctx, err) @@ -960,26 +1082,26 @@ func (ec *executionContext) _Event_researchId(ctx context.Context, field graphql } return graphql.Null } - res := resTmp.(string) + res := resTmp.(time.Time) fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Event_researchId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Event_createdAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Event", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } -func (ec *executionContext) _Event_content(ctx context.Context, field graphql.CollectedField, obj *model.Event) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Event_content(ctx, field) +func (ec *executionContext) _Event_userAgent(ctx context.Context, field graphql.CollectedField, obj *ent.Event) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Event_userAgent(ctx, field) if err != nil { return graphql.Null } @@ -992,7 +1114,7 @@ func (ec *executionContext) _Event_content(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Content, nil + return obj.UserAgent, nil }) if err != nil { ec.Error(ctx, err) @@ -1004,26 +1126,26 @@ func (ec *executionContext) _Event_content(ctx context.Context, field graphql.Co } return graphql.Null } - res := resTmp.(map[string]interface{}) + res := resTmp.(string) fc.Result = res - return ec.marshalNMap2map(ctx, field.Selections, res) + return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Event_content(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Event_userAgent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Event", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Map does not have child fields") + return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } -func (ec *executionContext) _Event_userId(ctx context.Context, field graphql.CollectedField, obj *model.Event) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Event_userId(ctx, field) +func (ec *executionContext) _Event_content(ctx context.Context, field graphql.CollectedField, obj *ent.Event) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Event_content(ctx, field) if err != nil { return graphql.Null } @@ -1036,7 +1158,7 @@ func (ec *executionContext) _Event_userId(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.UserID, nil + return obj.Content, nil }) if err != nil { ec.Error(ctx, err) @@ -1048,26 +1170,26 @@ func (ec *executionContext) _Event_userId(ctx context.Context, field graphql.Col } return graphql.Null } - res := resTmp.(string) + res := resTmp.(map[string]interface{}) fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) + return ec.marshalNMap2map(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Event_userId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Event_content(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Event", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + return nil, errors.New("field of type Map does not have child fields") }, } return fc, nil } -func (ec *executionContext) _Event_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.Event) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Event_createdAt(ctx, field) +func (ec *executionContext) _Event_user(ctx context.Context, field graphql.CollectedField, obj *ent.Event) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Event_user(ctx, field) if err != nil { return graphql.Null } @@ -1080,38 +1202,45 @@ func (ec *executionContext) _Event_createdAt(ctx context.Context, field graphql. }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.CreatedAt, nil + return obj.User(ctx) }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(time.Time) + res := resTmp.(*ent.User) fc.Result = res - return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) + return ec.marshalOUser2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐUser(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Event_createdAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Event_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Event", Field: field, - IsMethod: false, + IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Time does not have child fields") + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "name": + return ec.fieldContext_User_name(ctx, field) + case "email": + return ec.fieldContext_User_email(ctx, field) + case "attributes": + return ec.fieldContext_User_attributes(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil } -func (ec *executionContext) _Event_userAgent(ctx context.Context, field graphql.CollectedField, obj *model.Event) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Event_userAgent(ctx, field) +func (ec *executionContext) _Event_research(ctx context.Context, field graphql.CollectedField, obj *ent.Event) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Event_research(ctx, field) if err != nil { return graphql.Null } @@ -1124,7 +1253,7 @@ func (ec *executionContext) _Event_userAgent(ctx context.Context, field graphql. }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.UserAgent, nil + return obj.Research(ctx) }) if err != nil { ec.Error(ctx, err) @@ -1133,26 +1262,34 @@ func (ec *executionContext) _Event_userAgent(ctx context.Context, field graphql. if resTmp == nil { return graphql.Null } - res := resTmp.(*string) + res := resTmp.(*ent.Research) fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) + return ec.marshalOResearch2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearch(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Event_userAgent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Event_research(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Event", Field: field, - IsMethod: false, + IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + switch field.Name { + case "id": + return ec.fieldContext_Research_id(ctx, field) + case "name": + return ec.fieldContext_Research_name(ctx, field) + case "schema": + return ec.fieldContext_Research_schema(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Research", field.Name) }, } return fc, nil } -func (ec *executionContext) _EventsConnection_edges(ctx context.Context, field graphql.CollectedField, obj *model.EventsConnection) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_EventsConnection_edges(ctx, field) +func (ec *executionContext) _EventConnection_edges(ctx context.Context, field graphql.CollectedField, obj *ent.EventConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_EventConnection_edges(ctx, field) if err != nil { return graphql.Null } @@ -1177,32 +1314,32 @@ func (ec *executionContext) _EventsConnection_edges(ctx context.Context, field g } return graphql.Null } - res := resTmp.([]*model.EventsEdge) + res := resTmp.([]*ent.EventEdge) fc.Result = res - return ec.marshalNEventsEdge2ᚕᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEventsEdgeᚄ(ctx, field.Selections, res) + return ec.marshalNEventEdge2ᚕᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventEdgeᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EventsConnection_edges(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EventConnection_edges(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "EventsConnection", + Object: "EventConnection", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "node": - return ec.fieldContext_EventsEdge_node(ctx, field) + return ec.fieldContext_EventEdge_node(ctx, field) case "cursor": - return ec.fieldContext_EventsEdge_cursor(ctx, field) + return ec.fieldContext_EventEdge_cursor(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type EventsEdge", field.Name) + return nil, fmt.Errorf("no field named %q was found under type EventEdge", field.Name) }, } return fc, nil } -func (ec *executionContext) _EventsConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *model.EventsConnection) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_EventsConnection_pageInfo(ctx, field) +func (ec *executionContext) _EventConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *ent.EventConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_EventConnection_pageInfo(ctx, field) if err != nil { return graphql.Null } @@ -1227,14 +1364,14 @@ func (ec *executionContext) _EventsConnection_pageInfo(ctx context.Context, fiel } return graphql.Null } - res := resTmp.(*model.PageInfo) + res := resTmp.(entgql.PageInfo[string]) fc.Result = res - return ec.marshalNPageInfo2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐPageInfo(ctx, field.Selections, res) + return ec.marshalNPageInfo2entgoᚗioᚋcontribᚋentgqlᚐPageInfo(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EventsConnection_pageInfo(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EventConnection_pageInfo(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "EventsConnection", + Object: "EventConnection", Field: field, IsMethod: false, IsResolver: false, @@ -1255,8 +1392,52 @@ func (ec *executionContext) fieldContext_EventsConnection_pageInfo(ctx context.C return fc, nil } -func (ec *executionContext) _EventsEdge_node(ctx context.Context, field graphql.CollectedField, obj *model.EventsEdge) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_EventsEdge_node(ctx, field) +func (ec *executionContext) _EventConnection_totalCount(ctx context.Context, field graphql.CollectedField, obj *ent.EventConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_EventConnection_totalCount(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.TotalCount, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_EventConnection_totalCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "EventConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _EventEdge_node(ctx context.Context, field graphql.CollectedField, obj *ent.EventEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_EventEdge_node(ctx, field) if err != nil { return graphql.Null } @@ -1281,14 +1462,14 @@ func (ec *executionContext) _EventsEdge_node(ctx context.Context, field graphql. } return graphql.Null } - res := resTmp.(*model.Event) + res := resTmp.(*ent.Event) fc.Result = res - return ec.marshalNEvent2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEvent(ctx, field.Selections, res) + return ec.marshalNEvent2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEvent(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EventsEdge_node(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EventEdge_node(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "EventsEdge", + Object: "EventEdge", Field: field, IsMethod: false, IsResolver: false, @@ -1296,16 +1477,16 @@ func (ec *executionContext) fieldContext_EventsEdge_node(ctx context.Context, fi switch field.Name { case "id": return ec.fieldContext_Event_id(ctx, field) - case "researchId": - return ec.fieldContext_Event_researchId(ctx, field) - case "content": - return ec.fieldContext_Event_content(ctx, field) - case "userId": - return ec.fieldContext_Event_userId(ctx, field) case "createdAt": return ec.fieldContext_Event_createdAt(ctx, field) case "userAgent": return ec.fieldContext_Event_userAgent(ctx, field) + case "content": + return ec.fieldContext_Event_content(ctx, field) + case "user": + return ec.fieldContext_Event_user(ctx, field) + case "research": + return ec.fieldContext_Event_research(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Event", field.Name) }, @@ -1313,8 +1494,8 @@ func (ec *executionContext) fieldContext_EventsEdge_node(ctx context.Context, fi return fc, nil } -func (ec *executionContext) _EventsEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *model.EventsEdge) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_EventsEdge_cursor(ctx, field) +func (ec *executionContext) _EventEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *ent.EventEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_EventEdge_cursor(ctx, field) if err != nil { return graphql.Null } @@ -1339,19 +1520,19 @@ func (ec *executionContext) _EventsEdge_cursor(ctx context.Context, field graphq } return graphql.Null } - res := resTmp.(string) + res := resTmp.(entgql.Cursor[string]) fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) + return ec.marshalNCursor2entgoᚗioᚋcontribᚋentgqlᚐCursor(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_EventsEdge_cursor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_EventEdge_cursor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "EventsEdge", + Object: "EventEdge", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + return nil, errors.New("field of type Cursor does not have child fields") }, } return fc, nil @@ -1477,9 +1658,9 @@ func (ec *executionContext) _Mutation_login(ctx context.Context, field graphql.C } return graphql.Null } - res := resTmp.(*model.User) + res := resTmp.(*ent.User) fc.Result = res - return ec.marshalNUser2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐUser(ctx, field.Selections, res) + return ec.marshalNUser2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐUser(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_login(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -1530,7 +1711,7 @@ func (ec *executionContext) _Mutation_createEvent(ctx context.Context, field gra }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().CreateEvent(rctx, fc.Args["input"].(model.NewEvent)) + return ec.resolvers.Mutation().CreateEvent(rctx, fc.Args["input"].(model.CreateEventInput)) }) if err != nil { ec.Error(ctx, err) @@ -1542,9 +1723,9 @@ func (ec *executionContext) _Mutation_createEvent(ctx context.Context, field gra } return graphql.Null } - res := resTmp.(*model.Event) + res := resTmp.(*ent.Event) fc.Result = res - return ec.marshalNEvent2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEvent(ctx, field.Selections, res) + return ec.marshalNEvent2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEvent(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_createEvent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -1557,16 +1738,16 @@ func (ec *executionContext) fieldContext_Mutation_createEvent(ctx context.Contex switch field.Name { case "id": return ec.fieldContext_Event_id(ctx, field) - case "researchId": - return ec.fieldContext_Event_researchId(ctx, field) - case "content": - return ec.fieldContext_Event_content(ctx, field) - case "userId": - return ec.fieldContext_Event_userId(ctx, field) case "createdAt": return ec.fieldContext_Event_createdAt(ctx, field) case "userAgent": return ec.fieldContext_Event_userAgent(ctx, field) + case "content": + return ec.fieldContext_Event_content(ctx, field) + case "user": + return ec.fieldContext_Event_user(ctx, field) + case "research": + return ec.fieldContext_Event_research(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Event", field.Name) }, @@ -1616,10 +1797,10 @@ func (ec *executionContext) _Mutation_createUser(ctx context.Context, field grap if tmp == nil { return nil, nil } - if data, ok := tmp.(*model.User); ok { + if data, ok := tmp.(*ent.User); ok { return data, nil } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *exusiai.dev/roguestats-backend/internal/model.User`, tmp) + return nil, fmt.Errorf(`unexpected type %T from directive, should be *exusiai.dev/roguestats-backend/internal/ent.User`, tmp) }) if err != nil { ec.Error(ctx, err) @@ -1631,9 +1812,9 @@ func (ec *executionContext) _Mutation_createUser(ctx context.Context, field grap } return graphql.Null } - res := resTmp.(*model.User) + res := resTmp.(*ent.User) fc.Result = res - return ec.marshalNUser2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐUser(ctx, field.Selections, res) + return ec.marshalNUser2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐUser(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_createUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -1670,7 +1851,7 @@ func (ec *executionContext) fieldContext_Mutation_createUser(ctx context.Context return fc, nil } -func (ec *executionContext) _PageInfo_hasNextPage(ctx context.Context, field graphql.CollectedField, obj *model.PageInfo) (ret graphql.Marshaler) { +func (ec *executionContext) _PageInfo_hasNextPage(ctx context.Context, field graphql.CollectedField, obj *entgql.PageInfo[string]) (ret graphql.Marshaler) { fc, err := ec.fieldContext_PageInfo_hasNextPage(ctx, field) if err != nil { return graphql.Null @@ -1691,11 +1872,14 @@ func (ec *executionContext) _PageInfo_hasNextPage(ctx context.Context, field gra return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*bool) + res := resTmp.(bool) fc.Result = res - return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) + return ec.marshalNBoolean2bool(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_PageInfo_hasNextPage(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -1711,7 +1895,7 @@ func (ec *executionContext) fieldContext_PageInfo_hasNextPage(ctx context.Contex return fc, nil } -func (ec *executionContext) _PageInfo_hasPreviousPage(ctx context.Context, field graphql.CollectedField, obj *model.PageInfo) (ret graphql.Marshaler) { +func (ec *executionContext) _PageInfo_hasPreviousPage(ctx context.Context, field graphql.CollectedField, obj *entgql.PageInfo[string]) (ret graphql.Marshaler) { fc, err := ec.fieldContext_PageInfo_hasPreviousPage(ctx, field) if err != nil { return graphql.Null @@ -1732,11 +1916,14 @@ func (ec *executionContext) _PageInfo_hasPreviousPage(ctx context.Context, field return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*bool) + res := resTmp.(bool) fc.Result = res - return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) + return ec.marshalNBoolean2bool(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_PageInfo_hasPreviousPage(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -1752,7 +1939,7 @@ func (ec *executionContext) fieldContext_PageInfo_hasPreviousPage(ctx context.Co return fc, nil } -func (ec *executionContext) _PageInfo_startCursor(ctx context.Context, field graphql.CollectedField, obj *model.PageInfo) (ret graphql.Marshaler) { +func (ec *executionContext) _PageInfo_startCursor(ctx context.Context, field graphql.CollectedField, obj *entgql.PageInfo[string]) (ret graphql.Marshaler) { fc, err := ec.fieldContext_PageInfo_startCursor(ctx, field) if err != nil { return graphql.Null @@ -1773,14 +1960,11 @@ func (ec *executionContext) _PageInfo_startCursor(ctx context.Context, field gra return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(string) + res := resTmp.(*entgql.Cursor[string]) fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) + return ec.marshalOCursor2ᚖentgoᚗioᚋcontribᚋentgqlᚐCursor(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_PageInfo_startCursor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -1790,13 +1974,13 @@ func (ec *executionContext) fieldContext_PageInfo_startCursor(ctx context.Contex IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + return nil, errors.New("field of type Cursor does not have child fields") }, } return fc, nil } -func (ec *executionContext) _PageInfo_endCursor(ctx context.Context, field graphql.CollectedField, obj *model.PageInfo) (ret graphql.Marshaler) { +func (ec *executionContext) _PageInfo_endCursor(ctx context.Context, field graphql.CollectedField, obj *entgql.PageInfo[string]) (ret graphql.Marshaler) { fc, err := ec.fieldContext_PageInfo_endCursor(ctx, field) if err != nil { return graphql.Null @@ -1817,14 +2001,11 @@ func (ec *executionContext) _PageInfo_endCursor(ctx context.Context, field graph return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(string) + res := resTmp.(*entgql.Cursor[string]) fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) + return ec.marshalOCursor2ᚖentgoᚗioᚋcontribᚋentgqlᚐCursor(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_PageInfo_endCursor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -1834,7 +2015,7 @@ func (ec *executionContext) fieldContext_PageInfo_endCursor(ctx context.Context, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + return nil, errors.New("field of type Cursor does not have child fields") }, } return fc, nil @@ -1861,14 +2042,11 @@ func (ec *executionContext) _Query_me(ctx context.Context, field graphql.Collect return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(*model.User) + res := resTmp.(*ent.User) fc.Result = res - return ec.marshalNUser2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐUser(ctx, field.Selections, res) + return ec.marshalOUser2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐUser(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Query_me(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -1894,8 +2072,8 @@ func (ec *executionContext) fieldContext_Query_me(ctx context.Context, field gra return fc, nil } -func (ec *executionContext) _Query_research(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_research(ctx, field) +func (ec *executionContext) _Query_node(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_node(ctx, field) if err != nil { return graphql.Null } @@ -1908,43 +2086,28 @@ func (ec *executionContext) _Query_research(ctx context.Context, field graphql.C }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Research(rctx, fc.Args["id"].(string)) + return ec.resolvers.Query().Node(rctx, fc.Args["id"].(string)) }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(*model.Research) + res := resTmp.(ent.Noder) fc.Result = res - return ec.marshalNResearch2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐResearch(ctx, field.Selections, res) + return ec.marshalONode2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐNoder(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query_research(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_node(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Research_id(ctx, field) - case "name": - return ec.fieldContext_Research_name(ctx, field) - case "schema": - return ec.fieldContext_Research_schema(ctx, field) - case "event": - return ec.fieldContext_Research_event(ctx, field) - case "events": - return ec.fieldContext_Research_events(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Research", field.Name) + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") }, } defer func() { @@ -1954,15 +2117,15 @@ func (ec *executionContext) fieldContext_Query_research(ctx context.Context, fie } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_research_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_node_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_researches(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_researches(ctx, field) +func (ec *executionContext) _Query_nodes(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_nodes(ctx, field) if err != nil { return graphql.Null } @@ -1975,7 +2138,7 @@ func (ec *executionContext) _Query_researches(ctx context.Context, field graphql }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Researches(rctx) + return ec.resolvers.Query().Nodes(rctx, fc.Args["ids"].([]string)) }) if err != nil { ec.Error(ctx, err) @@ -1987,12 +2150,125 @@ func (ec *executionContext) _Query_researches(ctx context.Context, field graphql } return graphql.Null } - res := resTmp.([]*model.Research) + res := resTmp.([]ent.Noder) fc.Result = res - return ec.marshalNResearch2ᚕᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐResearchᚄ(ctx, field.Selections, res) + return ec.marshalNNode2ᚕexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐNoder(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query_researches(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_nodes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_nodes_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_groupCount(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_groupCount(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().GroupCount(rctx, fc.Args["input"].(model.GroupCountInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.GroupCountResult) + fc.Result = res + return ec.marshalNGroupCountResult2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐGroupCountResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_groupCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "results": + return ec.fieldContext_GroupCountResult_results(ctx, field) + case "total": + return ec.fieldContext_GroupCountResult_total(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type GroupCountResult", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_groupCount_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_event(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_event(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Event(rctx, fc.Args["id"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*ent.Event) + fc.Result = res + return ec.marshalOEvent2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEvent(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_event(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, @@ -2001,19 +2277,32 @@ func (ec *executionContext) fieldContext_Query_researches(ctx context.Context, f Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": - return ec.fieldContext_Research_id(ctx, field) - case "name": - return ec.fieldContext_Research_name(ctx, field) - case "schema": - return ec.fieldContext_Research_schema(ctx, field) - case "event": - return ec.fieldContext_Research_event(ctx, field) - case "events": - return ec.fieldContext_Research_events(ctx, field) + return ec.fieldContext_Event_id(ctx, field) + case "createdAt": + return ec.fieldContext_Event_createdAt(ctx, field) + case "userAgent": + return ec.fieldContext_Event_userAgent(ctx, field) + case "content": + return ec.fieldContext_Event_content(ctx, field) + case "user": + return ec.fieldContext_Event_user(ctx, field) + case "research": + return ec.fieldContext_Event_research(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type Research", field.Name) + return nil, fmt.Errorf("no field named %q was found under type Event", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_event_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } @@ -2031,7 +2320,7 @@ func (ec *executionContext) _Query_events(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Events(rctx, fc.Args["researchId"].(*string), fc.Args["first"].(*int), fc.Args["after"].(*string)) + return ec.resolvers.Query().Events(rctx, fc.Args["after"].(*entgql.Cursor[string]), fc.Args["first"].(*int), fc.Args["before"].(*entgql.Cursor[string]), fc.Args["last"].(*int), fc.Args["orderBy"].(*ent.EventOrder)) }) if err != nil { ec.Error(ctx, err) @@ -2043,9 +2332,9 @@ func (ec *executionContext) _Query_events(ctx context.Context, field graphql.Col } return graphql.Null } - res := resTmp.(*model.EventsConnection) + res := resTmp.(*ent.EventConnection) fc.Result = res - return ec.marshalNEventsConnection2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEventsConnection(ctx, field.Selections, res) + return ec.marshalNEventConnection2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventConnection(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Query_events(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -2057,11 +2346,13 @@ func (ec *executionContext) fieldContext_Query_events(ctx context.Context, field Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "edges": - return ec.fieldContext_EventsConnection_edges(ctx, field) + return ec.fieldContext_EventConnection_edges(ctx, field) case "pageInfo": - return ec.fieldContext_EventsConnection_pageInfo(ctx, field) + return ec.fieldContext_EventConnection_pageInfo(ctx, field) + case "totalCount": + return ec.fieldContext_EventConnection_totalCount(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type EventsConnection", field.Name) + return nil, fmt.Errorf("no field named %q was found under type EventConnection", field.Name) }, } defer func() { @@ -2078,8 +2369,8 @@ func (ec *executionContext) fieldContext_Query_events(ctx context.Context, field return fc, nil } -func (ec *executionContext) _Query_groupCount(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_groupCount(ctx, field) +func (ec *executionContext) _Query_research(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_research(ctx, field) if err != nil { return graphql.Null } @@ -2092,7 +2383,67 @@ func (ec *executionContext) _Query_groupCount(ctx context.Context, field graphql }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().GroupCount(rctx, fc.Args["input"].(model.GroupCountInput)) + return ec.resolvers.Query().Research(rctx, fc.Args["id"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*ent.Research) + fc.Result = res + return ec.marshalOResearch2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearch(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_research(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Research_id(ctx, field) + case "name": + return ec.fieldContext_Research_name(ctx, field) + case "schema": + return ec.fieldContext_Research_schema(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Research", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_research_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_researches(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_researches(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Researches(rctx, fc.Args["after"].(*entgql.Cursor[string]), fc.Args["first"].(*int), fc.Args["before"].(*entgql.Cursor[string]), fc.Args["last"].(*int), fc.Args["orderBy"].(*ent.ResearchOrder)) }) if err != nil { ec.Error(ctx, err) @@ -2104,12 +2455,12 @@ func (ec *executionContext) _Query_groupCount(ctx context.Context, field graphql } return graphql.Null } - res := resTmp.(*model.GroupCountResult) + res := resTmp.(*ent.ResearchConnection) fc.Result = res - return ec.marshalNGroupCountResult2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐGroupCountResult(ctx, field.Selections, res) + return ec.marshalNResearchConnection2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchConnection(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query_groupCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_researches(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, @@ -2117,12 +2468,14 @@ func (ec *executionContext) fieldContext_Query_groupCount(ctx context.Context, f IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "results": - return ec.fieldContext_GroupCountResult_results(ctx, field) - case "total": - return ec.fieldContext_GroupCountResult_total(ctx, field) + case "edges": + return ec.fieldContext_ResearchConnection_edges(ctx, field) + case "pageInfo": + return ec.fieldContext_ResearchConnection_pageInfo(ctx, field) + case "totalCount": + return ec.fieldContext_ResearchConnection_totalCount(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type GroupCountResult", field.Name) + return nil, fmt.Errorf("no field named %q was found under type ResearchConnection", field.Name) }, } defer func() { @@ -2132,7 +2485,7 @@ func (ec *executionContext) fieldContext_Query_groupCount(ctx context.Context, f } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_groupCount_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_researches_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } @@ -2268,7 +2621,7 @@ func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, fie return fc, nil } -func (ec *executionContext) _Research_id(ctx context.Context, field graphql.CollectedField, obj *model.Research) (ret graphql.Marshaler) { +func (ec *executionContext) _Research_id(ctx context.Context, field graphql.CollectedField, obj *ent.Research) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Research_id(ctx, field) if err != nil { return graphql.Null @@ -2312,7 +2665,7 @@ func (ec *executionContext) fieldContext_Research_id(ctx context.Context, field return fc, nil } -func (ec *executionContext) _Research_name(ctx context.Context, field graphql.CollectedField, obj *model.Research) (ret graphql.Marshaler) { +func (ec *executionContext) _Research_name(ctx context.Context, field graphql.CollectedField, obj *ent.Research) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Research_name(ctx, field) if err != nil { return graphql.Null @@ -2356,7 +2709,7 @@ func (ec *executionContext) fieldContext_Research_name(ctx context.Context, fiel return fc, nil } -func (ec *executionContext) _Research_schema(ctx context.Context, field graphql.CollectedField, obj *model.Research) (ret graphql.Marshaler) { +func (ec *executionContext) _Research_schema(ctx context.Context, field graphql.CollectedField, obj *ent.Research) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Research_schema(ctx, field) if err != nil { return graphql.Null @@ -2400,8 +2753,8 @@ func (ec *executionContext) fieldContext_Research_schema(ctx context.Context, fi return fc, nil } -func (ec *executionContext) _Research_event(ctx context.Context, field graphql.CollectedField, obj *model.Research) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Research_event(ctx, field) +func (ec *executionContext) _ResearchConnection_edges(ctx context.Context, field graphql.CollectedField, obj *ent.ResearchConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ResearchConnection_edges(ctx, field) if err != nil { return graphql.Null } @@ -2414,7 +2767,7 @@ func (ec *executionContext) _Research_event(ctx context.Context, field graphql.C }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Research().Event(rctx, obj, fc.Args["input"].(string)) + return obj.Edges, nil }) if err != nil { ec.Error(ctx, err) @@ -2426,51 +2779,32 @@ func (ec *executionContext) _Research_event(ctx context.Context, field graphql.C } return graphql.Null } - res := resTmp.(*model.Event) + res := resTmp.([]*ent.ResearchEdge) fc.Result = res - return ec.marshalNEvent2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEvent(ctx, field.Selections, res) + return ec.marshalNResearchEdge2ᚕᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchEdgeᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Research_event(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ResearchConnection_edges(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Research", + Object: "ResearchConnection", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "id": - return ec.fieldContext_Event_id(ctx, field) - case "researchId": - return ec.fieldContext_Event_researchId(ctx, field) - case "content": - return ec.fieldContext_Event_content(ctx, field) - case "userId": - return ec.fieldContext_Event_userId(ctx, field) - case "createdAt": - return ec.fieldContext_Event_createdAt(ctx, field) - case "userAgent": - return ec.fieldContext_Event_userAgent(ctx, field) + case "node": + return ec.fieldContext_ResearchEdge_node(ctx, field) + case "cursor": + return ec.fieldContext_ResearchEdge_cursor(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type Event", field.Name) + return nil, fmt.Errorf("no field named %q was found under type ResearchEdge", field.Name) }, } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Research_event_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } return fc, nil } -func (ec *executionContext) _Research_events(ctx context.Context, field graphql.CollectedField, obj *model.Research) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Research_events(ctx, field) +func (ec *executionContext) _ResearchConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *ent.ResearchConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ResearchConnection_pageInfo(ctx, field) if err != nil { return graphql.Null } @@ -2483,52 +2817,48 @@ func (ec *executionContext) _Research_events(ctx context.Context, field graphql. }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Research().Events(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*string)) + return obj.PageInfo, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*model.EventsConnection) + res := resTmp.(entgql.PageInfo[string]) fc.Result = res - return ec.marshalOEventsConnection2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEventsConnection(ctx, field.Selections, res) + return ec.marshalNPageInfo2entgoᚗioᚋcontribᚋentgqlᚐPageInfo(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Research_events(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ResearchConnection_pageInfo(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Research", + Object: "ResearchConnection", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "edges": - return ec.fieldContext_EventsConnection_edges(ctx, field) - case "pageInfo": - return ec.fieldContext_EventsConnection_pageInfo(ctx, field) + case "hasNextPage": + return ec.fieldContext_PageInfo_hasNextPage(ctx, field) + case "hasPreviousPage": + return ec.fieldContext_PageInfo_hasPreviousPage(ctx, field) + case "startCursor": + return ec.fieldContext_PageInfo_startCursor(ctx, field) + case "endCursor": + return ec.fieldContext_PageInfo_endCursor(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type EventsConnection", field.Name) + return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name) }, } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Research_events_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } return fc, nil } -func (ec *executionContext) _Topic_id(ctx context.Context, field graphql.CollectedField, obj *model.Topic) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Topic_id(ctx, field) +func (ec *executionContext) _ResearchConnection_totalCount(ctx context.Context, field graphql.CollectedField, obj *ent.ResearchConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ResearchConnection_totalCount(ctx, field) if err != nil { return graphql.Null } @@ -2541,7 +2871,7 @@ func (ec *executionContext) _Topic_id(ctx context.Context, field graphql.Collect }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.ID, nil + return obj.TotalCount, nil }) if err != nil { ec.Error(ctx, err) @@ -2553,26 +2883,26 @@ func (ec *executionContext) _Topic_id(ctx context.Context, field graphql.Collect } return graphql.Null } - res := resTmp.(string) + res := resTmp.(int) fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) + return ec.marshalNInt2int(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Topic_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ResearchConnection_totalCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Topic", + Object: "ResearchConnection", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } -func (ec *executionContext) _Topic_filterInput(ctx context.Context, field graphql.CollectedField, obj *model.Topic) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Topic_filterInput(ctx, field) +func (ec *executionContext) _ResearchEdge_node(ctx context.Context, field graphql.CollectedField, obj *ent.ResearchEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ResearchEdge_node(ctx, field) if err != nil { return graphql.Null } @@ -2585,7 +2915,7 @@ func (ec *executionContext) _Topic_filterInput(ctx context.Context, field graphq }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.FilterInput, nil + return obj.Node, nil }) if err != nil { ec.Error(ctx, err) @@ -2597,26 +2927,34 @@ func (ec *executionContext) _Topic_filterInput(ctx context.Context, field graphq } return graphql.Null } - res := resTmp.(string) + res := resTmp.(*ent.Research) fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) + return ec.marshalNResearch2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearch(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Topic_filterInput(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ResearchEdge_node(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Topic", + Object: "ResearchEdge", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + switch field.Name { + case "id": + return ec.fieldContext_Research_id(ctx, field) + case "name": + return ec.fieldContext_Research_name(ctx, field) + case "schema": + return ec.fieldContext_Research_schema(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Research", field.Name) }, } return fc, nil } -func (ec *executionContext) _Topic_resultMappingInput(ctx context.Context, field graphql.CollectedField, obj *model.Topic) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Topic_resultMappingInput(ctx, field) +func (ec *executionContext) _ResearchEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *ent.ResearchEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ResearchEdge_cursor(ctx, field) if err != nil { return graphql.Null } @@ -2629,7 +2967,7 @@ func (ec *executionContext) _Topic_resultMappingInput(ctx context.Context, field }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.ResultMappingInput, nil + return obj.Cursor, nil }) if err != nil { ec.Error(ctx, err) @@ -2641,25 +2979,25 @@ func (ec *executionContext) _Topic_resultMappingInput(ctx context.Context, field } return graphql.Null } - res := resTmp.(string) + res := resTmp.(entgql.Cursor[string]) fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) + return ec.marshalNCursor2entgoᚗioᚋcontribᚋentgqlᚐCursor(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Topic_resultMappingInput(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ResearchEdge_cursor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Topic", + Object: "ResearchEdge", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + return nil, errors.New("field of type Cursor does not have child fields") }, } return fc, nil } -func (ec *executionContext) _User_id(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { +func (ec *executionContext) _User_id(ctx context.Context, field graphql.CollectedField, obj *ent.User) (ret graphql.Marshaler) { fc, err := ec.fieldContext_User_id(ctx, field) if err != nil { return graphql.Null @@ -2703,7 +3041,7 @@ func (ec *executionContext) fieldContext_User_id(ctx context.Context, field grap return fc, nil } -func (ec *executionContext) _User_name(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { +func (ec *executionContext) _User_name(ctx context.Context, field graphql.CollectedField, obj *ent.User) (ret graphql.Marshaler) { fc, err := ec.fieldContext_User_name(ctx, field) if err != nil { return graphql.Null @@ -2747,7 +3085,7 @@ func (ec *executionContext) fieldContext_User_name(ctx context.Context, field gr return fc, nil } -func (ec *executionContext) _User_email(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { +func (ec *executionContext) _User_email(ctx context.Context, field graphql.CollectedField, obj *ent.User) (ret graphql.Marshaler) { fc, err := ec.fieldContext_User_email(ctx, field) if err != nil { return graphql.Null @@ -2782,10 +3120,10 @@ func (ec *executionContext) _User_email(ctx context.Context, field graphql.Colle if tmp == nil { return nil, nil } - if data, ok := tmp.(*string); ok { + if data, ok := tmp.(string); ok { return data, nil } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *string`, tmp) + return nil, fmt.Errorf(`unexpected type %T from directive, should be string`, tmp) }) if err != nil { ec.Error(ctx, err) @@ -2794,9 +3132,9 @@ func (ec *executionContext) _User_email(ctx context.Context, field graphql.Colle if resTmp == nil { return graphql.Null } - res := resTmp.(*string) + res := resTmp.(string) fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) + return ec.marshalOString2string(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_User_email(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -2812,7 +3150,7 @@ func (ec *executionContext) fieldContext_User_email(ctx context.Context, field g return fc, nil } -func (ec *executionContext) _User_attributes(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { +func (ec *executionContext) _User_attributes(ctx context.Context, field graphql.CollectedField, obj *ent.User) (ret graphql.Marshaler) { fc, err := ec.fieldContext_User_attributes(ctx, field) if err != nil { return graphql.Null @@ -2825,8 +3163,32 @@ func (ec *executionContext) _User_attributes(ctx context.Context, field graphql. } }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Attributes, nil + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Attributes, nil + } + directive1 := func(ctx context.Context) (interface{}, error) { + userIDFieldName, err := ec.unmarshalOString2ᚖstring(ctx, "id") + if err != nil { + return nil, err + } + if ec.directives.Private == nil { + return nil, errors.New("directive private is not implemented") + } + return ec.directives.Private(ctx, obj, directive0, userIDFieldName) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(map[string]interface{}); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be map[string]interface{}`, tmp) }) if err != nil { ec.Error(ctx, err) @@ -4626,6 +4988,53 @@ func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Conte // region **************************** input.gotpl ***************************** +func (ec *executionContext) unmarshalInputCreateEventInput(ctx context.Context, obj interface{}) (model.CreateEventInput, error) { + var it model.CreateEventInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"userAgent", "content", "researchID"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "userAgent": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userAgent")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.UserAgent = data + case "content": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("content")) + data, err := ec.unmarshalNMap2map(ctx, v) + if err != nil { + return it, err + } + it.Content = data + case "researchID": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("researchID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.ResearchID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputCreateUserInput(ctx context.Context, obj interface{}) (model.CreateUserInput, error) { var it model.CreateUserInput asMap := map[string]interface{}{} @@ -4652,21 +5061,63 @@ func (ec *executionContext) unmarshalInputCreateUserInput(ctx context.Context, o case "email": var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) - data, err := ec.unmarshalNString2string(ctx, v) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Email = data + case "attributes": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("attributes")) + data, err := ec.unmarshalOMap2map(ctx, v) + if err != nil { + return it, err + } + it.Attributes = data + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputEventOrder(ctx context.Context, obj interface{}) (ent.EventOrder, error) { + var it ent.EventOrder + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + if _, present := asMap["direction"]; !present { + asMap["direction"] = "ASC" + } + + fieldsInOrder := [...]string{"direction", "field"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "direction": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("direction")) + data, err := ec.unmarshalNOrderDirection2entgoᚗioᚋcontribᚋentgqlᚐOrderDirection(ctx, v) if err != nil { return it, err } - it.Email = data - case "attributes": + it.Direction = data + case "field": var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("attributes")) - data, err := ec.unmarshalOMap2map(ctx, v) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("field")) + data, err := ec.unmarshalNEventOrderField2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventOrderField(ctx, v) if err != nil { return it, err } - it.Attributes = data + it.Field = data } } @@ -4767,47 +5218,42 @@ func (ec *executionContext) unmarshalInputLoginInput(ctx context.Context, obj in return it, nil } -func (ec *executionContext) unmarshalInputNewEvent(ctx context.Context, obj interface{}) (model.NewEvent, error) { - var it model.NewEvent +func (ec *executionContext) unmarshalInputResearchOrder(ctx context.Context, obj interface{}) (ent.ResearchOrder, error) { + var it ent.ResearchOrder asMap := map[string]interface{}{} for k, v := range obj.(map[string]interface{}) { asMap[k] = v } - fieldsInOrder := [...]string{"content", "researchId", "userAgent"} + if _, present := asMap["direction"]; !present { + asMap["direction"] = "ASC" + } + + fieldsInOrder := [...]string{"direction", "field"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { - case "content": - var err error - - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("content")) - data, err := ec.unmarshalNMap2map(ctx, v) - if err != nil { - return it, err - } - it.Content = data - case "researchId": + case "direction": var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("researchId")) - data, err := ec.unmarshalNString2string(ctx, v) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("direction")) + data, err := ec.unmarshalNOrderDirection2entgoᚗioᚋcontribᚋentgqlᚐOrderDirection(ctx, v) if err != nil { return it, err } - it.ResearchID = data - case "userAgent": + it.Direction = data + case "field": var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userAgent")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("field")) + data, err := ec.unmarshalNResearchOrderField2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchOrderField(ctx, v) if err != nil { return it, err } - it.UserAgent = data + it.Field = data } } @@ -4818,38 +5264,25 @@ func (ec *executionContext) unmarshalInputNewEvent(ctx context.Context, obj inte // region ************************** interface.gotpl *************************** -func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj model.Node) graphql.Marshaler { +func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj ent.Noder) graphql.Marshaler { switch obj := (obj).(type) { case nil: return graphql.Null - case model.User: - return ec._User(ctx, sel, &obj) - case *model.User: - if obj == nil { - return graphql.Null - } - return ec._User(ctx, sel, obj) - case model.Event: - return ec._Event(ctx, sel, &obj) - case *model.Event: + case *ent.Event: if obj == nil { return graphql.Null } return ec._Event(ctx, sel, obj) - case model.Research: - return ec._Research(ctx, sel, &obj) - case *model.Research: + case *ent.Research: if obj == nil { return graphql.Null } return ec._Research(ctx, sel, obj) - case model.Topic: - return ec._Topic(ctx, sel, &obj) - case *model.Topic: + case *ent.User: if obj == nil { return graphql.Null } - return ec._Topic(ctx, sel, obj) + return ec._User(ctx, sel, obj) default: panic(fmt.Errorf("unexpected type %T", obj)) } @@ -4905,7 +5338,7 @@ func (ec *executionContext) _CategoryCount(ctx context.Context, sel ast.Selectio var eventImplementors = []string{"Event", "Node"} -func (ec *executionContext) _Event(ctx context.Context, sel ast.SelectionSet, obj *model.Event) graphql.Marshaler { +func (ec *executionContext) _Event(ctx context.Context, sel ast.SelectionSet, obj *ent.Event) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, eventImplementors) out := graphql.NewFieldSet(fields) @@ -4917,30 +5350,89 @@ func (ec *executionContext) _Event(ctx context.Context, sel ast.SelectionSet, ob case "id": out.Values[i] = ec._Event_id(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } - case "researchId": - out.Values[i] = ec._Event_researchId(ctx, field, obj) + case "createdAt": + out.Values[i] = ec._Event_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) + } + case "userAgent": + out.Values[i] = ec._Event_userAgent(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) } case "content": out.Values[i] = ec._Event_content(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } - case "userId": - out.Values[i] = ec._Event_userId(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + case "user": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Event_user(ctx, field, obj) + return res } - case "createdAt": - out.Values[i] = ec._Event_createdAt(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue } - case "userAgent": - out.Values[i] = ec._Event_userAgent(ctx, field, obj) + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "research": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Event_research(ctx, field, obj) + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -4964,24 +5456,29 @@ func (ec *executionContext) _Event(ctx context.Context, sel ast.SelectionSet, ob return out } -var eventsConnectionImplementors = []string{"EventsConnection"} +var eventConnectionImplementors = []string{"EventConnection"} -func (ec *executionContext) _EventsConnection(ctx context.Context, sel ast.SelectionSet, obj *model.EventsConnection) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, eventsConnectionImplementors) +func (ec *executionContext) _EventConnection(ctx context.Context, sel ast.SelectionSet, obj *ent.EventConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, eventConnectionImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("EventsConnection") + out.Values[i] = graphql.MarshalString("EventConnection") case "edges": - out.Values[i] = ec._EventsConnection_edges(ctx, field, obj) + out.Values[i] = ec._EventConnection_edges(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "pageInfo": - out.Values[i] = ec._EventsConnection_pageInfo(ctx, field, obj) + out.Values[i] = ec._EventConnection_pageInfo(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "totalCount": + out.Values[i] = ec._EventConnection_totalCount(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -5008,24 +5505,24 @@ func (ec *executionContext) _EventsConnection(ctx context.Context, sel ast.Selec return out } -var eventsEdgeImplementors = []string{"EventsEdge"} +var eventEdgeImplementors = []string{"EventEdge"} -func (ec *executionContext) _EventsEdge(ctx context.Context, sel ast.SelectionSet, obj *model.EventsEdge) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, eventsEdgeImplementors) +func (ec *executionContext) _EventEdge(ctx context.Context, sel ast.SelectionSet, obj *ent.EventEdge) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, eventEdgeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("EventsEdge") + out.Values[i] = graphql.MarshalString("EventEdge") case "node": - out.Values[i] = ec._EventsEdge_node(ctx, field, obj) + out.Values[i] = ec._EventEdge_node(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "cursor": - out.Values[i] = ec._EventsEdge_cursor(ctx, field, obj) + out.Values[i] = ec._EventEdge_cursor(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -5161,7 +5658,7 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) var pageInfoImplementors = []string{"PageInfo"} -func (ec *executionContext) _PageInfo(ctx context.Context, sel ast.SelectionSet, obj *model.PageInfo) graphql.Marshaler { +func (ec *executionContext) _PageInfo(ctx context.Context, sel ast.SelectionSet, obj *entgql.PageInfo[string]) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, pageInfoImplementors) out := graphql.NewFieldSet(fields) @@ -5172,18 +5669,18 @@ func (ec *executionContext) _PageInfo(ctx context.Context, sel ast.SelectionSet, out.Values[i] = graphql.MarshalString("PageInfo") case "hasNextPage": out.Values[i] = ec._PageInfo_hasNextPage(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "hasPreviousPage": out.Values[i] = ec._PageInfo_hasPreviousPage(ctx, field, obj) - case "startCursor": - out.Values[i] = ec._PageInfo_startCursor(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } + case "startCursor": + out.Values[i] = ec._PageInfo_startCursor(ctx, field, obj) case "endCursor": out.Values[i] = ec._PageInfo_endCursor(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -5236,9 +5733,6 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } }() res = ec._Query_me(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } return res } @@ -5248,7 +5742,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "research": + case "node": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { @@ -5257,7 +5751,26 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._Query_research(ctx, field) + res = ec._Query_node(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "nodes": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_nodes(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } @@ -5270,7 +5783,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "researches": + case "groupCount": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { @@ -5279,7 +5792,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._Query_researches(ctx, field) + res = ec._Query_groupCount(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } @@ -5291,6 +5804,25 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "event": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_event(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "events": field := field @@ -5314,7 +5846,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "groupCount": + case "research": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { @@ -5323,7 +5855,26 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._Query_groupCount(ctx, field) + res = ec._Query_research(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "researches": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_researches(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } @@ -5334,16 +5885,65 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "__type": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Query___type(ctx, field) - }) - case "__schema": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Query___schema(ctx, field) - }) + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "__type": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Query___type(ctx, field) + }) + case "__schema": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Query___schema(ctx, field) + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var researchImplementors = []string{"Research", "Node"} + +func (ec *executionContext) _Research(ctx context.Context, sel ast.SelectionSet, obj *ent.Research) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, researchImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Research") + case "id": + out.Values[i] = ec._Research_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._Research_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "schema": + out.Values[i] = ec._Research_schema(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -5367,101 +5967,32 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr return out } -var researchImplementors = []string{"Research", "Node"} +var researchConnectionImplementors = []string{"ResearchConnection"} -func (ec *executionContext) _Research(ctx context.Context, sel ast.SelectionSet, obj *model.Research) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, researchImplementors) +func (ec *executionContext) _ResearchConnection(ctx context.Context, sel ast.SelectionSet, obj *ent.ResearchConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, researchConnectionImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("Research") - case "id": - out.Values[i] = ec._Research_id(ctx, field, obj) + out.Values[i] = graphql.MarshalString("ResearchConnection") + case "edges": + out.Values[i] = ec._ResearchConnection_edges(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } - case "name": - out.Values[i] = ec._Research_name(ctx, field, obj) + case "pageInfo": + out.Values[i] = ec._ResearchConnection_pageInfo(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } - case "schema": - out.Values[i] = ec._Research_schema(ctx, field, obj) + case "totalCount": + out.Values[i] = ec._ResearchConnection_totalCount(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) - } - case "event": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Research_event(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - if field.Deferrable != nil { - dfs, ok := deferred[field.Deferrable.Label] - di := 0 - if ok { - dfs.AddField(field) - di = len(dfs.Values) - 1 - } else { - dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) - deferred[field.Deferrable.Label] = dfs - } - dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { - return innerFunc(ctx, dfs) - }) - - // don't run the out.Concurrently() call below - out.Values[i] = graphql.Null - continue - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - case "events": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Research_events(ctx, field, obj) - return res - } - - if field.Deferrable != nil { - dfs, ok := deferred[field.Deferrable.Label] - di := 0 - if ok { - dfs.AddField(field) - di = len(dfs.Values) - 1 - } else { - dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) - deferred[field.Deferrable.Label] = dfs - } - dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { - return innerFunc(ctx, dfs) - }) - - // don't run the out.Concurrently() call below - out.Values[i] = graphql.Null - continue + out.Invalids++ } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -5485,29 +6016,24 @@ func (ec *executionContext) _Research(ctx context.Context, sel ast.SelectionSet, return out } -var topicImplementors = []string{"Topic", "Node"} +var researchEdgeImplementors = []string{"ResearchEdge"} -func (ec *executionContext) _Topic(ctx context.Context, sel ast.SelectionSet, obj *model.Topic) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, topicImplementors) +func (ec *executionContext) _ResearchEdge(ctx context.Context, sel ast.SelectionSet, obj *ent.ResearchEdge) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, researchEdgeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("Topic") - case "id": - out.Values[i] = ec._Topic_id(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "filterInput": - out.Values[i] = ec._Topic_filterInput(ctx, field, obj) + out.Values[i] = graphql.MarshalString("ResearchEdge") + case "node": + out.Values[i] = ec._ResearchEdge_node(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "resultMappingInput": - out.Values[i] = ec._Topic_resultMappingInput(ctx, field, obj) + case "cursor": + out.Values[i] = ec._ResearchEdge_cursor(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -5536,7 +6062,7 @@ func (ec *executionContext) _Topic(ctx context.Context, sel ast.SelectionSet, ob var userImplementors = []string{"User", "Node"} -func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *model.User) graphql.Marshaler { +func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *ent.User) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, userImplementors) out := graphql.NewFieldSet(fields) @@ -5998,16 +6524,31 @@ func (ec *executionContext) marshalNCategoryCount2ᚖexusiaiᚗdevᚋroguestats return ec._CategoryCount(ctx, sel, v) } +func (ec *executionContext) unmarshalNCreateEventInput2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐCreateEventInput(ctx context.Context, v interface{}) (model.CreateEventInput, error) { + res, err := ec.unmarshalInputCreateEventInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalNCreateUserInput2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐCreateUserInput(ctx context.Context, v interface{}) (model.CreateUserInput, error) { res, err := ec.unmarshalInputCreateUserInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNEvent2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEvent(ctx context.Context, sel ast.SelectionSet, v model.Event) graphql.Marshaler { +func (ec *executionContext) unmarshalNCursor2entgoᚗioᚋcontribᚋentgqlᚐCursor(ctx context.Context, v interface{}) (entgql.Cursor[string], error) { + var res entgql.Cursor[string] + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNCursor2entgoᚗioᚋcontribᚋentgqlᚐCursor(ctx context.Context, sel ast.SelectionSet, v entgql.Cursor[string]) graphql.Marshaler { + return v +} + +func (ec *executionContext) marshalNEvent2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEvent(ctx context.Context, sel ast.SelectionSet, v ent.Event) graphql.Marshaler { return ec._Event(ctx, sel, &v) } -func (ec *executionContext) marshalNEvent2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEvent(ctx context.Context, sel ast.SelectionSet, v *model.Event) graphql.Marshaler { +func (ec *executionContext) marshalNEvent2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEvent(ctx context.Context, sel ast.SelectionSet, v *ent.Event) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -6017,21 +6558,21 @@ func (ec *executionContext) marshalNEvent2ᚖexusiaiᚗdevᚋroguestatsᚑbacken return ec._Event(ctx, sel, v) } -func (ec *executionContext) marshalNEventsConnection2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEventsConnection(ctx context.Context, sel ast.SelectionSet, v model.EventsConnection) graphql.Marshaler { - return ec._EventsConnection(ctx, sel, &v) +func (ec *executionContext) marshalNEventConnection2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventConnection(ctx context.Context, sel ast.SelectionSet, v ent.EventConnection) graphql.Marshaler { + return ec._EventConnection(ctx, sel, &v) } -func (ec *executionContext) marshalNEventsConnection2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEventsConnection(ctx context.Context, sel ast.SelectionSet, v *model.EventsConnection) graphql.Marshaler { +func (ec *executionContext) marshalNEventConnection2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventConnection(ctx context.Context, sel ast.SelectionSet, v *ent.EventConnection) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } - return ec._EventsConnection(ctx, sel, v) + return ec._EventConnection(ctx, sel, v) } -func (ec *executionContext) marshalNEventsEdge2ᚕᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEventsEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.EventsEdge) graphql.Marshaler { +func (ec *executionContext) marshalNEventEdge2ᚕᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*ent.EventEdge) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -6055,7 +6596,7 @@ func (ec *executionContext) marshalNEventsEdge2ᚕᚖexusiaiᚗdevᚋroguestats if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNEventsEdge2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEventsEdge(ctx, sel, v[i]) + ret[i] = ec.marshalNEventEdge2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventEdge(ctx, sel, v[i]) } if isLen1 { f(i) @@ -6075,14 +6616,30 @@ func (ec *executionContext) marshalNEventsEdge2ᚕᚖexusiaiᚗdevᚋroguestats return ret } -func (ec *executionContext) marshalNEventsEdge2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEventsEdge(ctx context.Context, sel ast.SelectionSet, v *model.EventsEdge) graphql.Marshaler { +func (ec *executionContext) marshalNEventEdge2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventEdge(ctx context.Context, sel ast.SelectionSet, v *ent.EventEdge) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._EventEdge(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNEventOrderField2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventOrderField(ctx context.Context, v interface{}) (*ent.EventOrderField, error) { + var res = new(ent.EventOrderField) + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNEventOrderField2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventOrderField(ctx context.Context, sel ast.SelectionSet, v *ent.EventOrderField) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } - return ec._EventsEdge(ctx, sel, v) + return v } func (ec *executionContext) unmarshalNGroupCountInput2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐGroupCountInput(ctx context.Context, v interface{}) (model.GroupCountInput, error) { @@ -6119,6 +6676,38 @@ func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.Selec return res } +func (ec *executionContext) unmarshalNID2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]string, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNID2string(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalNID2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + for i := range v { + ret[i] = ec.marshalNID2string(ctx, sel, v[i]) + } + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) { res, err := graphql.UnmarshalInt(v) return res, graphql.ErrorOnPath(ctx, err) @@ -6160,26 +6749,83 @@ func (ec *executionContext) marshalNMap2map(ctx context.Context, sel ast.Selecti return res } -func (ec *executionContext) unmarshalNNewEvent2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐNewEvent(ctx context.Context, v interface{}) (model.NewEvent, error) { - res, err := ec.unmarshalInputNewEvent(ctx, v) +func (ec *executionContext) marshalNNode2ᚕexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐNoder(ctx context.Context, sel ast.SelectionSet, v []ent.Noder) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalONode2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐNoder(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + return ret +} + +func (ec *executionContext) unmarshalNOrderDirection2entgoᚗioᚋcontribᚋentgqlᚐOrderDirection(ctx context.Context, v interface{}) (entgql.OrderDirection, error) { + var res entgql.OrderDirection + err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNPageInfo2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐPageInfo(ctx context.Context, sel ast.SelectionSet, v *model.PageInfo) graphql.Marshaler { +func (ec *executionContext) marshalNOrderDirection2entgoᚗioᚋcontribᚋentgqlᚐOrderDirection(ctx context.Context, sel ast.SelectionSet, v entgql.OrderDirection) graphql.Marshaler { + return v +} + +func (ec *executionContext) marshalNPageInfo2entgoᚗioᚋcontribᚋentgqlᚐPageInfo(ctx context.Context, sel ast.SelectionSet, v entgql.PageInfo[string]) graphql.Marshaler { + return ec._PageInfo(ctx, sel, &v) +} + +func (ec *executionContext) marshalNResearch2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearch(ctx context.Context, sel ast.SelectionSet, v *ent.Research) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } - return ec._PageInfo(ctx, sel, v) + return ec._Research(ctx, sel, v) +} + +func (ec *executionContext) marshalNResearchConnection2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchConnection(ctx context.Context, sel ast.SelectionSet, v ent.ResearchConnection) graphql.Marshaler { + return ec._ResearchConnection(ctx, sel, &v) } -func (ec *executionContext) marshalNResearch2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐResearch(ctx context.Context, sel ast.SelectionSet, v model.Research) graphql.Marshaler { - return ec._Research(ctx, sel, &v) +func (ec *executionContext) marshalNResearchConnection2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchConnection(ctx context.Context, sel ast.SelectionSet, v *ent.ResearchConnection) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._ResearchConnection(ctx, sel, v) } -func (ec *executionContext) marshalNResearch2ᚕᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐResearchᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Research) graphql.Marshaler { +func (ec *executionContext) marshalNResearchEdge2ᚕᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*ent.ResearchEdge) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -6203,7 +6849,7 @@ func (ec *executionContext) marshalNResearch2ᚕᚖexusiaiᚗdevᚋroguestatsᚑ if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNResearch2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐResearch(ctx, sel, v[i]) + ret[i] = ec.marshalNResearchEdge2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchEdge(ctx, sel, v[i]) } if isLen1 { f(i) @@ -6223,14 +6869,30 @@ func (ec *executionContext) marshalNResearch2ᚕᚖexusiaiᚗdevᚋroguestatsᚑ return ret } -func (ec *executionContext) marshalNResearch2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐResearch(ctx context.Context, sel ast.SelectionSet, v *model.Research) graphql.Marshaler { +func (ec *executionContext) marshalNResearchEdge2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchEdge(ctx context.Context, sel ast.SelectionSet, v *ent.ResearchEdge) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } - return ec._Research(ctx, sel, v) + return ec._ResearchEdge(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNResearchOrderField2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchOrderField(ctx context.Context, v interface{}) (*ent.ResearchOrderField, error) { + var res = new(ent.ResearchOrderField) + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNResearchOrderField2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchOrderField(ctx context.Context, sel ast.SelectionSet, v *ent.ResearchOrderField) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return v } func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { @@ -6263,11 +6925,11 @@ func (ec *executionContext) marshalNTime2timeᚐTime(ctx context.Context, sel as return res } -func (ec *executionContext) marshalNUser2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v model.User) graphql.Marshaler { +func (ec *executionContext) marshalNUser2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐUser(ctx context.Context, sel ast.SelectionSet, v ent.User) graphql.Marshaler { return ec._User(ctx, sel, &v) } -func (ec *executionContext) marshalNUser2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { +func (ec *executionContext) marshalNUser2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐUser(ctx context.Context, sel ast.SelectionSet, v *ent.User) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") @@ -6556,27 +7218,35 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast return res } -func (ec *executionContext) marshalOEventsConnection2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋmodelᚐEventsConnection(ctx context.Context, sel ast.SelectionSet, v *model.EventsConnection) graphql.Marshaler { +func (ec *executionContext) unmarshalOCursor2ᚖentgoᚗioᚋcontribᚋentgqlᚐCursor(ctx context.Context, v interface{}) (*entgql.Cursor[string], error) { if v == nil { - return graphql.Null + return nil, nil } - return ec._EventsConnection(ctx, sel, v) + var res = new(entgql.Cursor[string]) + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOID2ᚖstring(ctx context.Context, v interface{}) (*string, error) { +func (ec *executionContext) marshalOCursor2ᚖentgoᚗioᚋcontribᚋentgqlᚐCursor(ctx context.Context, sel ast.SelectionSet, v *entgql.Cursor[string]) graphql.Marshaler { if v == nil { - return nil, nil + return graphql.Null } - res, err := graphql.UnmarshalID(v) - return &res, graphql.ErrorOnPath(ctx, err) + return v } -func (ec *executionContext) marshalOID2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { +func (ec *executionContext) marshalOEvent2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEvent(ctx context.Context, sel ast.SelectionSet, v *ent.Event) graphql.Marshaler { if v == nil { return graphql.Null } - res := graphql.MarshalID(*v) - return res + return ec._Event(ctx, sel, v) +} + +func (ec *executionContext) unmarshalOEventOrder2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐEventOrder(ctx context.Context, v interface{}) (*ent.EventOrder, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputEventOrder(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v interface{}) (*int, error) { @@ -6611,6 +7281,38 @@ func (ec *executionContext) marshalOMap2map(ctx context.Context, sel ast.Selecti return res } +func (ec *executionContext) marshalONode2exusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐNoder(ctx context.Context, sel ast.SelectionSet, v ent.Noder) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._Node(ctx, sel, v) +} + +func (ec *executionContext) marshalOResearch2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearch(ctx context.Context, sel ast.SelectionSet, v *ent.Research) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._Research(ctx, sel, v) +} + +func (ec *executionContext) unmarshalOResearchOrder2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐResearchOrder(ctx context.Context, v interface{}) (*ent.ResearchOrder, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputResearchOrder(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + return res +} + func (ec *executionContext) unmarshalOString2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { if v == nil { return nil, nil @@ -6665,6 +7367,13 @@ func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel as return res } +func (ec *executionContext) marshalOUser2ᚖexusiaiᚗdevᚋroguestatsᚑbackendᚋinternalᚋentᚐUser(ctx context.Context, sel ast.SelectionSet, v *ent.User) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._User(ctx, sel, v) +} + func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/internal/graph/resolver.go b/internal/graph/resolver.go index 3e44295..dfdd937 100644 --- a/internal/graph/resolver.go +++ b/internal/graph/resolver.go @@ -1,9 +1,9 @@ package graph import ( - "github.com/uptrace/bun" "go.uber.org/fx" + "exusiai.dev/roguestats-backend/internal/ent" "exusiai.dev/roguestats-backend/internal/service" ) @@ -20,9 +20,7 @@ type Resolver struct { type ResolverDeps struct { fx.In - DB *bun.DB - AuthService service.Auth - UserService service.User - EventService service.Event - ResearchService service.Research + Ent *ent.Client + AuthService service.Auth + EventService service.Event } diff --git a/internal/graph/schema.resolvers.go b/internal/graph/schema.resolvers.go index b242931..4d222b4 100644 --- a/internal/graph/schema.resolvers.go +++ b/internal/graph/schema.resolvers.go @@ -7,78 +7,70 @@ package graph import ( "context" - "exusiai.dev/roguestats-backend/internal/cursorutils" + "entgo.io/contrib/entgql" + "exusiai.dev/roguestats-backend/internal/ent" "exusiai.dev/roguestats-backend/internal/model" ) // Login is the resolver for the login field. -func (r *mutationResolver) Login(ctx context.Context, input model.LoginInput) (*model.User, error) { +func (r *mutationResolver) Login(ctx context.Context, input model.LoginInput) (*ent.User, error) { return r.AuthService.AuthByLoginInput(ctx, input) } // CreateEvent is the resolver for the createEvent field. -func (r *mutationResolver) CreateEvent(ctx context.Context, input model.NewEvent) (*model.Event, error) { - return r.EventService.CreateEventFromInput(ctx, &input) +func (r *mutationResolver) CreateEvent(ctx context.Context, input model.CreateEventInput) (*ent.Event, error) { + return r.EventService.CreateEventFromInput(ctx, input) } // CreateUser is the resolver for the createUser field. -func (r *mutationResolver) CreateUser(ctx context.Context, input model.CreateUserInput) (*model.User, error) { +func (r *mutationResolver) CreateUser(ctx context.Context, input model.CreateUserInput) (*ent.User, error) { return r.AuthService.CreateUser(ctx, input) } -// Me is the resolver for the `me` field. -func (r *queryResolver) Me(ctx context.Context) (*model.User, error) { +// Me is the resolver for the me field. +func (r *queryResolver) Me(ctx context.Context) (*ent.User, error) { return r.AuthService.CurrentUser(ctx) } -// Research is the resolver for the research field. -func (r *queryResolver) Research(ctx context.Context, id string) (*model.Research, error) { - return r.ResearchService.GetResearchByID(ctx, id) +// Node is the resolver for the node field. +func (r *queryResolver) Node(ctx context.Context, id string) (ent.Noder, error) { + return r.Ent.Noder(ctx, id) } -// Researches is the resolver for the researches field. -func (r *queryResolver) Researches(ctx context.Context) ([]*model.Research, error) { - return r.ResearchService.GetAllResearch(ctx) -} - -// Events is the resolver for the events field. -func (r *queryResolver) Events(ctx context.Context, researchID *string, first *int, after *string) (*model.EventsConnection, error) { - var decodedCursor string - var err error - if after != nil { - decodedCursor, err = cursorutils.DecodeCursor(*after) - if err != nil { - return nil, err - } - } - return r.EventService.GetPaginatedEvents(ctx, *researchID, *first, decodedCursor) +// Nodes is the resolver for the nodes field. +func (r *queryResolver) Nodes(ctx context.Context, ids []string) ([]ent.Noder, error) { + return r.Ent.Noders(ctx, ids) } // GroupCount is the resolver for the groupCount field. func (r *queryResolver) GroupCount(ctx context.Context, input model.GroupCountInput) (*model.GroupCountResult, error) { - groupCountResult, err := r.EventService.CalculateStats(ctx, input.ResearchID, input.FilterInput, input.ResultMappingInput) - if err != nil { - return nil, err - } - return groupCountResult, nil + return r.EventService.CalculateStats(ctx, input.ResearchID, input.FilterInput, input.ResultMappingInput) } // Event is the resolver for the event field. -func (r *researchResolver) Event(ctx context.Context, obj *model.Research, input string) (*model.Event, error) { - return r.EventService.GetEvent(ctx, obj.ID) +func (r *queryResolver) Event(ctx context.Context, id string) (*ent.Event, error) { + return r.Ent.Event.Get(ctx, id) } // Events is the resolver for the events field. -func (r *researchResolver) Events(ctx context.Context, obj *model.Research, first *int, after *string) (*model.EventsConnection, error) { - var decodedCursor string - var err error - if after != nil { - decodedCursor, err = cursorutils.DecodeCursor(*after) - if err != nil { - return nil, err - } - } - return r.EventService.GetPaginatedEvents(ctx, obj.ID, *first, decodedCursor) +func (r *queryResolver) Events(ctx context.Context, after *entgql.Cursor[string], first *int, before *entgql.Cursor[string], last *int, orderBy *ent.EventOrder) (*ent.EventConnection, error) { + return r.Ent.Event.Query(). + Paginate(ctx, after, first, before, last, + ent.WithEventOrder(orderBy), + ) +} + +// Research is the resolver for the research field. +func (r *queryResolver) Research(ctx context.Context, id string) (*ent.Research, error) { + return r.Ent.Research.Get(ctx, id) +} + +// Researches is the resolver for the researches field. +func (r *queryResolver) Researches(ctx context.Context, after *entgql.Cursor[string], first *int, before *entgql.Cursor[string], last *int, orderBy *ent.ResearchOrder) (*ent.ResearchConnection, error) { + return r.Ent.Research.Query(). + Paginate(ctx, after, first, before, last, + ent.WithResearchOrder(orderBy), + ) } // Mutation returns MutationResolver implementation. @@ -87,11 +79,5 @@ func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } // Query returns QueryResolver implementation. func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } -// Research returns ResearchResolver implementation. -func (r *Resolver) Research() ResearchResolver { return &researchResolver{r} } - -type ( - mutationResolver struct{ *Resolver } - queryResolver struct{ *Resolver } - researchResolver struct{ *Resolver } -) +type mutationResolver struct{ *Resolver } +type queryResolver struct{ *Resolver } diff --git a/internal/graph/schema.resolvers.go.backup b/internal/graph/schema.resolvers.go.backup new file mode 100644 index 0000000..b8bd422 --- /dev/null +++ b/internal/graph/schema.resolvers.go.backup @@ -0,0 +1,82 @@ +package graph + +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.36 + +import ( + "context" + + "exusiai.dev/roguestats-backend/internal/cursorutils" + "exusiai.dev/roguestats-backend/internal/ent" +) + +// Node is the resolver for the node field. +func (r *queryResolver) Node(ctx context.Context, id string) (ent.Noder, error) { + return r.Ent.Noder(ctx, id) +} + +// Nodes is the resolver for the nodes field. +func (r *queryResolver) Nodes(ctx context.Context, ids []string) ([]ent.Noder, error) { + return r.Ent.Noders(ctx, ids) +} + +// Events is the resolver for the events field. +func (r *queryResolver) Events(ctx context.Context) ([]*ent.Event, error) { + var decodedCursor string + var err error + if after != nil { + decodedCursor, err = cursorutils.DecodeCursor(*after) + if err != nil { + return nil, err + } + } + return r.EventService.GetPaginatedEvents(ctx, *researchID, *first, decodedCursor) +} + +// Researches is the resolver for the researches field. +func (r *queryResolver) Researches(ctx context.Context) ([]*ent.Research, error) { + return r.ResearchService.GetAllResearch(ctx) +} + +// Query returns QueryResolver implementation. +func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } + +type queryResolver struct{ *Resolver } + +// !!! WARNING !!! +// The code below was going to be deleted when updating resolvers. It has been copied here so you have +// one last chance to move it out of harms way if you want. There are two reasons this happens: +// - When renaming or deleting a resolver the old code will be put in here. You can safely delete +// it when you're done. +// - You have helper methods in this file. Move them out to keep these resolver files clean. +func (r *mutationResolver) Login(ctx context.Context, input ent.LoginInput) (*ent.User, error) { + return r.AuthService.AuthByLoginInput(ctx, input) +} + +func (r *mutationResolver) CreateEvent(ctx context.Context, input ent.NewEvent) (*ent.Event, error) { + return r.EventService.CreateEventFromInput(ctx, &input) +} + +func (r *mutationResolver) CreateUser(ctx context.Context, input ent.CreateUserInput) (*ent.User, error) { + return r.AuthService.CreateUser(ctx, input) +} + +func (r *queryResolver) Me(ctx context.Context) (*ent.User, error) { + return r.AuthService.CurrentUser(ctx) +} + +func (r *queryResolver) Research(ctx context.Context, id string) (*ent.Research, error) { + return r.ResearchService.GetResearchByID(ctx, id) +} + +func (r *queryResolver) GroupCount(ctx context.Context, input ent.GroupCountInput) (*ent.GroupCountResult, error) { + groupCountResult, err := r.EventService.CalculateStats(ctx, input.ResearchID, input.FilterInput, input.ResultMappingInput) + if err != nil { + return nil, err + } + return groupCountResult, nil +} +func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } + +type mutationResolver struct{ *Resolver } diff --git a/internal/infra/db/db.go b/internal/infra/db/db.go index b772710..c8c81d8 100644 --- a/internal/infra/db/db.go +++ b/internal/infra/db/db.go @@ -1,16 +1,24 @@ package db import ( - "database/sql" + "context" + + "github.com/rs/zerolog/log" "exusiai.dev/roguestats-backend/internal/app/appconfig" - "github.com/uptrace/bun" - "github.com/uptrace/bun/dialect/pgdialect" - "github.com/uptrace/bun/driver/pgdriver" + "exusiai.dev/roguestats-backend/internal/ent" + + _ "github.com/lib/pq" ) -func New(conf *appconfig.Config) *bun.DB { - sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(conf.DatabaseURL))) - db := bun.NewDB(sqldb, pgdialect.New()) - return db +func New(conf *appconfig.Config) *ent.Client { + client, err := ent.Open("postgres", conf.DatabaseURL) + if err != nil { + log.Fatal().Err(err).Msg("failed connecting to database") + } + + if err := client.Schema.Create(context.Background()); err != nil { + log.Fatal().Err(err).Msg("failed creating schema resources") + } + return client.Debug() } diff --git a/internal/infra/db/migrations/logformat.go b/internal/infra/db/migrations/logformat.go deleted file mode 100644 index 19f8d3a..0000000 --- a/internal/infra/db/migrations/logformat.go +++ /dev/null @@ -1,19 +0,0 @@ -package migrations - -import ( - "strings" - - "github.com/uptrace/bun/migrate" -) - -// formatMigrations formats migrations for logging. -func formatMigrations(s migrate.MigrationSlice) string { - var sb strings.Builder - for i, m := range s { - if i > 0 { - sb.WriteString(", ") - } - sb.WriteString(m.String()) - } - return sb.String() -} diff --git a/internal/infra/db/migrations/migrations.go b/internal/infra/db/migrations/migrations.go deleted file mode 100644 index 209abef..0000000 --- a/internal/infra/db/migrations/migrations.go +++ /dev/null @@ -1,19 +0,0 @@ -package migrations - -import ( - "embed" - - "github.com/uptrace/bun/migrate" -) - -// A collection of migrations. -var Migrations = migrate.NewMigrations() - -//go:embed sql/*.sql -var sqlMigrations embed.FS - -func init() { - if err := Migrations.Discover(sqlMigrations); err != nil { - panic(err) - } -} diff --git a/internal/infra/db/migrations/migrator.go b/internal/infra/db/migrations/migrator.go deleted file mode 100644 index 9cea00c..0000000 --- a/internal/infra/db/migrations/migrator.go +++ /dev/null @@ -1,131 +0,0 @@ -package migrations - -import ( - "context" - - "github.com/rs/zerolog/log" - "github.com/uptrace/bun/migrate" -) - -type Migrator struct { - m *migrate.Migrator -} - -func NewMigrator(m *migrate.Migrator) *Migrator { - return &Migrator{m: m} -} - -func (m *Migrator) Init(ctx context.Context) error { - return m.m.Init(ctx) -} - -func (m *Migrator) Migrate(ctx context.Context) error { - group, err := m.m.Migrate(ctx) - if err != nil { - return err - } - - if group.IsZero() { - log.Info().Msg("no migrations to apply") - return nil - } - - log.Info(). - Str("migrations", formatMigrations(group.Migrations)). - Msg("applied migrations") - - return nil -} - -func (m *Migrator) Rollback(ctx context.Context) error { - group, err := m.m.Rollback(ctx) - if err != nil { - return err - } - - if group.IsZero() { - log.Info().Msg("no migrations to rollback") - return nil - } - - log.Info(). - Interface("migrations", formatMigrations(group.Migrations)). - Msg("rolled back migrations") - return nil -} - -func (m *Migrator) Lock(ctx context.Context) error { - return m.m.Lock(ctx) -} - -func (m *Migrator) Unlock(ctx context.Context) error { - return m.m.Unlock(ctx) -} - -func (m *Migrator) CreateGoMigration(ctx context.Context, name string) error { - mf, err := m.m.CreateGoMigration(ctx, name) - if err != nil { - return err - } - - log.Info(). - Str("name", mf.Name). - Str("path", mf.Path). - Msg("created go migration file") - - return nil -} - -func (m *Migrator) CreateSQLMigrations(ctx context.Context, name string) error { - files, err := m.m.CreateSQLMigrations(ctx, name) - if err != nil { - return err - } - - for _, mf := range files { - log.Info(). - Str("name", mf.Name). - Str("path", mf.Path). - Msg("created sql migration file") - } - - return nil -} - -func (m *Migrator) Status(ctx context.Context) error { - ms, err := m.m.MigrationsWithStatus(ctx) - if err != nil { - return err - } - - log.Info(). - Interface("migrations", formatMigrations(ms)). - Msg("migrations status") - - log.Info(). - Interface("unapplied", formatMigrations(ms.Unapplied())). - Msg("unapplied migrations") - - log.Info(). - Stringer("last_group", ms.LastGroup()). - Msg("last migration group") - - return nil -} - -func (m *Migrator) MarkApplied(ctx context.Context) error { - group, err := m.m.Migrate(ctx, migrate.WithNopMigration()) - if err != nil { - return err - } - - if group.IsZero() { - log.Info().Msg("no migrations to apply") - return nil - } - - log.Info(). - Interface("migrations", formatMigrations(group.Migrations)). - Msg("marked migrations as applied") - return nil -} diff --git a/internal/infra/db/migrations/sql/20230820005345_init.tx.down.sql b/internal/infra/db/migrations/sql/20230820005345_init.tx.down.sql deleted file mode 100644 index 36f6963..0000000 --- a/internal/infra/db/migrations/sql/20230820005345_init.tx.down.sql +++ /dev/null @@ -1,3 +0,0 @@ -drop table public.events; -drop table public.researches; -drop table public.users; diff --git a/internal/infra/db/migrations/sql/20230820005345_init.tx.up.sql b/internal/infra/db/migrations/sql/20230820005345_init.tx.up.sql deleted file mode 100644 index 2315747..0000000 --- a/internal/infra/db/migrations/sql/20230820005345_init.tx.up.sql +++ /dev/null @@ -1,29 +0,0 @@ -create table - public.users ( - user_id text not null constraint users_pk primary key, - name text not null, - email text not null, - credential text not null, - attributes jsonb - ); - -create unique index users_email_uindex on public.users (email); - -alter table public.users add constraint users_email unique (email); - -create table - researches ( - research_id text not null constraint research_pk primary key, - name text not null, - schema jsonb not null - ); - -create table - events ( - event_id text not null constraint events_pk primary key, - created_at timestamp, - user_id text constraint events_users_user_id_fk references users, - user_agent text, - content jsonb, - research_id text constraint events_researches_research_id_fk references researches - ); \ No newline at end of file diff --git a/internal/infra/resend.go b/internal/infra/resend.go index 3985913..2588c14 100644 --- a/internal/infra/resend.go +++ b/internal/infra/resend.go @@ -7,6 +7,5 @@ import ( ) func Resend(conf *appconfig.Config) *resend.Client { - client := resend.NewClient(conf.ResendApiKey) - return client + return resend.NewClient(conf.ResendApiKey) } diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index 2ddba91..a0b7995 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -6,6 +6,7 @@ import ( "github.com/gofiber/fiber/v2" "go.uber.org/fx" + "exusiai.dev/roguestats-backend/internal/appcontext" "exusiai.dev/roguestats-backend/internal/service" ) @@ -17,8 +18,9 @@ type Middleware struct { func (m Middleware) CurrentUser() func(ctx *fiber.Ctx) error { return func(ctx *fiber.Ctx) error { - token := ctx.Get("Authorization") + token := ctx.Get(fiber.HeaderAuthorization) if token == "" { + // some routes don't require authentication so we just skip them return ctx.Next() } @@ -27,8 +29,16 @@ func (m Middleware) CurrentUser() func(ctx *fiber.Ctx) error { return fiber.NewError(fiber.StatusUnauthorized, "invalid token") } - ctx.Context().SetUserValue("currentUser", user) + ctx.Context().SetUserValue(appcontext.CtxKeyCurrentUser, user) return ctx.Next() } } + +func (m Middleware) InjectFiberCtx() func(ctx *fiber.Ctx) error { + return func(ctx *fiber.Ctx) error { + // inject fiber context into *fasthttp.RequestCtx + ctx.Context().SetUserValue(appcontext.CtxKeyFiberCtx, ctx) + return ctx.Next() + } +} diff --git a/internal/model/models_custom.go b/internal/model/models_custom.go new file mode 100644 index 0000000..4300cf0 --- /dev/null +++ b/internal/model/models_custom.go @@ -0,0 +1,7 @@ +package model + +type LoginInput struct { + Email string `json:"email"` + Password string `json:"password"` + TurnstileResponse string `json:"turnstileResponse"` +} diff --git a/internal/model/models_gen.go b/internal/model/models_gen.go index ce599d4..99c4227 100644 --- a/internal/model/models_gen.go +++ b/internal/model/models_gen.go @@ -2,48 +2,23 @@ package model -import ( - "time" -) - -type Node interface { - IsNode() - GetID() string -} - type CategoryCount struct { Category interface{} `json:"category"` Count int `json:"count"` } +type CreateEventInput struct { + UserAgent string `json:"userAgent"` + Content map[string]interface{} `json:"content"` + ResearchID string `json:"researchID"` +} + type CreateUserInput struct { Name string `json:"name"` Email string `json:"email"` Attributes map[string]interface{} `json:"attributes,omitempty"` } -type Event struct { - ID string `json:"id" bun:"event_id"` - ResearchID string `json:"researchId" bun:"research_id"` - Content map[string]interface{} `json:"content"` - UserID string `json:"userId" bun:"user_id"` - CreatedAt time.Time `json:"createdAt"` - UserAgent *string `json:"userAgent,omitempty"` -} - -func (Event) IsNode() {} -func (this Event) GetID() string { return this.ID } - -type EventsConnection struct { - Edges []*EventsEdge `json:"edges"` - PageInfo *PageInfo `json:"pageInfo"` -} - -type EventsEdge struct { - Node *Event `json:"node"` - Cursor string `json:"cursor"` -} - type GroupCountInput struct { ResearchID string `json:"researchId"` FilterInput string `json:"filterInput"` @@ -54,54 +29,3 @@ type GroupCountResult struct { Results []*CategoryCount `json:"results"` Total int `json:"total"` } - -type LoginInput struct { - Email string `json:"email"` - Password string `json:"password"` - TurnstileResponse string `json:"turnstileResponse"` -} - -type NewEvent struct { - Content map[string]interface{} `json:"content"` - ResearchID string `json:"researchId"` - UserAgent *string `json:"userAgent,omitempty"` -} - -type PageInfo struct { - HasNextPage *bool `json:"hasNextPage,omitempty"` - HasPreviousPage *bool `json:"hasPreviousPage,omitempty"` - StartCursor string `json:"startCursor"` - EndCursor string `json:"endCursor"` -} - -type Research struct { - ID string `json:"id" bun:"research_id"` - Name string `json:"name"` - Schema map[string]interface{} `json:"schema"` - Event *Event `json:"event" bun:"-"` - Events *EventsConnection `json:"events,omitempty" bun:"-"` -} - -func (Research) IsNode() {} -func (this Research) GetID() string { return this.ID } - -type Topic struct { - ID string `json:"id" bun:"topic_id"` - FilterInput string `json:"filterInput"` - ResultMappingInput string `json:"resultMappingInput"` -} - -func (Topic) IsNode() {} -func (this Topic) GetID() string { return this.ID } - -type User struct { - ID string `json:"id" bun:"user_id"` - Name string `json:"name"` - Email *string `json:"email,omitempty"` - Attributes map[string]interface{} `json:"attributes,omitempty"` - // User's encrypted credential - Credential string `json:"-"` -} - -func (User) IsNode() {} -func (this User) GetID() string { return this.ID } diff --git a/internal/model/stub.go b/internal/model/stub.go deleted file mode 100644 index 8b53790..0000000 --- a/internal/model/stub.go +++ /dev/null @@ -1 +0,0 @@ -package model diff --git a/internal/repo/0module.go b/internal/repo/0module.go deleted file mode 100644 index fe2623f..0000000 --- a/internal/repo/0module.go +++ /dev/null @@ -1,9 +0,0 @@ -package repo - -import ( - "go.uber.org/fx" -) - -func Module() fx.Option { - return fx.Module("repo", fx.Populate(&User{})) -} diff --git a/internal/repo/event.go b/internal/repo/event.go deleted file mode 100644 index 6c8daba..0000000 --- a/internal/repo/event.go +++ /dev/null @@ -1,71 +0,0 @@ -package repo - -import ( - "context" - - "github.com/uptrace/bun" - "go.uber.org/fx" - - "exusiai.dev/roguestats-backend/internal/model" -) - -type Event struct { - fx.In - - DB *bun.DB -} - -func (r *Event) CreateEvent(ctx context.Context, event *model.Event) error { - _, err := r.DB.NewInsert().Model(event).Exec(ctx) - return err -} - -func (r *Event) GetEvent(ctx context.Context, eventID string) (*model.Event, error) { - var event model.Event - - err := r.DB.NewSelect(). - Model(&event). - Where("event_id = ?", eventID). - Scan(ctx) - - return &event, err -} - -func (r *Event) GetEvents(ctx context.Context) ([]*model.Event, error) { - var events []*model.Event - - err := r.DB.NewSelect(). - Model(&events). - Scan(ctx) - - return events, err -} - -func (r *Event) GetEventsByResearchID(ctx context.Context, researchID string) ([]*model.Event, error) { - var events []*model.Event - - err := r.DB.NewSelect(). - Model(&events). - Where("research_id = ?", researchID). - Scan(ctx) - - return events, err -} - -func (r *Event) GetPaginatedEventsByResearchID(ctx context.Context, researchID string, first int, after string) ([]*model.Event, error) { - var events []*model.Event - - query := r.DB.NewSelect().Model(&events) - if researchID != "" { - query = query.Where("research_id = ?", researchID) - } - if after != "" { - query = query.Where("event_id > ?", after) - } - - err := query. - Order("event_id ASC"). - Limit(first). - Scan(ctx) - return events, err -} diff --git a/internal/repo/research.go b/internal/repo/research.go deleted file mode 100644 index 11d20f6..0000000 --- a/internal/repo/research.go +++ /dev/null @@ -1,37 +0,0 @@ -package repo - -import ( - "context" - - "github.com/uptrace/bun" - "go.uber.org/fx" - - "exusiai.dev/roguestats-backend/internal/model" -) - -type Research struct { - fx.In - - DB *bun.DB -} - -func (r *Research) GetAllResearch(ctx context.Context) ([]*model.Research, error) { - var research []*model.Research - - err := r.DB.NewSelect(). - Model(&research). - Scan(ctx) - - return research, err -} - -func (r *Research) GetResearchByID(ctx context.Context, id string) (*model.Research, error) { - var research model.Research - - err := r.DB.NewSelect(). - Model(&research). - Where("research_id = ?", id). - Scan(ctx) - - return &research, err -} diff --git a/internal/repo/user.go b/internal/repo/user.go deleted file mode 100644 index b28d39d..0000000 --- a/internal/repo/user.go +++ /dev/null @@ -1,56 +0,0 @@ -package repo - -import ( - "context" - - "github.com/uptrace/bun" - "go.uber.org/fx" - - "exusiai.dev/roguestats-backend/internal/model" -) - -type User struct { - fx.In - - DB *bun.DB -} - -func (r *User) GetUserByID(ctx context.Context, id string) (*model.User, error) { - var user model.User - - err := r.DB.NewSelect(). - Model(&user). - Where("user_id = ?", id). - Scan(ctx) - - return &user, err -} - -func (r *User) GetUserByEmail(ctx context.Context, email string) (*model.User, error) { - var user model.User - - err := r.DB.NewSelect(). - Model(&user). - Where("email = ?", email). - Scan(ctx) - - return &user, err -} - -func (r *User) GetUsers(ctx context.Context) ([]*model.User, error) { - var users []*model.User - - err := r.DB.NewSelect(). - Model(&users). - Scan(ctx) - - return users, err -} - -func (r *User) CreateUser(ctx context.Context, user *model.User) error { - _, err := r.DB.NewInsert(). - Model(user). - Exec(ctx) - - return err -} diff --git a/internal/research/schema/battle.schema.json b/internal/research/schema/battle.schema.json index 4cb975f..36a3639 100644 --- a/internal/research/schema/battle.schema.json +++ b/internal/research/schema/battle.schema.json @@ -1,6 +1,6 @@ { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://penguin-stats.io/roguestats/battle.schema.json", + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://rogue.penguin-stats.io/_/schema/research/battle", "title": "作战节点", "type": "object", "additionalProperties": false, @@ -152,7 +152,7 @@ "title": "掉落招募券", "description": "若藏品有电台,请留空不填;一个【招募券掉落框】内若为二选一,请同时选择两项;如果没有第二个【招募券掉落框】,第二个请留空", "type": "array", - "minItems": 2, + "minItems": 0, "maxItems": 2, "items": { "type": "array", @@ -241,7 +241,7 @@ "title": "掉落密文板", "description": "若藏品有伶牙毁林者,请留空不填;请同时把两个选项都选上", "type": "array", - "minItems": 0, + "minItems": 1, "maxItems": 3, "uniqueItems": true, "items": { diff --git a/internal/research/schema/incident.schema.json b/internal/research/schema/incident.schema.json index cf6bb15..e191f5b 100644 --- a/internal/research/schema/incident.schema.json +++ b/internal/research/schema/incident.schema.json @@ -1,6 +1,6 @@ { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://penguin-stats.io/roguestats/incident.schema.json", + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://rogue.penguin-stats.io/_/schema/research/incident", "title": "不期而遇", "type": "object", "additionalProperties": false, diff --git a/internal/research/schema/portal.schema.json b/internal/research/schema/portal.schema.json index 8674641..9f2a475 100644 --- a/internal/research/schema/portal.schema.json +++ b/internal/research/schema/portal.schema.json @@ -1,6 +1,6 @@ { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://penguin-stats.io/roguestats/portal.schema.json", + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://rogue.penguin-stats.io/_/schema/research/portal", "title": "Portal", "type": "object", "additionalProperties": false, diff --git a/internal/research/schema/rest.schema.json b/internal/research/schema/rest.schema.json index 830121a..9fcec9f 100644 --- a/internal/research/schema/rest.schema.json +++ b/internal/research/schema/rest.schema.json @@ -1,6 +1,6 @@ { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://penguin-stats.io/roguestats/rest.schema.json", + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://rogue.penguin-stats.io/_/schema/research/rest", "title": "安全屋", "type": "object", "additionalProperties": false, diff --git a/internal/service/0module.go b/internal/service/0module.go index 4321616..905380e 100644 --- a/internal/service/0module.go +++ b/internal/service/0module.go @@ -6,10 +6,6 @@ import ( func Module() fx.Option { return fx.Module("service", - fx.Populate(&Auth{}), - fx.Populate(&User{}), fx.Provide(NewJWT), - fx.Provide(NewTurnstile), - fx.Populate(&Event{}), - fx.Populate(&Directive{})) + fx.Provide(NewTurnstile)) } diff --git a/internal/service/auth.go b/internal/service/auth.go index 4345c35..6e1a518 100644 --- a/internal/service/auth.go +++ b/internal/service/auth.go @@ -6,7 +6,6 @@ import ( "encoding/base64" "time" - "github.com/gofiber/fiber/v2" "github.com/pkg/errors" "github.com/vektah/gqlparser/v2/gqlerror" "go.uber.org/fx" @@ -15,27 +14,30 @@ import ( "exusiai.dev/roguestats-backend/internal/app/appconfig" "exusiai.dev/roguestats-backend/internal/appcontext" "exusiai.dev/roguestats-backend/internal/blob" + "exusiai.dev/roguestats-backend/internal/ent" + "exusiai.dev/roguestats-backend/internal/ent/user" "exusiai.dev/roguestats-backend/internal/model" - "exusiai.dev/roguestats-backend/internal/repo" ) type Auth struct { fx.In Config *appconfig.Config - UserRepo repo.User + Ent *ent.Client JWT JWT Turnstile Turnstile MailService Mail } -func (s Auth) AuthByLoginInput(ctx context.Context, args model.LoginInput) (*model.User, error) { +func (s Auth) AuthByLoginInput(ctx context.Context, args model.LoginInput) (*ent.User, error) { err := s.Turnstile.Verify(ctx, args.TurnstileResponse, "login") if err != nil { return nil, gqlerror.Errorf("captcha verification failed: invalid turnstile response") } - user, err := s.UserRepo.GetUserByEmail(ctx, args.Email) + user, err := s.Ent.User.Query(). + Where(user.Email(args.Email)). + First(ctx) if err != nil { return nil, err } @@ -53,7 +55,7 @@ func (s Auth) AuthByLoginInput(ctx context.Context, args model.LoginInput) (*mod return user, err } -func (s Auth) AuthByToken(ctx context.Context, token string) (*model.User, error) { +func (s Auth) AuthByToken(ctx context.Context, token string) (*ent.User, error) { userId, expireAt, err := s.JWT.Verify(token) if err != nil { return nil, err @@ -61,41 +63,41 @@ func (s Auth) AuthByToken(ctx context.Context, token string) (*model.User, error // auto renew token if time.Until(expireAt) < s.Config.JWTAutoRenewalTime { - err = s.SetUserToken(ctx, &model.User{ID: userId}) + err = s.SetUserToken(ctx, &ent.User{ID: userId}) if err != nil { return nil, err } } - return s.UserRepo.GetUserByID(ctx, userId) + return s.Ent.User.Get(ctx, userId) } -func (s Auth) CreateUser(ctx context.Context, args model.CreateUserInput) (*model.User, error) { - var randomBytes [32]byte +func (s Auth) CreateUser(ctx context.Context, args model.CreateUserInput) (*ent.User, error) { + var randomBytes [16]byte _, err := rand.Read(randomBytes[:]) if err != nil { return nil, err } randomString := base64.RawURLEncoding.EncodeToString(randomBytes[:]) - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(randomString), 14) + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(randomString), 12) if err != nil { return nil, err } - user := &model.User{ - Name: args.Name, - Email: &args.Email, - Attributes: args.Attributes, - Credential: string(hashedPassword), - } + client := ent.FromContext(ctx) - err = s.UserRepo.CreateUser(ctx, user) + user, err := client.User.Create(). + SetName(args.Name). + SetEmail(args.Email). + SetAttributes(args.Attributes). + SetCredential(string(hashedPassword)). + Save(ctx) if err != nil { return nil, err } - rendered, err := blob.RenderPair("password-generated", map[string]interface{}{ + rendered, err := blob.RenderPair("password-generated", map[string]any{ "Username": user.Name, "Email": user.Email, "Password": randomString, @@ -105,7 +107,7 @@ func (s Auth) CreateUser(ctx context.Context, args model.CreateUserInput) (*mode } _, err = s.MailService.Send(&SendEmailRequest{ - To: []string{*user.Email}, + To: []string{user.Email}, Subject: "你的 RogueStats 登录信息已准备就绪", Html: rendered.HTML, Text: rendered.Text, @@ -117,7 +119,7 @@ func (s Auth) CreateUser(ctx context.Context, args model.CreateUserInput) (*mode return user, err } -func (s Auth) CurrentUser(ctx context.Context) (*model.User, error) { +func (s Auth) CurrentUser(ctx context.Context) (*ent.User, error) { user := appcontext.CurrentUser(ctx) if user != nil { return user, nil @@ -126,8 +128,8 @@ func (s Auth) CurrentUser(ctx context.Context) (*model.User, error) { return nil, errors.New("you are not logged in") } -func (s Auth) SetUserToken(ctx context.Context, user *model.User) error { - fiberCtx := ctx.Value("fiberCtx").(*fiber.Ctx) +func (s Auth) SetUserToken(ctx context.Context, user *ent.User) error { + fiberCtx := appcontext.FiberCtx(ctx) token, err := s.JWT.Sign(user.ID) if err != nil { diff --git a/internal/service/directive.go b/internal/service/directive.go index df4251d..80a3885 100644 --- a/internal/service/directive.go +++ b/internal/service/directive.go @@ -6,6 +6,7 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/rs/zerolog/log" + "github.com/vektah/gqlparser/v2/gqlerror" "go.uber.org/fx" "exusiai.dev/roguestats-backend/internal/appcontext" @@ -13,24 +14,21 @@ import ( type Directive struct { fx.In - - User User } // Admin directive is used to check if the current user is an admin. -// if not, return null for the field. +// if not, return error. func (s Directive) Admin(ctx context.Context, obj any, next graphql.Resolver) (res any, err error) { currentUser := appcontext.CurrentUser(ctx) if currentUser == nil { - // for anonymous user, return null as well - return nil, nil + return nil, gqlerror.Errorf("You must be logged in to access this resource") } - if currentUser.Attributes["admin"] == true { + if currentUser.Attributes["role"] == "admin" { return next(ctx) } - return nil, nil + return nil, gqlerror.Errorf("You must be an admin to access this resource") } // Private directive is used to check if the current user is the owner of the object. diff --git a/internal/service/event.go b/internal/service/event.go index 4c2006b..21af664 100644 --- a/internal/service/event.go +++ b/internal/service/event.go @@ -7,89 +7,61 @@ import ( "fmt" "reflect" "sort" - "strings" - "time" - "github.com/oklog/ulid/v2" "github.com/pkg/errors" "github.com/santhosh-tekuri/jsonschema/v5" "go.uber.org/fx" - "exusiai.dev/roguestats-backend/internal/cursorutils" + "exusiai.dev/roguestats-backend/internal/ent" + "exusiai.dev/roguestats-backend/internal/ent/event" + "exusiai.dev/roguestats-backend/internal/ent/research" "exusiai.dev/roguestats-backend/internal/exprutils" "exusiai.dev/roguestats-backend/internal/model" - "exusiai.dev/roguestats-backend/internal/repo" ) type Event struct { fx.In - EventRepo repo.Event - ResearchService Research - AuthService Auth + Ent *ent.Client + AuthService Auth } -func (s Event) CreateEvent(ctx context.Context, event *model.Event) error { - return s.EventRepo.CreateEvent(ctx, event) -} - -func (s Event) GetEvent(ctx context.Context, eventID string) (*model.Event, error) { - return s.EventRepo.GetEvent(ctx, eventID) -} - -func (s Event) GetEvents(ctx context.Context) ([]*model.Event, error) { - return s.EventRepo.GetEvents(ctx) -} - -func (s Event) GetEventsByResearchID(ctx context.Context, researchID string) ([]*model.Event, error) { - return s.EventRepo.GetEventsByResearchID(ctx, researchID) -} +func (s Event) CreateEventFromInput(ctx context.Context, input model.CreateEventInput) (*ent.Event, error) { + client := ent.FromContext(ctx) -func (s Event) CreateEventFromInput(ctx context.Context, input *model.NewEvent) (*model.Event, error) { - event, err := s.convertFromEventInputToEvent(ctx, input) + user, err := s.AuthService.CurrentUser(ctx) if err != nil { return nil, err } - err = s.CreateEvent(ctx, event) + + // get schema from research + research, err := client.Research.Get(ctx, input.ResearchID) if err != nil { + if err == sql.ErrNoRows { + return nil, errors.New("research not found") + } return nil, err } - return event, nil -} -func (s Event) GetPaginatedEvents(ctx context.Context, researchID string, first int, after string) (*model.EventsConnection, error) { - events, err := s.EventRepo.GetPaginatedEventsByResearchID(ctx, researchID, first+1, after) + // validate event json + schema, err := json.Marshal(research.Schema) if err != nil { return nil, err } - - hasNextPage := len(events) > first - hasPreviousPage := after != "" - if len(events) > first { - events = events[:len(events)-1] - } - - eventsConnection := &model.EventsConnection{ - Edges: make([]*model.EventsEdge, 0, len(events)), - PageInfo: &model.PageInfo{ - HasNextPage: &hasNextPage, - HasPreviousPage: &hasPreviousPage, - }, - } - for _, event := range events { - eventsConnection.Edges = append(eventsConnection.Edges, &model.EventsEdge{ - Node: event, - Cursor: cursorutils.EncodeCursor(event.ID), - }) + sch, err := jsonschema.CompileString("schema.json", string(schema)) + if err != nil { + return nil, err } - - // decide StartCursor and EndCursor - if len(events) > 0 { - eventsConnection.PageInfo.StartCursor = cursorutils.EncodeCursor(events[0].ID) - eventsConnection.PageInfo.EndCursor = cursorutils.EncodeCursor(events[len(events)-1].ID) + if err = sch.Validate(input.Content); err != nil { + return nil, err } - return eventsConnection, nil + return client.Event.Create(). + SetContent(input.Content). + SetUserAgent(input.UserAgent). + SetResearchID(input.ResearchID). + SetUserID(user.ID). + Save(ctx) } /** @@ -104,7 +76,7 @@ func (s Event) CalculateStats(ctx context.Context, researchID string, filterInpu return nil, err } - categoryCountMap := make(map[interface{}]int) + categoryCountMap := make(map[any]int) totalCount := 0 for _, event := range filteredEvents { @@ -147,8 +119,10 @@ func (s Event) CalculateStats(ctx context.Context, researchID string, filterInpu * In the future, we should implement a filter that can be translated into a SQL query. * @param {string} filterInput For current implementation, we use expr */ -func (s Event) getEventsWithFilter(ctx context.Context, researchID string, filterInput string) ([]*model.Event, error) { - events, err := s.GetEventsByResearchID(ctx, researchID) +func (s Event) getEventsWithFilter(ctx context.Context, researchID string, filterInput string) ([]*ent.Event, error) { + events, err := s.Ent.Event.Query(). + Where(event.HasResearchWith(research.ID(researchID))). + All(ctx) if err != nil { return nil, err } @@ -156,7 +130,7 @@ func (s Event) getEventsWithFilter(ctx context.Context, researchID string, filte return events, nil } exprRunner := exprutils.GetExprRunner() - filteredEvents := make([]*model.Event, 0) + filteredEvents := make([]*ent.Event, 0) for _, event := range events { output, err := exprRunner.RunCode(filterInput, exprRunner.PrepareEnv(event)) if err != nil { @@ -172,7 +146,7 @@ func (s Event) getEventsWithFilter(ctx context.Context, researchID string, filte return filteredEvents, nil } -func (s Event) mapEventToResult(event *model.Event, resultMappingInput string) ([]interface{}, error) { +func (s Event) mapEventToResult(event *ent.Event, resultMappingInput string) ([]any, error) { exprRunner := exprutils.GetExprRunner() output, err := exprRunner.RunCode(resultMappingInput, exprRunner.PrepareEnv(event)) if err != nil { @@ -182,9 +156,9 @@ func (s Event) mapEventToResult(event *model.Event, resultMappingInput string) ( return nil, nil } - mappedResults := make([]interface{}, 0) + mappedResults := make([]any, 0) if isArray(output) { - mappedResults = output.([]interface{}) + mappedResults = output.([]any) } else { mappedResults = append(mappedResults, output) } @@ -198,46 +172,7 @@ func (s Event) mapEventToResult(event *model.Event, resultMappingInput string) ( return mappedResults, nil } -func (s Event) convertFromEventInputToEvent(ctx context.Context, input *model.NewEvent) (*model.Event, error) { - user, err := s.AuthService.CurrentUser(ctx) - if err != nil { - return nil, err - } - - // get schema from research - research, err := s.ResearchService.GetResearchByID(ctx, input.ResearchID) - if err != nil { - if err == sql.ErrNoRows { - return nil, errors.New("research not found") - } - return nil, err - } - - // validate event json - schema, err := json.Marshal(research.Schema) - if err != nil { - return nil, err - } - sch, err := jsonschema.CompileString("schema.json", string(schema)) - if err != nil { - return nil, err - } - if err = sch.Validate(input.Content); err != nil { - return nil, err - } - - event := &model.Event{ - ID: strings.ToLower(ulid.Make().String()), - ResearchID: input.ResearchID, - Content: input.Content, - UserID: user.ID, - CreatedAt: time.Now(), - UserAgent: input.UserAgent, - } - return event, nil -} - -func isHashable(v interface{}) bool { +func isHashable(v any) bool { switch reflect.TypeOf(v).Kind() { case reflect.Slice, reflect.Map, reflect.Func: return false @@ -246,7 +181,7 @@ func isHashable(v interface{}) bool { } } -func isArray(input interface{}) bool { +func isArray(input any) bool { kind := reflect.TypeOf(input).Kind() return kind == reflect.Array || kind == reflect.Slice } diff --git a/internal/service/research.go b/internal/service/research.go deleted file mode 100644 index ffd3ae2..0000000 --- a/internal/service/research.go +++ /dev/null @@ -1,24 +0,0 @@ -package service - -import ( - "context" - - "go.uber.org/fx" - - "exusiai.dev/roguestats-backend/internal/model" - "exusiai.dev/roguestats-backend/internal/repo" -) - -type Research struct { - fx.In - - ResearchRepo repo.Research -} - -func (s Research) GetAllResearch(ctx context.Context) ([]*model.Research, error) { - return s.ResearchRepo.GetAllResearch(ctx) -} - -func (s Research) GetResearchByID(ctx context.Context, id string) (*model.Research, error) { - return s.ResearchRepo.GetResearchByID(ctx, id) -} diff --git a/internal/service/user.go b/internal/service/user.go deleted file mode 100644 index 0fee364..0000000 --- a/internal/service/user.go +++ /dev/null @@ -1,20 +0,0 @@ -package service - -import ( - "context" - - "go.uber.org/fx" - - "exusiai.dev/roguestats-backend/internal/model" - "exusiai.dev/roguestats-backend/internal/repo" -) - -type User struct { - fx.In - - UserRepo repo.User -} - -func (s User) GetUsers(ctx context.Context) ([]*model.User, error) { - return s.UserRepo.GetUsers(ctx) -} diff --git a/internal/x/entid/entid.go b/internal/x/entid/entid.go new file mode 100644 index 0000000..9d435d5 --- /dev/null +++ b/internal/x/entid/entid.go @@ -0,0 +1,22 @@ +package entid + +import ( + "strings" + + "github.com/oklog/ulid/v2" +) + +func New(entity string) string { + return entity + "_" + strings.ToLower(ulid.Make().String()) +} + +func NewGenerator(entity string) func() string { + return func() string { + return New(entity) + } +} + +var ( + User = NewGenerator("usr") + Event = NewGenerator("evt") +)