From 568ab1679521a68393e17393fe27e5e269e29c18 Mon Sep 17 00:00:00 2001 From: pilyang Date: Sat, 15 Feb 2025 22:59:00 +0900 Subject: [PATCH 1/6] feat: add postings model --- ent/schema/company.go | 5 ++++- ent/schema/posting.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 ent/schema/posting.go diff --git a/ent/schema/company.go b/ent/schema/company.go index f027af7..648b45a 100644 --- a/ent/schema/company.go +++ b/ent/schema/company.go @@ -4,6 +4,7 @@ import ( "net/url" "entgo.io/ent" + "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" "entgo.io/ent/schema/mixin" ) @@ -37,5 +38,7 @@ func (Company) Fields() []ent.Field { // Edges of the Company. func (Company) Edges() []ent.Edge { - return nil + return []ent.Edge{ + edge.To("postings", Posting.Type), + } } diff --git a/ent/schema/posting.go b/ent/schema/posting.go new file mode 100644 index 0000000..08177f5 --- /dev/null +++ b/ent/schema/posting.go @@ -0,0 +1,43 @@ +package schema + +import ( + "net/url" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + + "github.com/techbloghub/server/internal/schemasupport" +) + +// Posting holds the schema definition for the Posting entity. +type Posting struct { + ent.Schema +} + +// Fields of the Posting. +func (Posting) Fields() []ent.Field { + return []ent.Field{ + field.String("title"), + field.String("url"). + GoType(&url.URL{}). + ValueScanner(field.BinaryValueScanner[*url.URL]{}). + Unique(), + field.Time("published_at"), + field.Other("tags", &schemasupport.PostingTags{}). + SchemaType(map[string]string{ + dialect.Postgres: "text[]", + }). + Optional(), + } +} + +// Edges of the Posting. +func (Posting) Edges() []ent.Edge { + return []ent.Edge{ + edge.From("company", Company.Type). + Ref("postings"). + Unique(), + } +} From 8cc47dab366e442b96ab225093769eeefecbc57d Mon Sep 17 00:00:00 2001 From: pilyang Date: Sat, 15 Feb 2025 22:59:12 +0900 Subject: [PATCH 2/6] chore: generated by ent --- ent/client.go | 180 ++++++- ent/company.go | 28 +- ent/company/company.go | 31 ++ ent/company/where.go | 24 + ent/company_create.go | 32 ++ ent/company_query.go | 102 +++- ent/company_update.go | 163 ++++++ ent/ent.go | 2 + ent/hook/hook.go | 12 + ent/intercept/intercept.go | 30 ++ ent/internal/schema.go | 2 +- ent/migrate/schema.go | 25 + ent/mutation.go | 707 ++++++++++++++++++++++++- ent/posting.go | 184 +++++++ ent/posting/posting.go | 116 ++++ ent/posting/where.go | 387 ++++++++++++++ ent/posting_create.go | 269 ++++++++++ ent/posting_delete.go | 88 +++ ent/posting_query.go | 614 +++++++++++++++++++++ ent/posting_update.go | 417 +++++++++++++++ ent/predicate/predicate.go | 14 + ent/runtime/runtime.go | 6 + ent/tx.go | 3 + internal/schemasupport/posting_tags.go | 17 + 24 files changed, 3421 insertions(+), 32 deletions(-) create mode 100644 ent/posting.go create mode 100644 ent/posting/posting.go create mode 100644 ent/posting/where.go create mode 100644 ent/posting_create.go create mode 100644 ent/posting_delete.go create mode 100644 ent/posting_query.go create mode 100644 ent/posting_update.go create mode 100644 internal/schemasupport/posting_tags.go diff --git a/ent/client.go b/ent/client.go index f1b2464..ceaef65 100644 --- a/ent/client.go +++ b/ent/client.go @@ -14,7 +14,9 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect" "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" "github.com/techbloghub/server/ent/tag" ) @@ -25,6 +27,8 @@ type Client struct { Schema *migrate.Schema // Company is the client for interacting with the Company builders. Company *CompanyClient + // Posting is the client for interacting with the Posting builders. + Posting *PostingClient // Tag is the client for interacting with the Tag builders. Tag *TagClient } @@ -39,6 +43,7 @@ func NewClient(opts ...Option) *Client { func (c *Client) init() { c.Schema = migrate.NewSchema(c.driver) c.Company = NewCompanyClient(c.config) + c.Posting = NewPostingClient(c.config) c.Tag = NewTagClient(c.config) } @@ -133,6 +138,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { ctx: ctx, config: cfg, Company: NewCompanyClient(cfg), + Posting: NewPostingClient(cfg), Tag: NewTagClient(cfg), }, nil } @@ -154,6 +160,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) ctx: ctx, config: cfg, Company: NewCompanyClient(cfg), + Posting: NewPostingClient(cfg), Tag: NewTagClient(cfg), }, nil } @@ -184,6 +191,7 @@ func (c *Client) Close() error { // In order to add hooks to a specific client, call: `client.Node.Use(...)`. func (c *Client) Use(hooks ...Hook) { c.Company.Use(hooks...) + c.Posting.Use(hooks...) c.Tag.Use(hooks...) } @@ -191,6 +199,7 @@ func (c *Client) Use(hooks ...Hook) { // In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`. func (c *Client) Intercept(interceptors ...Interceptor) { c.Company.Intercept(interceptors...) + c.Posting.Intercept(interceptors...) c.Tag.Intercept(interceptors...) } @@ -199,6 +208,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { switch m := m.(type) { case *CompanyMutation: return c.Company.mutate(ctx, m) + case *PostingMutation: + return c.Posting.mutate(ctx, m) case *TagMutation: return c.Tag.mutate(ctx, m) default: @@ -314,6 +325,22 @@ func (c *CompanyClient) GetX(ctx context.Context, id int) *Company { return obj } +// QueryPostings queries the postings edge of a Company. +func (c *CompanyClient) QueryPostings(co *Company) *PostingQuery { + query := (&PostingClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := co.ID + step := sqlgraph.NewStep( + sqlgraph.From(company.Table, company.FieldID, id), + sqlgraph.To(posting.Table, posting.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, company.PostingsTable, company.PostingsColumn), + ) + fromV = sqlgraph.Neighbors(co.driver.Dialect(), step) + return fromV, nil + } + return query +} + // Hooks returns the client hooks. func (c *CompanyClient) Hooks() []Hook { hooks := c.hooks.Company @@ -341,6 +368,155 @@ func (c *CompanyClient) mutate(ctx context.Context, m *CompanyMutation) (Value, } } +// PostingClient is a client for the Posting schema. +type PostingClient struct { + config +} + +// NewPostingClient returns a client for the Posting from the given config. +func NewPostingClient(c config) *PostingClient { + return &PostingClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `posting.Hooks(f(g(h())))`. +func (c *PostingClient) Use(hooks ...Hook) { + c.hooks.Posting = append(c.hooks.Posting, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `posting.Intercept(f(g(h())))`. +func (c *PostingClient) Intercept(interceptors ...Interceptor) { + c.inters.Posting = append(c.inters.Posting, interceptors...) +} + +// Create returns a builder for creating a Posting entity. +func (c *PostingClient) Create() *PostingCreate { + mutation := newPostingMutation(c.config, OpCreate) + return &PostingCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of Posting entities. +func (c *PostingClient) CreateBulk(builders ...*PostingCreate) *PostingCreateBulk { + return &PostingCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *PostingClient) MapCreateBulk(slice any, setFunc func(*PostingCreate, int)) *PostingCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &PostingCreateBulk{err: fmt.Errorf("calling to PostingClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*PostingCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &PostingCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for Posting. +func (c *PostingClient) Update() *PostingUpdate { + mutation := newPostingMutation(c.config, OpUpdate) + return &PostingUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *PostingClient) UpdateOne(po *Posting) *PostingUpdateOne { + mutation := newPostingMutation(c.config, OpUpdateOne, withPosting(po)) + return &PostingUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *PostingClient) UpdateOneID(id int) *PostingUpdateOne { + mutation := newPostingMutation(c.config, OpUpdateOne, withPostingID(id)) + return &PostingUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for Posting. +func (c *PostingClient) Delete() *PostingDelete { + mutation := newPostingMutation(c.config, OpDelete) + return &PostingDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *PostingClient) DeleteOne(po *Posting) *PostingDeleteOne { + return c.DeleteOneID(po.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *PostingClient) DeleteOneID(id int) *PostingDeleteOne { + builder := c.Delete().Where(posting.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &PostingDeleteOne{builder} +} + +// Query returns a query builder for Posting. +func (c *PostingClient) Query() *PostingQuery { + return &PostingQuery{ + config: c.config, + ctx: &QueryContext{Type: TypePosting}, + inters: c.Interceptors(), + } +} + +// Get returns a Posting entity by its id. +func (c *PostingClient) Get(ctx context.Context, id int) (*Posting, error) { + return c.Query().Where(posting.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *PostingClient) GetX(ctx context.Context, id int) *Posting { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryCompany queries the company edge of a Posting. +func (c *PostingClient) QueryCompany(po *Posting) *CompanyQuery { + query := (&CompanyClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := po.ID + step := sqlgraph.NewStep( + sqlgraph.From(posting.Table, posting.FieldID, id), + sqlgraph.To(company.Table, company.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, posting.CompanyTable, posting.CompanyColumn), + ) + fromV = sqlgraph.Neighbors(po.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *PostingClient) Hooks() []Hook { + return c.hooks.Posting +} + +// Interceptors returns the client interceptors. +func (c *PostingClient) Interceptors() []Interceptor { + return c.inters.Posting +} + +func (c *PostingClient) mutate(ctx context.Context, m *PostingMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&PostingCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&PostingUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&PostingUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&PostingDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown Posting mutation op: %q", m.Op()) + } +} + // TagClient is a client for the Tag schema. type TagClient struct { config @@ -479,9 +655,9 @@ func (c *TagClient) mutate(ctx context.Context, m *TagMutation) (Value, error) { // hooks and interceptors per client, for fast access. type ( hooks struct { - Company, Tag []ent.Hook + Company, Posting, Tag []ent.Hook } inters struct { - Company, Tag []ent.Interceptor + Company, Posting, Tag []ent.Interceptor } ) diff --git a/ent/company.go b/ent/company.go index 197bba5..ca98fe6 100644 --- a/ent/company.go +++ b/ent/company.go @@ -31,10 +31,31 @@ type Company struct { // BlogURL holds the value of the "blog_url" field. BlogURL *url.URL `json:"blog_url,omitempty"` // RssURL holds the value of the "rss_url" field. - RssURL *url.URL `json:"rss_url,omitempty"` + RssURL *url.URL `json:"rss_url,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the CompanyQuery when eager-loading is set. + Edges CompanyEdges `json:"edges"` selectValues sql.SelectValues } +// CompanyEdges holds the relations/edges for other nodes in the graph. +type CompanyEdges struct { + // Postings holds the value of the postings edge. + Postings []*Posting `json:"postings,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [1]bool +} + +// PostingsOrErr returns the Postings value or an error if the edge +// was not loaded in eager-loading. +func (e CompanyEdges) PostingsOrErr() ([]*Posting, error) { + if e.loadedTypes[0] { + return e.Postings, nil + } + return nil, &NotLoadedError{edge: "postings"} +} + // scanValues returns the types for scanning values from sql.Rows. func (*Company) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) @@ -128,6 +149,11 @@ func (c *Company) Value(name string) (ent.Value, error) { return c.selectValues.Get(name) } +// QueryPostings queries the "postings" edge of the Company entity. +func (c *Company) QueryPostings() *PostingQuery { + return NewCompanyClient(c.config).QueryPostings(c) +} + // Update returns a builder for updating this Company. // Note that you need to call Company.Unwrap() before calling this method if this Company // was returned from a transaction, and the transaction was committed or rolled back. diff --git a/ent/company/company.go b/ent/company/company.go index ff7d1d1..2bc2c3e 100644 --- a/ent/company/company.go +++ b/ent/company/company.go @@ -8,6 +8,7 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" ) @@ -30,8 +31,17 @@ const ( FieldBlogURL = "blog_url" // FieldRssURL holds the string denoting the rss_url field in the database. FieldRssURL = "rss_url" + // EdgePostings holds the string denoting the postings edge name in mutations. + EdgePostings = "postings" // Table holds the table name of the company in the database. Table = "companies" + // PostingsTable is the table that holds the postings relation/edge. + PostingsTable = "postings" + // PostingsInverseTable is the table name for the Posting entity. + // It exists in this package in order to avoid circular dependency with the "posting" package. + PostingsInverseTable = "postings" + // PostingsColumn is the table column denoting the postings relation/edge. + PostingsColumn = "company_postings" ) // Columns holds all SQL columns for company fields. @@ -120,3 +130,24 @@ func ByBlogURL(opts ...sql.OrderTermOption) OrderOption { func ByRssURL(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldRssURL, opts...).ToFunc() } + +// ByPostingsCount orders the results by postings count. +func ByPostingsCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newPostingsStep(), opts...) + } +} + +// ByPostings orders the results by postings terms. +func ByPostings(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newPostingsStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} +func newPostingsStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(PostingsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, PostingsTable, PostingsColumn), + ) +} diff --git a/ent/company/where.go b/ent/company/where.go index f29e241..5aa401d 100644 --- a/ent/company/where.go +++ b/ent/company/where.go @@ -8,6 +8,7 @@ import ( "time" "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" "github.com/techbloghub/server/ent/predicate" ) @@ -631,6 +632,29 @@ func RssURLContainsFold(v *url.URL) predicate.Company { return predicate.CompanyOrErr(sql.FieldContainsFold(FieldRssURL, vcs), err) } +// HasPostings applies the HasEdge predicate on the "postings" edge. +func HasPostings() predicate.Company { + return predicate.Company(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, PostingsTable, PostingsColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasPostingsWith applies the HasEdge predicate on the "postings" edge with a given conditions (other predicates). +func HasPostingsWith(preds ...predicate.Posting) predicate.Company { + return predicate.Company(func(s *sql.Selector) { + step := newPostingsStep() + 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.Company) predicate.Company { return predicate.Company(sql.AndPredicates(predicates...)) diff --git a/ent/company_create.go b/ent/company_create.go index 6cc933b..a104ffd 100644 --- a/ent/company_create.go +++ b/ent/company_create.go @@ -12,6 +12,7 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" ) // CompanyCreate is the builder for creating a Company entity. @@ -87,6 +88,21 @@ func (cc *CompanyCreate) SetRssURL(u *url.URL) *CompanyCreate { return cc } +// AddPostingIDs adds the "postings" edge to the Posting entity by IDs. +func (cc *CompanyCreate) AddPostingIDs(ids ...int) *CompanyCreate { + cc.mutation.AddPostingIDs(ids...) + return cc +} + +// AddPostings adds the "postings" edges to the Posting entity. +func (cc *CompanyCreate) AddPostings(p ...*Posting) *CompanyCreate { + ids := make([]int, len(p)) + for i := range p { + ids[i] = p[i].ID + } + return cc.AddPostingIDs(ids...) +} + // Mutation returns the CompanyMutation object of the builder. func (cc *CompanyCreate) Mutation() *CompanyMutation { return cc.mutation @@ -230,6 +246,22 @@ func (cc *CompanyCreate) createSpec() (*Company, *sqlgraph.CreateSpec, error) { _spec.SetField(company.FieldRssURL, field.TypeString, vv) _node.RssURL = value } + if nodes := cc.mutation.PostingsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: company.PostingsTable, + Columns: []string{company.PostingsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } return _node, _spec, nil } diff --git a/ent/company_query.go b/ent/company_query.go index b5b3d74..fa486cb 100644 --- a/ent/company_query.go +++ b/ent/company_query.go @@ -4,6 +4,7 @@ package ent import ( "context" + "database/sql/driver" "fmt" "math" @@ -12,16 +13,18 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" "github.com/techbloghub/server/ent/predicate" ) // CompanyQuery is the builder for querying Company entities. type CompanyQuery struct { config - ctx *QueryContext - order []company.OrderOption - inters []Interceptor - predicates []predicate.Company + ctx *QueryContext + order []company.OrderOption + inters []Interceptor + predicates []predicate.Company + withPostings *PostingQuery // intermediate query (i.e. traversal path). sql *sql.Selector path func(context.Context) (*sql.Selector, error) @@ -58,6 +61,28 @@ func (cq *CompanyQuery) Order(o ...company.OrderOption) *CompanyQuery { return cq } +// QueryPostings chains the current query on the "postings" edge. +func (cq *CompanyQuery) QueryPostings() *PostingQuery { + query := (&PostingClient{config: cq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := cq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := cq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(company.Table, company.FieldID, selector), + sqlgraph.To(posting.Table, posting.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, company.PostingsTable, company.PostingsColumn), + ) + fromU = sqlgraph.SetNeighbors(cq.driver.Dialect(), step) + return fromU, nil + } + return query +} + // First returns the first Company entity from the query. // Returns a *NotFoundError when no Company was found. func (cq *CompanyQuery) First(ctx context.Context) (*Company, error) { @@ -245,17 +270,29 @@ func (cq *CompanyQuery) Clone() *CompanyQuery { return nil } return &CompanyQuery{ - config: cq.config, - ctx: cq.ctx.Clone(), - order: append([]company.OrderOption{}, cq.order...), - inters: append([]Interceptor{}, cq.inters...), - predicates: append([]predicate.Company{}, cq.predicates...), + config: cq.config, + ctx: cq.ctx.Clone(), + order: append([]company.OrderOption{}, cq.order...), + inters: append([]Interceptor{}, cq.inters...), + predicates: append([]predicate.Company{}, cq.predicates...), + withPostings: cq.withPostings.Clone(), // clone intermediate query. sql: cq.sql.Clone(), path: cq.path, } } +// WithPostings tells the query-builder to eager-load the nodes that are connected to +// the "postings" edge. The optional arguments are used to configure the query builder of the edge. +func (cq *CompanyQuery) WithPostings(opts ...func(*PostingQuery)) *CompanyQuery { + query := (&PostingClient{config: cq.config}).Query() + for _, opt := range opts { + opt(query) + } + cq.withPostings = query + return cq +} + // 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. // @@ -332,8 +369,11 @@ func (cq *CompanyQuery) prepareQuery(ctx context.Context) error { func (cq *CompanyQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Company, error) { var ( - nodes = []*Company{} - _spec = cq.querySpec() + nodes = []*Company{} + _spec = cq.querySpec() + loadedTypes = [1]bool{ + cq.withPostings != nil, + } ) _spec.ScanValues = func(columns []string) ([]any, error) { return (*Company).scanValues(nil, columns) @@ -341,6 +381,7 @@ func (cq *CompanyQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Comp _spec.Assign = func(columns []string, values []any) error { node := &Company{config: cq.config} nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes return node.assignValues(columns, values) } for i := range hooks { @@ -352,9 +393,48 @@ func (cq *CompanyQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Comp if len(nodes) == 0 { return nodes, nil } + if query := cq.withPostings; query != nil { + if err := cq.loadPostings(ctx, query, nodes, + func(n *Company) { n.Edges.Postings = []*Posting{} }, + func(n *Company, e *Posting) { n.Edges.Postings = append(n.Edges.Postings, e) }); err != nil { + return nil, err + } + } return nodes, nil } +func (cq *CompanyQuery) loadPostings(ctx context.Context, query *PostingQuery, nodes []*Company, init func(*Company), assign func(*Company, *Posting)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[int]*Company) + 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.Posting(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(company.PostingsColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.company_postings + if fk == nil { + return fmt.Errorf(`foreign-key "company_postings" is nil for node %v`, n.ID) + } + node, ok := nodeids[*fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "company_postings" returned %v for node %v`, *fk, n.ID) + } + assign(node, n) + } + return nil +} + func (cq *CompanyQuery) sqlCount(ctx context.Context) (int, error) { _spec := cq.querySpec() _spec.Node.Columns = cq.ctx.Fields diff --git a/ent/company_update.go b/ent/company_update.go index 3c7817a..da1a88f 100644 --- a/ent/company_update.go +++ b/ent/company_update.go @@ -13,6 +13,7 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" "github.com/techbloghub/server/ent/predicate" ) @@ -87,11 +88,47 @@ func (cu *CompanyUpdate) SetRssURL(u *url.URL) *CompanyUpdate { return cu } +// AddPostingIDs adds the "postings" edge to the Posting entity by IDs. +func (cu *CompanyUpdate) AddPostingIDs(ids ...int) *CompanyUpdate { + cu.mutation.AddPostingIDs(ids...) + return cu +} + +// AddPostings adds the "postings" edges to the Posting entity. +func (cu *CompanyUpdate) AddPostings(p ...*Posting) *CompanyUpdate { + ids := make([]int, len(p)) + for i := range p { + ids[i] = p[i].ID + } + return cu.AddPostingIDs(ids...) +} + // Mutation returns the CompanyMutation object of the builder. func (cu *CompanyUpdate) Mutation() *CompanyMutation { return cu.mutation } +// ClearPostings clears all "postings" edges to the Posting entity. +func (cu *CompanyUpdate) ClearPostings() *CompanyUpdate { + cu.mutation.ClearPostings() + return cu +} + +// RemovePostingIDs removes the "postings" edge to Posting entities by IDs. +func (cu *CompanyUpdate) RemovePostingIDs(ids ...int) *CompanyUpdate { + cu.mutation.RemovePostingIDs(ids...) + return cu +} + +// RemovePostings removes "postings" edges to Posting entities. +func (cu *CompanyUpdate) RemovePostings(p ...*Posting) *CompanyUpdate { + ids := make([]int, len(p)) + for i := range p { + ids[i] = p[i].ID + } + return cu.RemovePostingIDs(ids...) +} + // Save executes the query and returns the number of nodes affected by the update operation. func (cu *CompanyUpdate) Save(ctx context.Context) (int, error) { if err := cu.defaults(); err != nil { @@ -176,6 +213,51 @@ func (cu *CompanyUpdate) sqlSave(ctx context.Context) (n int, err error) { } _spec.SetField(company.FieldRssURL, field.TypeString, vv) } + if cu.mutation.PostingsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: company.PostingsTable, + Columns: []string{company.PostingsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := cu.mutation.RemovedPostingsIDs(); len(nodes) > 0 && !cu.mutation.PostingsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: company.PostingsTable, + Columns: []string{company.PostingsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := cu.mutation.PostingsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: company.PostingsTable, + Columns: []string{company.PostingsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt), + }, + } + 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, cu.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { err = &NotFoundError{company.Label} @@ -254,11 +336,47 @@ func (cuo *CompanyUpdateOne) SetRssURL(u *url.URL) *CompanyUpdateOne { return cuo } +// AddPostingIDs adds the "postings" edge to the Posting entity by IDs. +func (cuo *CompanyUpdateOne) AddPostingIDs(ids ...int) *CompanyUpdateOne { + cuo.mutation.AddPostingIDs(ids...) + return cuo +} + +// AddPostings adds the "postings" edges to the Posting entity. +func (cuo *CompanyUpdateOne) AddPostings(p ...*Posting) *CompanyUpdateOne { + ids := make([]int, len(p)) + for i := range p { + ids[i] = p[i].ID + } + return cuo.AddPostingIDs(ids...) +} + // Mutation returns the CompanyMutation object of the builder. func (cuo *CompanyUpdateOne) Mutation() *CompanyMutation { return cuo.mutation } +// ClearPostings clears all "postings" edges to the Posting entity. +func (cuo *CompanyUpdateOne) ClearPostings() *CompanyUpdateOne { + cuo.mutation.ClearPostings() + return cuo +} + +// RemovePostingIDs removes the "postings" edge to Posting entities by IDs. +func (cuo *CompanyUpdateOne) RemovePostingIDs(ids ...int) *CompanyUpdateOne { + cuo.mutation.RemovePostingIDs(ids...) + return cuo +} + +// RemovePostings removes "postings" edges to Posting entities. +func (cuo *CompanyUpdateOne) RemovePostings(p ...*Posting) *CompanyUpdateOne { + ids := make([]int, len(p)) + for i := range p { + ids[i] = p[i].ID + } + return cuo.RemovePostingIDs(ids...) +} + // Where appends a list predicates to the CompanyUpdate builder. func (cuo *CompanyUpdateOne) Where(ps ...predicate.Company) *CompanyUpdateOne { cuo.mutation.Where(ps...) @@ -373,6 +491,51 @@ func (cuo *CompanyUpdateOne) sqlSave(ctx context.Context) (_node *Company, err e } _spec.SetField(company.FieldRssURL, field.TypeString, vv) } + if cuo.mutation.PostingsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: company.PostingsTable, + Columns: []string{company.PostingsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := cuo.mutation.RemovedPostingsIDs(); len(nodes) > 0 && !cuo.mutation.PostingsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: company.PostingsTable, + Columns: []string{company.PostingsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := cuo.mutation.PostingsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: company.PostingsTable, + Columns: []string{company.PostingsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } _node = &Company{config: cuo.config} _spec.Assign = _node.assignValues _spec.ScanValues = _node.scanValues diff --git a/ent/ent.go b/ent/ent.go index 0ae6918..9025160 100644 --- a/ent/ent.go +++ b/ent/ent.go @@ -13,6 +13,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" "github.com/techbloghub/server/ent/tag" ) @@ -75,6 +76,7 @@ func checkColumn(table, column string) error { initCheck.Do(func() { columnCheck = sql.NewColumnCheck(map[string]func(string) bool{ company.Table: company.ValidColumn, + posting.Table: posting.ValidColumn, tag.Table: tag.ValidColumn, }) }) diff --git a/ent/hook/hook.go b/ent/hook/hook.go index 0923266..da2b737 100644 --- a/ent/hook/hook.go +++ b/ent/hook/hook.go @@ -21,6 +21,18 @@ func (f CompanyFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, err return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.CompanyMutation", m) } +// The PostingFunc type is an adapter to allow the use of ordinary +// function as Posting mutator. +type PostingFunc func(context.Context, *ent.PostingMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f PostingFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.PostingMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.PostingMutation", m) +} + // The TagFunc type is an adapter to allow the use of ordinary // function as Tag mutator. type TagFunc func(context.Context, *ent.TagMutation) (ent.Value, error) diff --git a/ent/intercept/intercept.go b/ent/intercept/intercept.go index edfb063..9e186e2 100644 --- a/ent/intercept/intercept.go +++ b/ent/intercept/intercept.go @@ -9,6 +9,7 @@ import ( "entgo.io/ent/dialect/sql" "github.com/techbloghub/server/ent" "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" "github.com/techbloghub/server/ent/predicate" "github.com/techbloghub/server/ent/tag" ) @@ -96,6 +97,33 @@ func (f TraverseCompany) Traverse(ctx context.Context, q ent.Query) error { return fmt.Errorf("unexpected query type %T. expect *ent.CompanyQuery", q) } +// The PostingFunc type is an adapter to allow the use of ordinary function as a Querier. +type PostingFunc func(context.Context, *ent.PostingQuery) (ent.Value, error) + +// Query calls f(ctx, q). +func (f PostingFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) { + if q, ok := q.(*ent.PostingQuery); ok { + return f(ctx, q) + } + return nil, fmt.Errorf("unexpected query type %T. expect *ent.PostingQuery", q) +} + +// The TraversePosting type is an adapter to allow the use of ordinary function as Traverser. +type TraversePosting func(context.Context, *ent.PostingQuery) error + +// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline. +func (f TraversePosting) Intercept(next ent.Querier) ent.Querier { + return next +} + +// Traverse calls f(ctx, q). +func (f TraversePosting) Traverse(ctx context.Context, q ent.Query) error { + if q, ok := q.(*ent.PostingQuery); ok { + return f(ctx, q) + } + return fmt.Errorf("unexpected query type %T. expect *ent.PostingQuery", q) +} + // The TagFunc type is an adapter to allow the use of ordinary function as a Querier. type TagFunc func(context.Context, *ent.TagQuery) (ent.Value, error) @@ -128,6 +156,8 @@ func NewQuery(q ent.Query) (Query, error) { switch q := q.(type) { case *ent.CompanyQuery: return &query[*ent.CompanyQuery, predicate.Company, company.OrderOption]{typ: ent.TypeCompany, tq: q}, nil + case *ent.PostingQuery: + return &query[*ent.PostingQuery, predicate.Posting, posting.OrderOption]{typ: ent.TypePosting, tq: q}, nil case *ent.TagQuery: return &query[*ent.TagQuery, predicate.Tag, tag.OrderOption]{typ: ent.TypeTag, tq: q}, nil default: diff --git a/ent/internal/schema.go b/ent/internal/schema.go index 0a3deaf..f942142 100644 --- a/ent/internal/schema.go +++ b/ent/internal/schema.go @@ -6,4 +6,4 @@ // Package internal holds a loadable version of the latest schema. package internal -const Schema = "{\"Schema\":\"github.com/techbloghub/server/ent/schema\",\"Package\":\"github.com/techbloghub/server/ent\",\"Schemas\":[{\"name\":\"Company\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"create_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"update_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"delete_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"logo_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"blog_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"rss_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}]},{\"name\":\"Tag\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"create_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"update_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"delete_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}]}],\"Features\":[\"intercept\",\"schema/snapshot\"]}" +const Schema = "{\"Schema\":\"github.com/techbloghub/server/ent/schema\",\"Package\":\"github.com/techbloghub/server/ent\",\"Schemas\":[{\"name\":\"Company\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"postings\",\"type\":\"Posting\"}],\"fields\":[{\"name\":\"create_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"update_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"delete_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"logo_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"blog_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"rss_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}]},{\"name\":\"Posting\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"company\",\"type\":\"Company\",\"ref_name\":\"postings\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"title\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"unique\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"published_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"tags\",\"type\":{\"Type\":8,\"Ident\":\"*schemasupport.PostingTags\",\"PkgPath\":\"github.com/techbloghub/server/internal/schemasupport\",\"PkgName\":\"schemasupport\",\"Nillable\":true,\"RType\":{\"Name\":\"PostingTags\",\"Ident\":\"schemasupport.PostingTags\",\"Kind\":22,\"PkgPath\":\"github.com/techbloghub/server/internal/schemasupport\",\"Methods\":{\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"postgres\":\"text[]\"}}]},{\"name\":\"Tag\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"create_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"update_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"delete_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}]}],\"Features\":[\"intercept\",\"schema/snapshot\"]}" diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index c9c698b..3e5d8fd 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -25,6 +25,29 @@ var ( Columns: CompaniesColumns, PrimaryKey: []*schema.Column{CompaniesColumns[0]}, } + // PostingsColumns holds the columns for the "postings" table. + PostingsColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt, Increment: true}, + {Name: "title", Type: field.TypeString}, + {Name: "url", Type: field.TypeString, Unique: true}, + {Name: "published_at", Type: field.TypeTime}, + {Name: "tags", Type: field.TypeOther, Nullable: true, SchemaType: map[string]string{"postgres": "text[]"}}, + {Name: "company_postings", Type: field.TypeInt, Nullable: true}, + } + // PostingsTable holds the schema information for the "postings" table. + PostingsTable = &schema.Table{ + Name: "postings", + Columns: PostingsColumns, + PrimaryKey: []*schema.Column{PostingsColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "postings_companies_postings", + Columns: []*schema.Column{PostingsColumns[5]}, + RefColumns: []*schema.Column{CompaniesColumns[0]}, + OnDelete: schema.SetNull, + }, + }, + } // TagsColumns holds the columns for the "tags" table. TagsColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, @@ -42,9 +65,11 @@ var ( // Tables holds all the tables in the schema. Tables = []*schema.Table{ CompaniesTable, + PostingsTable, TagsTable, } ) func init() { + PostingsTable.ForeignKeys[0].RefTable = CompaniesTable } diff --git a/ent/mutation.go b/ent/mutation.go index 9523c82..dcdd093 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -13,8 +13,10 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" "github.com/techbloghub/server/ent/predicate" "github.com/techbloghub/server/ent/tag" + "github.com/techbloghub/server/internal/schemasupport" ) const ( @@ -27,26 +29,30 @@ const ( // Node types. TypeCompany = "Company" + TypePosting = "Posting" TypeTag = "Tag" ) // CompanyMutation represents an operation that mutates the Company nodes in the graph. type CompanyMutation struct { config - op Op - typ string - id *int - create_time *time.Time - update_time *time.Time - delete_time *time.Time - name *string - logo_url **url.URL - blog_url **url.URL - rss_url **url.URL - clearedFields map[string]struct{} - done bool - oldValue func(context.Context) (*Company, error) - predicates []predicate.Company + op Op + typ string + id *int + create_time *time.Time + update_time *time.Time + delete_time *time.Time + name *string + logo_url **url.URL + blog_url **url.URL + rss_url **url.URL + clearedFields map[string]struct{} + postings map[int]struct{} + removedpostings map[int]struct{} + clearedpostings bool + done bool + oldValue func(context.Context) (*Company, error) + predicates []predicate.Company } var _ ent.Mutation = (*CompanyMutation)(nil) @@ -412,6 +418,60 @@ func (m *CompanyMutation) ResetRssURL() { m.rss_url = nil } +// AddPostingIDs adds the "postings" edge to the Posting entity by ids. +func (m *CompanyMutation) AddPostingIDs(ids ...int) { + if m.postings == nil { + m.postings = make(map[int]struct{}) + } + for i := range ids { + m.postings[ids[i]] = struct{}{} + } +} + +// ClearPostings clears the "postings" edge to the Posting entity. +func (m *CompanyMutation) ClearPostings() { + m.clearedpostings = true +} + +// PostingsCleared reports if the "postings" edge to the Posting entity was cleared. +func (m *CompanyMutation) PostingsCleared() bool { + return m.clearedpostings +} + +// RemovePostingIDs removes the "postings" edge to the Posting entity by IDs. +func (m *CompanyMutation) RemovePostingIDs(ids ...int) { + if m.removedpostings == nil { + m.removedpostings = make(map[int]struct{}) + } + for i := range ids { + delete(m.postings, ids[i]) + m.removedpostings[ids[i]] = struct{}{} + } +} + +// RemovedPostings returns the removed IDs of the "postings" edge to the Posting entity. +func (m *CompanyMutation) RemovedPostingsIDs() (ids []int) { + for id := range m.removedpostings { + ids = append(ids, id) + } + return +} + +// PostingsIDs returns the "postings" edge IDs in the mutation. +func (m *CompanyMutation) PostingsIDs() (ids []int) { + for id := range m.postings { + ids = append(ids, id) + } + return +} + +// ResetPostings resets all changes to the "postings" edge. +func (m *CompanyMutation) ResetPostings() { + m.postings = nil + m.clearedpostings = false + m.removedpostings = nil +} + // Where appends a list predicates to the CompanyMutation builder. func (m *CompanyMutation) Where(ps ...predicate.Company) { m.predicates = append(m.predicates, ps...) @@ -656,52 +716,665 @@ func (m *CompanyMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *CompanyMutation) AddedEdges() []string { - edges := make([]string, 0, 0) + edges := make([]string, 0, 1) + if m.postings != nil { + edges = append(edges, company.EdgePostings) + } return edges } // AddedIDs returns all IDs (to other nodes) that were added for the given edge // name in this mutation. func (m *CompanyMutation) AddedIDs(name string) []ent.Value { + switch name { + case company.EdgePostings: + ids := make([]ent.Value, 0, len(m.postings)) + for id := range m.postings { + ids = append(ids, id) + } + return ids + } return nil } // RemovedEdges returns all edge names that were removed in this mutation. func (m *CompanyMutation) RemovedEdges() []string { - edges := make([]string, 0, 0) + edges := make([]string, 0, 1) + if m.removedpostings != nil { + edges = append(edges, company.EdgePostings) + } return edges } // RemovedIDs returns all IDs (to other nodes) that were removed for the edge with // the given name in this mutation. func (m *CompanyMutation) RemovedIDs(name string) []ent.Value { + switch name { + case company.EdgePostings: + ids := make([]ent.Value, 0, len(m.removedpostings)) + for id := range m.removedpostings { + ids = append(ids, id) + } + return ids + } return nil } // ClearedEdges returns all edge names that were cleared in this mutation. func (m *CompanyMutation) ClearedEdges() []string { - edges := make([]string, 0, 0) + edges := make([]string, 0, 1) + if m.clearedpostings { + edges = append(edges, company.EdgePostings) + } return edges } // EdgeCleared returns a boolean which indicates if the edge with the given name // was cleared in this mutation. func (m *CompanyMutation) EdgeCleared(name string) bool { + switch name { + case company.EdgePostings: + return m.clearedpostings + } 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 *CompanyMutation) ClearEdge(name string) error { + switch name { + } return fmt.Errorf("unknown Company 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 *CompanyMutation) ResetEdge(name string) error { + switch name { + case company.EdgePostings: + m.ResetPostings() + return nil + } return fmt.Errorf("unknown Company edge %s", name) } +// PostingMutation represents an operation that mutates the Posting nodes in the graph. +type PostingMutation struct { + config + op Op + typ string + id *int + title *string + url **url.URL + published_at *time.Time + tags **schemasupport.PostingTags + clearedFields map[string]struct{} + company *int + clearedcompany bool + done bool + oldValue func(context.Context) (*Posting, error) + predicates []predicate.Posting +} + +var _ ent.Mutation = (*PostingMutation)(nil) + +// postingOption allows management of the mutation configuration using functional options. +type postingOption func(*PostingMutation) + +// newPostingMutation creates new mutation for the Posting entity. +func newPostingMutation(c config, op Op, opts ...postingOption) *PostingMutation { + m := &PostingMutation{ + config: c, + op: op, + typ: TypePosting, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withPostingID sets the ID field of the mutation. +func withPostingID(id int) postingOption { + return func(m *PostingMutation) { + var ( + err error + once sync.Once + value *Posting + ) + m.oldValue = func(ctx context.Context) (*Posting, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().Posting.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withPosting sets the old Posting of the mutation. +func withPosting(node *Posting) postingOption { + return func(m *PostingMutation) { + m.oldValue = func(context.Context) (*Posting, 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 PostingMutation) 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 PostingMutation) 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 +} + +// 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 *PostingMutation) ID() (id int, 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 *PostingMutation) IDs(ctx context.Context) ([]int, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().Posting.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetTitle sets the "title" field. +func (m *PostingMutation) SetTitle(s string) { + m.title = &s +} + +// Title returns the value of the "title" field in the mutation. +func (m *PostingMutation) Title() (r string, exists bool) { + v := m.title + if v == nil { + return + } + return *v, true +} + +// OldTitle returns the old "title" field's value of the Posting entity. +// If the Posting 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 *PostingMutation) OldTitle(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldTitle is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldTitle requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldTitle: %w", err) + } + return oldValue.Title, nil +} + +// ResetTitle resets all changes to the "title" field. +func (m *PostingMutation) ResetTitle() { + m.title = nil +} + +// SetURL sets the "url" field. +func (m *PostingMutation) SetURL(u *url.URL) { + m.url = &u +} + +// URL returns the value of the "url" field in the mutation. +func (m *PostingMutation) URL() (r *url.URL, exists bool) { + v := m.url + if v == nil { + return + } + return *v, true +} + +// OldURL returns the old "url" field's value of the Posting entity. +// If the Posting 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 *PostingMutation) OldURL(ctx context.Context) (v *url.URL, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldURL is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldURL requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldURL: %w", err) + } + return oldValue.URL, nil +} + +// ResetURL resets all changes to the "url" field. +func (m *PostingMutation) ResetURL() { + m.url = nil +} + +// SetPublishedAt sets the "published_at" field. +func (m *PostingMutation) SetPublishedAt(t time.Time) { + m.published_at = &t +} + +// PublishedAt returns the value of the "published_at" field in the mutation. +func (m *PostingMutation) PublishedAt() (r time.Time, exists bool) { + v := m.published_at + if v == nil { + return + } + return *v, true +} + +// OldPublishedAt returns the old "published_at" field's value of the Posting entity. +// If the Posting 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 *PostingMutation) OldPublishedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPublishedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPublishedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPublishedAt: %w", err) + } + return oldValue.PublishedAt, nil +} + +// ResetPublishedAt resets all changes to the "published_at" field. +func (m *PostingMutation) ResetPublishedAt() { + m.published_at = nil +} + +// SetTags sets the "tags" field. +func (m *PostingMutation) SetTags(st *schemasupport.PostingTags) { + m.tags = &st +} + +// Tags returns the value of the "tags" field in the mutation. +func (m *PostingMutation) Tags() (r *schemasupport.PostingTags, exists bool) { + v := m.tags + if v == nil { + return + } + return *v, true +} + +// OldTags returns the old "tags" field's value of the Posting entity. +// If the Posting 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 *PostingMutation) OldTags(ctx context.Context) (v *schemasupport.PostingTags, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldTags is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldTags requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldTags: %w", err) + } + return oldValue.Tags, nil +} + +// ClearTags clears the value of the "tags" field. +func (m *PostingMutation) ClearTags() { + m.tags = nil + m.clearedFields[posting.FieldTags] = struct{}{} +} + +// TagsCleared returns if the "tags" field was cleared in this mutation. +func (m *PostingMutation) TagsCleared() bool { + _, ok := m.clearedFields[posting.FieldTags] + return ok +} + +// ResetTags resets all changes to the "tags" field. +func (m *PostingMutation) ResetTags() { + m.tags = nil + delete(m.clearedFields, posting.FieldTags) +} + +// SetCompanyID sets the "company" edge to the Company entity by id. +func (m *PostingMutation) SetCompanyID(id int) { + m.company = &id +} + +// ClearCompany clears the "company" edge to the Company entity. +func (m *PostingMutation) ClearCompany() { + m.clearedcompany = true +} + +// CompanyCleared reports if the "company" edge to the Company entity was cleared. +func (m *PostingMutation) CompanyCleared() bool { + return m.clearedcompany +} + +// CompanyID returns the "company" edge ID in the mutation. +func (m *PostingMutation) CompanyID() (id int, exists bool) { + if m.company != nil { + return *m.company, true + } + return +} + +// CompanyIDs returns the "company" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// CompanyID instead. It exists only for internal usage by the builders. +func (m *PostingMutation) CompanyIDs() (ids []int) { + if id := m.company; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetCompany resets all changes to the "company" edge. +func (m *PostingMutation) ResetCompany() { + m.company = nil + m.clearedcompany = false +} + +// Where appends a list predicates to the PostingMutation builder. +func (m *PostingMutation) Where(ps ...predicate.Posting) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the PostingMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *PostingMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.Posting, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *PostingMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *PostingMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (Posting). +func (m *PostingMutation) 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 *PostingMutation) Fields() []string { + fields := make([]string, 0, 4) + if m.title != nil { + fields = append(fields, posting.FieldTitle) + } + if m.url != nil { + fields = append(fields, posting.FieldURL) + } + if m.published_at != nil { + fields = append(fields, posting.FieldPublishedAt) + } + if m.tags != nil { + fields = append(fields, posting.FieldTags) + } + 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 *PostingMutation) Field(name string) (ent.Value, bool) { + switch name { + case posting.FieldTitle: + return m.Title() + case posting.FieldURL: + return m.URL() + case posting.FieldPublishedAt: + return m.PublishedAt() + case posting.FieldTags: + return m.Tags() + } + 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 *PostingMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case posting.FieldTitle: + return m.OldTitle(ctx) + case posting.FieldURL: + return m.OldURL(ctx) + case posting.FieldPublishedAt: + return m.OldPublishedAt(ctx) + case posting.FieldTags: + return m.OldTags(ctx) + } + return nil, fmt.Errorf("unknown Posting 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 *PostingMutation) SetField(name string, value ent.Value) error { + switch name { + case posting.FieldTitle: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetTitle(v) + return nil + case posting.FieldURL: + v, ok := value.(*url.URL) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetURL(v) + return nil + case posting.FieldPublishedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPublishedAt(v) + return nil + case posting.FieldTags: + v, ok := value.(*schemasupport.PostingTags) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetTags(v) + return nil + } + return fmt.Errorf("unknown Posting field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *PostingMutation) 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 *PostingMutation) 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 *PostingMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown Posting numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *PostingMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(posting.FieldTags) { + fields = append(fields, posting.FieldTags) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *PostingMutation) 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 *PostingMutation) ClearField(name string) error { + switch name { + case posting.FieldTags: + m.ClearTags() + return nil + } + return fmt.Errorf("unknown Posting 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 *PostingMutation) ResetField(name string) error { + switch name { + case posting.FieldTitle: + m.ResetTitle() + return nil + case posting.FieldURL: + m.ResetURL() + return nil + case posting.FieldPublishedAt: + m.ResetPublishedAt() + return nil + case posting.FieldTags: + m.ResetTags() + return nil + } + return fmt.Errorf("unknown Posting field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *PostingMutation) AddedEdges() []string { + edges := make([]string, 0, 1) + if m.company != nil { + edges = append(edges, posting.EdgeCompany) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *PostingMutation) AddedIDs(name string) []ent.Value { + switch name { + case posting.EdgeCompany: + if id := m.company; id != nil { + return []ent.Value{*id} + } + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *PostingMutation) RemovedEdges() []string { + edges := make([]string, 0, 1) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *PostingMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *PostingMutation) ClearedEdges() []string { + edges := make([]string, 0, 1) + if m.clearedcompany { + edges = append(edges, posting.EdgeCompany) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *PostingMutation) EdgeCleared(name string) bool { + switch name { + case posting.EdgeCompany: + return m.clearedcompany + } + 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 *PostingMutation) ClearEdge(name string) error { + switch name { + case posting.EdgeCompany: + m.ClearCompany() + return nil + } + return fmt.Errorf("unknown Posting 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 *PostingMutation) ResetEdge(name string) error { + switch name { + case posting.EdgeCompany: + m.ResetCompany() + return nil + } + return fmt.Errorf("unknown Posting edge %s", name) +} + // TagMutation represents an operation that mutates the Tag nodes in the graph. type TagMutation struct { config diff --git a/ent/posting.go b/ent/posting.go new file mode 100644 index 0000000..704cdd7 --- /dev/null +++ b/ent/posting.go @@ -0,0 +1,184 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "fmt" + "net/url" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" + "github.com/techbloghub/server/internal/schemasupport" +) + +// Posting is the model entity for the Posting schema. +type Posting struct { + config `json:"-"` + // ID of the ent. + ID int `json:"id,omitempty"` + // Title holds the value of the "title" field. + Title string `json:"title,omitempty"` + // URL holds the value of the "url" field. + URL *url.URL `json:"url,omitempty"` + // PublishedAt holds the value of the "published_at" field. + PublishedAt time.Time `json:"published_at,omitempty"` + // Tags holds the value of the "tags" field. + Tags *schemasupport.PostingTags `json:"tags,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the PostingQuery when eager-loading is set. + Edges PostingEdges `json:"edges"` + company_postings *int + selectValues sql.SelectValues +} + +// PostingEdges holds the relations/edges for other nodes in the graph. +type PostingEdges struct { + // Company holds the value of the company edge. + Company *Company `json:"company,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [1]bool +} + +// CompanyOrErr returns the Company value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e PostingEdges) CompanyOrErr() (*Company, error) { + if e.Company != nil { + return e.Company, nil + } else if e.loadedTypes[0] { + return nil, &NotFoundError{label: company.Label} + } + return nil, &NotLoadedError{edge: "company"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*Posting) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case posting.FieldTags: + values[i] = new(schemasupport.PostingTags) + case posting.FieldID: + values[i] = new(sql.NullInt64) + case posting.FieldTitle: + values[i] = new(sql.NullString) + case posting.FieldPublishedAt: + values[i] = new(sql.NullTime) + case posting.FieldURL: + values[i] = posting.ValueScanner.URL.ScanValue() + case posting.ForeignKeys[0]: // company_postings + values[i] = new(sql.NullInt64) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the Posting fields. +func (po *Posting) 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 posting.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + po.ID = int(value.Int64) + case posting.FieldTitle: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field title", values[i]) + } else if value.Valid { + po.Title = value.String + } + case posting.FieldURL: + if value, err := posting.ValueScanner.URL.FromValue(values[i]); err != nil { + return err + } else { + po.URL = value + } + case posting.FieldPublishedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field published_at", values[i]) + } else if value.Valid { + po.PublishedAt = value.Time + } + case posting.FieldTags: + if value, ok := values[i].(*schemasupport.PostingTags); !ok { + return fmt.Errorf("unexpected type %T for field tags", values[i]) + } else if value != nil { + po.Tags = value + } + case posting.ForeignKeys[0]: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for edge-field company_postings", value) + } else if value.Valid { + po.company_postings = new(int) + *po.company_postings = int(value.Int64) + } + default: + po.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the Posting. +// This includes values selected through modifiers, order, etc. +func (po *Posting) Value(name string) (ent.Value, error) { + return po.selectValues.Get(name) +} + +// QueryCompany queries the "company" edge of the Posting entity. +func (po *Posting) QueryCompany() *CompanyQuery { + return NewPostingClient(po.config).QueryCompany(po) +} + +// Update returns a builder for updating this Posting. +// Note that you need to call Posting.Unwrap() before calling this method if this Posting +// was returned from a transaction, and the transaction was committed or rolled back. +func (po *Posting) Update() *PostingUpdateOne { + return NewPostingClient(po.config).UpdateOne(po) +} + +// Unwrap unwraps the Posting 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 (po *Posting) Unwrap() *Posting { + _tx, ok := po.config.driver.(*txDriver) + if !ok { + panic("ent: Posting is not a transactional entity") + } + po.config.driver = _tx.drv + return po +} + +// String implements the fmt.Stringer. +func (po *Posting) String() string { + var builder strings.Builder + builder.WriteString("Posting(") + builder.WriteString(fmt.Sprintf("id=%v, ", po.ID)) + builder.WriteString("title=") + builder.WriteString(po.Title) + builder.WriteString(", ") + builder.WriteString("url=") + builder.WriteString(fmt.Sprintf("%v", po.URL)) + builder.WriteString(", ") + builder.WriteString("published_at=") + builder.WriteString(po.PublishedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("tags=") + builder.WriteString(fmt.Sprintf("%v", po.Tags)) + builder.WriteByte(')') + return builder.String() +} + +// Postings is a parsable slice of Posting. +type Postings []*Posting diff --git a/ent/posting/posting.go b/ent/posting/posting.go new file mode 100644 index 0000000..11044f1 --- /dev/null +++ b/ent/posting/posting.go @@ -0,0 +1,116 @@ +// Code generated by ent, DO NOT EDIT. + +package posting + +import ( + "net/url" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" +) + +const ( + // Label holds the string label denoting the posting type in the database. + Label = "posting" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldTitle holds the string denoting the title field in the database. + FieldTitle = "title" + // FieldURL holds the string denoting the url field in the database. + FieldURL = "url" + // FieldPublishedAt holds the string denoting the published_at field in the database. + FieldPublishedAt = "published_at" + // FieldTags holds the string denoting the tags field in the database. + FieldTags = "tags" + // EdgeCompany holds the string denoting the company edge name in mutations. + EdgeCompany = "company" + // Table holds the table name of the posting in the database. + Table = "postings" + // CompanyTable is the table that holds the company relation/edge. + CompanyTable = "postings" + // CompanyInverseTable is the table name for the Company entity. + // It exists in this package in order to avoid circular dependency with the "company" package. + CompanyInverseTable = "companies" + // CompanyColumn is the table column denoting the company relation/edge. + CompanyColumn = "company_postings" +) + +// Columns holds all SQL columns for posting fields. +var Columns = []string{ + FieldID, + FieldTitle, + FieldURL, + FieldPublishedAt, + FieldTags, +} + +// ForeignKeys holds the SQL foreign-keys that are owned by the "postings" +// table and are not defined as standalone fields in the schema. +var ForeignKeys = []string{ + "company_postings", +} + +// 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 ( + // ValueScanner of all Posting fields. + ValueScanner struct { + URL field.TypeValueScanner[*url.URL] + } +) + +// OrderOption defines the ordering options for the Posting 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() +} + +// ByTitle orders the results by the title field. +func ByTitle(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldTitle, opts...).ToFunc() +} + +// ByURL orders the results by the url field. +func ByURL(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldURL, opts...).ToFunc() +} + +// ByPublishedAt orders the results by the published_at field. +func ByPublishedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPublishedAt, opts...).ToFunc() +} + +// ByTags orders the results by the tags field. +func ByTags(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldTags, opts...).ToFunc() +} + +// ByCompanyField orders the results by company field. +func ByCompanyField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newCompanyStep(), sql.OrderByField(field, opts...)) + } +} +func newCompanyStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(CompanyInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, CompanyTable, CompanyColumn), + ) +} diff --git a/ent/posting/where.go b/ent/posting/where.go new file mode 100644 index 0000000..074a994 --- /dev/null +++ b/ent/posting/where.go @@ -0,0 +1,387 @@ +// Code generated by ent, DO NOT EDIT. + +package posting + +import ( + "fmt" + "net/url" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/techbloghub/server/ent/predicate" + "github.com/techbloghub/server/internal/schemasupport" +) + +// ID filters vertices based on their ID field. +func ID(id int) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int) predicate.Posting { + return predicate.Posting(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int) predicate.Posting { + return predicate.Posting(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int) predicate.Posting { + return predicate.Posting(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int) predicate.Posting { + return predicate.Posting(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int) predicate.Posting { + return predicate.Posting(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int) predicate.Posting { + return predicate.Posting(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int) predicate.Posting { + return predicate.Posting(sql.FieldLTE(FieldID, id)) +} + +// Title applies equality check predicate on the "title" field. It's identical to TitleEQ. +func Title(v string) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldTitle, v)) +} + +// URL applies equality check predicate on the "url" field. It's identical to URLEQ. +func URL(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + return predicate.PostingOrErr(sql.FieldEQ(FieldURL, vc), err) +} + +// PublishedAt applies equality check predicate on the "published_at" field. It's identical to PublishedAtEQ. +func PublishedAt(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldPublishedAt, v)) +} + +// Tags applies equality check predicate on the "tags" field. It's identical to TagsEQ. +func Tags(v *schemasupport.PostingTags) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldTags, v)) +} + +// TitleEQ applies the EQ predicate on the "title" field. +func TitleEQ(v string) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldTitle, v)) +} + +// TitleNEQ applies the NEQ predicate on the "title" field. +func TitleNEQ(v string) predicate.Posting { + return predicate.Posting(sql.FieldNEQ(FieldTitle, v)) +} + +// TitleIn applies the In predicate on the "title" field. +func TitleIn(vs ...string) predicate.Posting { + return predicate.Posting(sql.FieldIn(FieldTitle, vs...)) +} + +// TitleNotIn applies the NotIn predicate on the "title" field. +func TitleNotIn(vs ...string) predicate.Posting { + return predicate.Posting(sql.FieldNotIn(FieldTitle, vs...)) +} + +// TitleGT applies the GT predicate on the "title" field. +func TitleGT(v string) predicate.Posting { + return predicate.Posting(sql.FieldGT(FieldTitle, v)) +} + +// TitleGTE applies the GTE predicate on the "title" field. +func TitleGTE(v string) predicate.Posting { + return predicate.Posting(sql.FieldGTE(FieldTitle, v)) +} + +// TitleLT applies the LT predicate on the "title" field. +func TitleLT(v string) predicate.Posting { + return predicate.Posting(sql.FieldLT(FieldTitle, v)) +} + +// TitleLTE applies the LTE predicate on the "title" field. +func TitleLTE(v string) predicate.Posting { + return predicate.Posting(sql.FieldLTE(FieldTitle, v)) +} + +// TitleContains applies the Contains predicate on the "title" field. +func TitleContains(v string) predicate.Posting { + return predicate.Posting(sql.FieldContains(FieldTitle, v)) +} + +// TitleHasPrefix applies the HasPrefix predicate on the "title" field. +func TitleHasPrefix(v string) predicate.Posting { + return predicate.Posting(sql.FieldHasPrefix(FieldTitle, v)) +} + +// TitleHasSuffix applies the HasSuffix predicate on the "title" field. +func TitleHasSuffix(v string) predicate.Posting { + return predicate.Posting(sql.FieldHasSuffix(FieldTitle, v)) +} + +// TitleEqualFold applies the EqualFold predicate on the "title" field. +func TitleEqualFold(v string) predicate.Posting { + return predicate.Posting(sql.FieldEqualFold(FieldTitle, v)) +} + +// TitleContainsFold applies the ContainsFold predicate on the "title" field. +func TitleContainsFold(v string) predicate.Posting { + return predicate.Posting(sql.FieldContainsFold(FieldTitle, v)) +} + +// URLEQ applies the EQ predicate on the "url" field. +func URLEQ(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + return predicate.PostingOrErr(sql.FieldEQ(FieldURL, vc), err) +} + +// URLNEQ applies the NEQ predicate on the "url" field. +func URLNEQ(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + return predicate.PostingOrErr(sql.FieldNEQ(FieldURL, vc), err) +} + +// URLIn applies the In predicate on the "url" field. +func URLIn(vs ...*url.URL) predicate.Posting { + var ( + err error + v = make([]any, len(vs)) + ) + for i := range v { + if v[i], err = ValueScanner.URL.Value(vs[i]); err != nil { + break + } + } + return predicate.PostingOrErr(sql.FieldIn(FieldURL, v...), err) +} + +// URLNotIn applies the NotIn predicate on the "url" field. +func URLNotIn(vs ...*url.URL) predicate.Posting { + var ( + err error + v = make([]any, len(vs)) + ) + for i := range v { + if v[i], err = ValueScanner.URL.Value(vs[i]); err != nil { + break + } + } + return predicate.PostingOrErr(sql.FieldNotIn(FieldURL, v...), err) +} + +// URLGT applies the GT predicate on the "url" field. +func URLGT(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + return predicate.PostingOrErr(sql.FieldGT(FieldURL, vc), err) +} + +// URLGTE applies the GTE predicate on the "url" field. +func URLGTE(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + return predicate.PostingOrErr(sql.FieldGTE(FieldURL, vc), err) +} + +// URLLT applies the LT predicate on the "url" field. +func URLLT(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + return predicate.PostingOrErr(sql.FieldLT(FieldURL, vc), err) +} + +// URLLTE applies the LTE predicate on the "url" field. +func URLLTE(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + return predicate.PostingOrErr(sql.FieldLTE(FieldURL, vc), err) +} + +// URLContains applies the Contains predicate on the "url" field. +func URLContains(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + vcs, ok := vc.(string) + if err == nil && !ok { + err = fmt.Errorf("url value is not a string: %T", vc) + } + return predicate.PostingOrErr(sql.FieldContains(FieldURL, vcs), err) +} + +// URLHasPrefix applies the HasPrefix predicate on the "url" field. +func URLHasPrefix(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + vcs, ok := vc.(string) + if err == nil && !ok { + err = fmt.Errorf("url value is not a string: %T", vc) + } + return predicate.PostingOrErr(sql.FieldHasPrefix(FieldURL, vcs), err) +} + +// URLHasSuffix applies the HasSuffix predicate on the "url" field. +func URLHasSuffix(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + vcs, ok := vc.(string) + if err == nil && !ok { + err = fmt.Errorf("url value is not a string: %T", vc) + } + return predicate.PostingOrErr(sql.FieldHasSuffix(FieldURL, vcs), err) +} + +// URLEqualFold applies the EqualFold predicate on the "url" field. +func URLEqualFold(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + vcs, ok := vc.(string) + if err == nil && !ok { + err = fmt.Errorf("url value is not a string: %T", vc) + } + return predicate.PostingOrErr(sql.FieldEqualFold(FieldURL, vcs), err) +} + +// URLContainsFold applies the ContainsFold predicate on the "url" field. +func URLContainsFold(v *url.URL) predicate.Posting { + vc, err := ValueScanner.URL.Value(v) + vcs, ok := vc.(string) + if err == nil && !ok { + err = fmt.Errorf("url value is not a string: %T", vc) + } + return predicate.PostingOrErr(sql.FieldContainsFold(FieldURL, vcs), err) +} + +// PublishedAtEQ applies the EQ predicate on the "published_at" field. +func PublishedAtEQ(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldPublishedAt, v)) +} + +// PublishedAtNEQ applies the NEQ predicate on the "published_at" field. +func PublishedAtNEQ(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldNEQ(FieldPublishedAt, v)) +} + +// PublishedAtIn applies the In predicate on the "published_at" field. +func PublishedAtIn(vs ...time.Time) predicate.Posting { + return predicate.Posting(sql.FieldIn(FieldPublishedAt, vs...)) +} + +// PublishedAtNotIn applies the NotIn predicate on the "published_at" field. +func PublishedAtNotIn(vs ...time.Time) predicate.Posting { + return predicate.Posting(sql.FieldNotIn(FieldPublishedAt, vs...)) +} + +// PublishedAtGT applies the GT predicate on the "published_at" field. +func PublishedAtGT(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldGT(FieldPublishedAt, v)) +} + +// PublishedAtGTE applies the GTE predicate on the "published_at" field. +func PublishedAtGTE(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldGTE(FieldPublishedAt, v)) +} + +// PublishedAtLT applies the LT predicate on the "published_at" field. +func PublishedAtLT(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldLT(FieldPublishedAt, v)) +} + +// PublishedAtLTE applies the LTE predicate on the "published_at" field. +func PublishedAtLTE(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldLTE(FieldPublishedAt, v)) +} + +// TagsEQ applies the EQ predicate on the "tags" field. +func TagsEQ(v *schemasupport.PostingTags) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldTags, v)) +} + +// TagsNEQ applies the NEQ predicate on the "tags" field. +func TagsNEQ(v *schemasupport.PostingTags) predicate.Posting { + return predicate.Posting(sql.FieldNEQ(FieldTags, v)) +} + +// TagsIn applies the In predicate on the "tags" field. +func TagsIn(vs ...*schemasupport.PostingTags) predicate.Posting { + return predicate.Posting(sql.FieldIn(FieldTags, vs...)) +} + +// TagsNotIn applies the NotIn predicate on the "tags" field. +func TagsNotIn(vs ...*schemasupport.PostingTags) predicate.Posting { + return predicate.Posting(sql.FieldNotIn(FieldTags, vs...)) +} + +// TagsGT applies the GT predicate on the "tags" field. +func TagsGT(v *schemasupport.PostingTags) predicate.Posting { + return predicate.Posting(sql.FieldGT(FieldTags, v)) +} + +// TagsGTE applies the GTE predicate on the "tags" field. +func TagsGTE(v *schemasupport.PostingTags) predicate.Posting { + return predicate.Posting(sql.FieldGTE(FieldTags, v)) +} + +// TagsLT applies the LT predicate on the "tags" field. +func TagsLT(v *schemasupport.PostingTags) predicate.Posting { + return predicate.Posting(sql.FieldLT(FieldTags, v)) +} + +// TagsLTE applies the LTE predicate on the "tags" field. +func TagsLTE(v *schemasupport.PostingTags) predicate.Posting { + return predicate.Posting(sql.FieldLTE(FieldTags, v)) +} + +// TagsIsNil applies the IsNil predicate on the "tags" field. +func TagsIsNil() predicate.Posting { + return predicate.Posting(sql.FieldIsNull(FieldTags)) +} + +// TagsNotNil applies the NotNil predicate on the "tags" field. +func TagsNotNil() predicate.Posting { + return predicate.Posting(sql.FieldNotNull(FieldTags)) +} + +// HasCompany applies the HasEdge predicate on the "company" edge. +func HasCompany() predicate.Posting { + return predicate.Posting(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, CompanyTable, CompanyColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasCompanyWith applies the HasEdge predicate on the "company" edge with a given conditions (other predicates). +func HasCompanyWith(preds ...predicate.Company) predicate.Posting { + return predicate.Posting(func(s *sql.Selector) { + step := newCompanyStep() + 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.Posting) predicate.Posting { + return predicate.Posting(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.Posting) predicate.Posting { + return predicate.Posting(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.Posting) predicate.Posting { + return predicate.Posting(sql.NotPredicates(p)) +} diff --git a/ent/posting_create.go b/ent/posting_create.go new file mode 100644 index 0000000..f57616a --- /dev/null +++ b/ent/posting_create.go @@ -0,0 +1,269 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "net/url" + "time" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" + "github.com/techbloghub/server/internal/schemasupport" +) + +// PostingCreate is the builder for creating a Posting entity. +type PostingCreate struct { + config + mutation *PostingMutation + hooks []Hook +} + +// SetTitle sets the "title" field. +func (pc *PostingCreate) SetTitle(s string) *PostingCreate { + pc.mutation.SetTitle(s) + return pc +} + +// SetURL sets the "url" field. +func (pc *PostingCreate) SetURL(u *url.URL) *PostingCreate { + pc.mutation.SetURL(u) + return pc +} + +// SetPublishedAt sets the "published_at" field. +func (pc *PostingCreate) SetPublishedAt(t time.Time) *PostingCreate { + pc.mutation.SetPublishedAt(t) + return pc +} + +// SetTags sets the "tags" field. +func (pc *PostingCreate) SetTags(st *schemasupport.PostingTags) *PostingCreate { + pc.mutation.SetTags(st) + return pc +} + +// SetCompanyID sets the "company" edge to the Company entity by ID. +func (pc *PostingCreate) SetCompanyID(id int) *PostingCreate { + pc.mutation.SetCompanyID(id) + return pc +} + +// SetNillableCompanyID sets the "company" edge to the Company entity by ID if the given value is not nil. +func (pc *PostingCreate) SetNillableCompanyID(id *int) *PostingCreate { + if id != nil { + pc = pc.SetCompanyID(*id) + } + return pc +} + +// SetCompany sets the "company" edge to the Company entity. +func (pc *PostingCreate) SetCompany(c *Company) *PostingCreate { + return pc.SetCompanyID(c.ID) +} + +// Mutation returns the PostingMutation object of the builder. +func (pc *PostingCreate) Mutation() *PostingMutation { + return pc.mutation +} + +// Save creates the Posting in the database. +func (pc *PostingCreate) Save(ctx context.Context) (*Posting, error) { + return withHooks(ctx, pc.sqlSave, pc.mutation, pc.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (pc *PostingCreate) SaveX(ctx context.Context) *Posting { + v, err := pc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (pc *PostingCreate) Exec(ctx context.Context) error { + _, err := pc.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (pc *PostingCreate) ExecX(ctx context.Context) { + if err := pc.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (pc *PostingCreate) check() error { + if _, ok := pc.mutation.Title(); !ok { + return &ValidationError{Name: "title", err: errors.New(`ent: missing required field "Posting.title"`)} + } + if _, ok := pc.mutation.URL(); !ok { + return &ValidationError{Name: "url", err: errors.New(`ent: missing required field "Posting.url"`)} + } + if _, ok := pc.mutation.PublishedAt(); !ok { + return &ValidationError{Name: "published_at", err: errors.New(`ent: missing required field "Posting.published_at"`)} + } + return nil +} + +func (pc *PostingCreate) sqlSave(ctx context.Context) (*Posting, error) { + if err := pc.check(); err != nil { + return nil, err + } + _node, _spec, err := pc.createSpec() + if err != nil { + return nil, err + } + if err := sqlgraph.CreateNode(ctx, pc.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + id := _spec.ID.Value.(int64) + _node.ID = int(id) + pc.mutation.id = &_node.ID + pc.mutation.done = true + return _node, nil +} + +func (pc *PostingCreate) createSpec() (*Posting, *sqlgraph.CreateSpec, error) { + var ( + _node = &Posting{config: pc.config} + _spec = sqlgraph.NewCreateSpec(posting.Table, sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt)) + ) + if value, ok := pc.mutation.Title(); ok { + _spec.SetField(posting.FieldTitle, field.TypeString, value) + _node.Title = value + } + if value, ok := pc.mutation.URL(); ok { + vv, err := posting.ValueScanner.URL.Value(value) + if err != nil { + return nil, nil, err + } + _spec.SetField(posting.FieldURL, field.TypeString, vv) + _node.URL = value + } + if value, ok := pc.mutation.PublishedAt(); ok { + _spec.SetField(posting.FieldPublishedAt, field.TypeTime, value) + _node.PublishedAt = value + } + if value, ok := pc.mutation.Tags(); ok { + _spec.SetField(posting.FieldTags, field.TypeOther, value) + _node.Tags = value + } + if nodes := pc.mutation.CompanyIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: posting.CompanyTable, + Columns: []string{posting.CompanyColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(company.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.company_postings = &nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec, nil +} + +// PostingCreateBulk is the builder for creating many Posting entities in bulk. +type PostingCreateBulk struct { + config + err error + builders []*PostingCreate +} + +// Save creates the Posting entities in the database. +func (pcb *PostingCreateBulk) Save(ctx context.Context) ([]*Posting, error) { + if pcb.err != nil { + return nil, pcb.err + } + specs := make([]*sqlgraph.CreateSpec, len(pcb.builders)) + nodes := make([]*Posting, len(pcb.builders)) + mutators := make([]Mutator, len(pcb.builders)) + for i := range pcb.builders { + func(i int, root context.Context) { + builder := pcb.builders[i] + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*PostingMutation) + 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], err = builder.createSpec() + if err != nil { + return nil, err + } + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, pcb.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, pcb.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 + if specs[i].ID.Value != nil { + id := specs[i].ID.Value.(int64) + nodes[i].ID = int(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, pcb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (pcb *PostingCreateBulk) SaveX(ctx context.Context) []*Posting { + v, err := pcb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (pcb *PostingCreateBulk) Exec(ctx context.Context) error { + _, err := pcb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (pcb *PostingCreateBulk) ExecX(ctx context.Context) { + if err := pcb.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/posting_delete.go b/ent/posting_delete.go new file mode 100644 index 0000000..dc5c768 --- /dev/null +++ b/ent/posting_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" + "github.com/techbloghub/server/ent/posting" + "github.com/techbloghub/server/ent/predicate" +) + +// PostingDelete is the builder for deleting a Posting entity. +type PostingDelete struct { + config + hooks []Hook + mutation *PostingMutation +} + +// Where appends a list predicates to the PostingDelete builder. +func (pd *PostingDelete) Where(ps ...predicate.Posting) *PostingDelete { + pd.mutation.Where(ps...) + return pd +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (pd *PostingDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, pd.sqlExec, pd.mutation, pd.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (pd *PostingDelete) ExecX(ctx context.Context) int { + n, err := pd.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (pd *PostingDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(posting.Table, sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt)) + if ps := pd.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, pd.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + pd.mutation.done = true + return affected, err +} + +// PostingDeleteOne is the builder for deleting a single Posting entity. +type PostingDeleteOne struct { + pd *PostingDelete +} + +// Where appends a list predicates to the PostingDelete builder. +func (pdo *PostingDeleteOne) Where(ps ...predicate.Posting) *PostingDeleteOne { + pdo.pd.mutation.Where(ps...) + return pdo +} + +// Exec executes the deletion query. +func (pdo *PostingDeleteOne) Exec(ctx context.Context) error { + n, err := pdo.pd.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{posting.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (pdo *PostingDeleteOne) ExecX(ctx context.Context) { + if err := pdo.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/posting_query.go b/ent/posting_query.go new file mode 100644 index 0000000..e2f7345 --- /dev/null +++ b/ent/posting_query.go @@ -0,0 +1,614 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" + "github.com/techbloghub/server/ent/predicate" +) + +// PostingQuery is the builder for querying Posting entities. +type PostingQuery struct { + config + ctx *QueryContext + order []posting.OrderOption + inters []Interceptor + predicates []predicate.Posting + withCompany *CompanyQuery + withFKs bool + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the PostingQuery builder. +func (pq *PostingQuery) Where(ps ...predicate.Posting) *PostingQuery { + pq.predicates = append(pq.predicates, ps...) + return pq +} + +// Limit the number of records to be returned by this query. +func (pq *PostingQuery) Limit(limit int) *PostingQuery { + pq.ctx.Limit = &limit + return pq +} + +// Offset to start from. +func (pq *PostingQuery) Offset(offset int) *PostingQuery { + pq.ctx.Offset = &offset + return pq +} + +// 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 (pq *PostingQuery) Unique(unique bool) *PostingQuery { + pq.ctx.Unique = &unique + return pq +} + +// Order specifies how the records should be ordered. +func (pq *PostingQuery) Order(o ...posting.OrderOption) *PostingQuery { + pq.order = append(pq.order, o...) + return pq +} + +// QueryCompany chains the current query on the "company" edge. +func (pq *PostingQuery) QueryCompany() *CompanyQuery { + query := (&CompanyClient{config: pq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := pq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := pq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(posting.Table, posting.FieldID, selector), + sqlgraph.To(company.Table, company.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, posting.CompanyTable, posting.CompanyColumn), + ) + fromU = sqlgraph.SetNeighbors(pq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first Posting entity from the query. +// Returns a *NotFoundError when no Posting was found. +func (pq *PostingQuery) First(ctx context.Context) (*Posting, error) { + nodes, err := pq.Limit(1).All(setContextOp(ctx, pq.ctx, ent.OpQueryFirst)) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{posting.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (pq *PostingQuery) FirstX(ctx context.Context) *Posting { + node, err := pq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first Posting ID from the query. +// Returns a *NotFoundError when no Posting ID was found. +func (pq *PostingQuery) FirstID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = pq.Limit(1).IDs(setContextOp(ctx, pq.ctx, ent.OpQueryFirstID)); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{posting.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (pq *PostingQuery) FirstIDX(ctx context.Context) int { + id, err := pq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single Posting entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one Posting entity is found. +// Returns a *NotFoundError when no Posting entities are found. +func (pq *PostingQuery) Only(ctx context.Context) (*Posting, error) { + nodes, err := pq.Limit(2).All(setContextOp(ctx, pq.ctx, ent.OpQueryOnly)) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{posting.Label} + default: + return nil, &NotSingularError{posting.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (pq *PostingQuery) OnlyX(ctx context.Context) *Posting { + node, err := pq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only Posting ID in the query. +// Returns a *NotSingularError when more than one Posting ID is found. +// Returns a *NotFoundError when no entities are found. +func (pq *PostingQuery) OnlyID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = pq.Limit(2).IDs(setContextOp(ctx, pq.ctx, ent.OpQueryOnlyID)); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{posting.Label} + default: + err = &NotSingularError{posting.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (pq *PostingQuery) OnlyIDX(ctx context.Context) int { + id, err := pq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of Postings. +func (pq *PostingQuery) All(ctx context.Context) ([]*Posting, error) { + ctx = setContextOp(ctx, pq.ctx, ent.OpQueryAll) + if err := pq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*Posting, *PostingQuery]() + return withInterceptors[[]*Posting](ctx, pq, qr, pq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (pq *PostingQuery) AllX(ctx context.Context) []*Posting { + nodes, err := pq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of Posting IDs. +func (pq *PostingQuery) IDs(ctx context.Context) (ids []int, err error) { + if pq.ctx.Unique == nil && pq.path != nil { + pq.Unique(true) + } + ctx = setContextOp(ctx, pq.ctx, ent.OpQueryIDs) + if err = pq.Select(posting.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (pq *PostingQuery) IDsX(ctx context.Context) []int { + ids, err := pq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (pq *PostingQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, pq.ctx, ent.OpQueryCount) + if err := pq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, pq, querierCount[*PostingQuery](), pq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (pq *PostingQuery) CountX(ctx context.Context) int { + count, err := pq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (pq *PostingQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, pq.ctx, ent.OpQueryExist) + switch _, err := pq.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 (pq *PostingQuery) ExistX(ctx context.Context) bool { + exist, err := pq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the PostingQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (pq *PostingQuery) Clone() *PostingQuery { + if pq == nil { + return nil + } + return &PostingQuery{ + config: pq.config, + ctx: pq.ctx.Clone(), + order: append([]posting.OrderOption{}, pq.order...), + inters: append([]Interceptor{}, pq.inters...), + predicates: append([]predicate.Posting{}, pq.predicates...), + withCompany: pq.withCompany.Clone(), + // clone intermediate query. + sql: pq.sql.Clone(), + path: pq.path, + } +} + +// WithCompany tells the query-builder to eager-load the nodes that are connected to +// the "company" edge. The optional arguments are used to configure the query builder of the edge. +func (pq *PostingQuery) WithCompany(opts ...func(*CompanyQuery)) *PostingQuery { + query := (&CompanyClient{config: pq.config}).Query() + for _, opt := range opts { + opt(query) + } + pq.withCompany = query + return pq +} + +// 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 { +// Title string `json:"title,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Posting.Query(). +// GroupBy(posting.FieldTitle). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (pq *PostingQuery) GroupBy(field string, fields ...string) *PostingGroupBy { + pq.ctx.Fields = append([]string{field}, fields...) + grbuild := &PostingGroupBy{build: pq} + grbuild.flds = &pq.ctx.Fields + grbuild.label = posting.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 { +// Title string `json:"title,omitempty"` +// } +// +// client.Posting.Query(). +// Select(posting.FieldTitle). +// Scan(ctx, &v) +func (pq *PostingQuery) Select(fields ...string) *PostingSelect { + pq.ctx.Fields = append(pq.ctx.Fields, fields...) + sbuild := &PostingSelect{PostingQuery: pq} + sbuild.label = posting.Label + sbuild.flds, sbuild.scan = &pq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a PostingSelect configured with the given aggregations. +func (pq *PostingQuery) Aggregate(fns ...AggregateFunc) *PostingSelect { + return pq.Select().Aggregate(fns...) +} + +func (pq *PostingQuery) prepareQuery(ctx context.Context) error { + for _, inter := range pq.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, pq); err != nil { + return err + } + } + } + for _, f := range pq.ctx.Fields { + if !posting.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if pq.path != nil { + prev, err := pq.path(ctx) + if err != nil { + return err + } + pq.sql = prev + } + return nil +} + +func (pq *PostingQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Posting, error) { + var ( + nodes = []*Posting{} + withFKs = pq.withFKs + _spec = pq.querySpec() + loadedTypes = [1]bool{ + pq.withCompany != nil, + } + ) + if pq.withCompany != nil { + withFKs = true + } + if withFKs { + _spec.Node.Columns = append(_spec.Node.Columns, posting.ForeignKeys...) + } + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*Posting).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &Posting{config: pq.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, pq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := pq.withCompany; query != nil { + if err := pq.loadCompany(ctx, query, nodes, nil, + func(n *Posting, e *Company) { n.Edges.Company = e }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (pq *PostingQuery) loadCompany(ctx context.Context, query *CompanyQuery, nodes []*Posting, init func(*Posting), assign func(*Posting, *Company)) error { + ids := make([]int, 0, len(nodes)) + nodeids := make(map[int][]*Posting) + for i := range nodes { + if nodes[i].company_postings == nil { + continue + } + fk := *nodes[i].company_postings + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(company.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 "company_postings" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} + +func (pq *PostingQuery) sqlCount(ctx context.Context) (int, error) { + _spec := pq.querySpec() + _spec.Node.Columns = pq.ctx.Fields + if len(pq.ctx.Fields) > 0 { + _spec.Unique = pq.ctx.Unique != nil && *pq.ctx.Unique + } + return sqlgraph.CountNodes(ctx, pq.driver, _spec) +} + +func (pq *PostingQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(posting.Table, posting.Columns, sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt)) + _spec.From = pq.sql + if unique := pq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if pq.path != nil { + _spec.Unique = true + } + if fields := pq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, posting.FieldID) + for i := range fields { + if fields[i] != posting.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := pq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := pq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := pq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := pq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (pq *PostingQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(pq.driver.Dialect()) + t1 := builder.Table(posting.Table) + columns := pq.ctx.Fields + if len(columns) == 0 { + columns = posting.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if pq.sql != nil { + selector = pq.sql + selector.Select(selector.Columns(columns...)...) + } + if pq.ctx.Unique != nil && *pq.ctx.Unique { + selector.Distinct() + } + for _, p := range pq.predicates { + p(selector) + } + for _, p := range pq.order { + p(selector) + } + if offset := pq.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 := pq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// PostingGroupBy is the group-by builder for Posting entities. +type PostingGroupBy struct { + selector + build *PostingQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (pgb *PostingGroupBy) Aggregate(fns ...AggregateFunc) *PostingGroupBy { + pgb.fns = append(pgb.fns, fns...) + return pgb +} + +// Scan applies the selector query and scans the result into the given value. +func (pgb *PostingGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, pgb.build.ctx, ent.OpQueryGroupBy) + if err := pgb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*PostingQuery, *PostingGroupBy](ctx, pgb.build, pgb, pgb.build.inters, v) +} + +func (pgb *PostingGroupBy) sqlScan(ctx context.Context, root *PostingQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(pgb.fns)) + for _, fn := range pgb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*pgb.flds)+len(pgb.fns)) + for _, f := range *pgb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*pgb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := pgb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// PostingSelect is the builder for selecting fields of Posting entities. +type PostingSelect struct { + *PostingQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (ps *PostingSelect) Aggregate(fns ...AggregateFunc) *PostingSelect { + ps.fns = append(ps.fns, fns...) + return ps +} + +// Scan applies the selector query and scans the result into the given value. +func (ps *PostingSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, ps.ctx, ent.OpQuerySelect) + if err := ps.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*PostingQuery, *PostingSelect](ctx, ps.PostingQuery, ps, ps.inters, v) +} + +func (ps *PostingSelect) sqlScan(ctx context.Context, root *PostingQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(ps.fns)) + for _, fn := range ps.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*ps.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 := ps.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/ent/posting_update.go b/ent/posting_update.go new file mode 100644 index 0000000..cfa7839 --- /dev/null +++ b/ent/posting_update.go @@ -0,0 +1,417 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "net/url" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" + "github.com/techbloghub/server/ent/predicate" + "github.com/techbloghub/server/internal/schemasupport" +) + +// PostingUpdate is the builder for updating Posting entities. +type PostingUpdate struct { + config + hooks []Hook + mutation *PostingMutation +} + +// Where appends a list predicates to the PostingUpdate builder. +func (pu *PostingUpdate) Where(ps ...predicate.Posting) *PostingUpdate { + pu.mutation.Where(ps...) + return pu +} + +// SetTitle sets the "title" field. +func (pu *PostingUpdate) SetTitle(s string) *PostingUpdate { + pu.mutation.SetTitle(s) + return pu +} + +// SetNillableTitle sets the "title" field if the given value is not nil. +func (pu *PostingUpdate) SetNillableTitle(s *string) *PostingUpdate { + if s != nil { + pu.SetTitle(*s) + } + return pu +} + +// SetURL sets the "url" field. +func (pu *PostingUpdate) SetURL(u *url.URL) *PostingUpdate { + pu.mutation.SetURL(u) + return pu +} + +// SetPublishedAt sets the "published_at" field. +func (pu *PostingUpdate) SetPublishedAt(t time.Time) *PostingUpdate { + pu.mutation.SetPublishedAt(t) + return pu +} + +// SetNillablePublishedAt sets the "published_at" field if the given value is not nil. +func (pu *PostingUpdate) SetNillablePublishedAt(t *time.Time) *PostingUpdate { + if t != nil { + pu.SetPublishedAt(*t) + } + return pu +} + +// SetTags sets the "tags" field. +func (pu *PostingUpdate) SetTags(st *schemasupport.PostingTags) *PostingUpdate { + pu.mutation.SetTags(st) + return pu +} + +// ClearTags clears the value of the "tags" field. +func (pu *PostingUpdate) ClearTags() *PostingUpdate { + pu.mutation.ClearTags() + return pu +} + +// SetCompanyID sets the "company" edge to the Company entity by ID. +func (pu *PostingUpdate) SetCompanyID(id int) *PostingUpdate { + pu.mutation.SetCompanyID(id) + return pu +} + +// SetNillableCompanyID sets the "company" edge to the Company entity by ID if the given value is not nil. +func (pu *PostingUpdate) SetNillableCompanyID(id *int) *PostingUpdate { + if id != nil { + pu = pu.SetCompanyID(*id) + } + return pu +} + +// SetCompany sets the "company" edge to the Company entity. +func (pu *PostingUpdate) SetCompany(c *Company) *PostingUpdate { + return pu.SetCompanyID(c.ID) +} + +// Mutation returns the PostingMutation object of the builder. +func (pu *PostingUpdate) Mutation() *PostingMutation { + return pu.mutation +} + +// ClearCompany clears the "company" edge to the Company entity. +func (pu *PostingUpdate) ClearCompany() *PostingUpdate { + pu.mutation.ClearCompany() + return pu +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (pu *PostingUpdate) Save(ctx context.Context) (int, error) { + return withHooks(ctx, pu.sqlSave, pu.mutation, pu.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (pu *PostingUpdate) SaveX(ctx context.Context) int { + affected, err := pu.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (pu *PostingUpdate) Exec(ctx context.Context) error { + _, err := pu.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (pu *PostingUpdate) ExecX(ctx context.Context) { + if err := pu.Exec(ctx); err != nil { + panic(err) + } +} + +func (pu *PostingUpdate) sqlSave(ctx context.Context) (n int, err error) { + _spec := sqlgraph.NewUpdateSpec(posting.Table, posting.Columns, sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt)) + if ps := pu.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := pu.mutation.Title(); ok { + _spec.SetField(posting.FieldTitle, field.TypeString, value) + } + if value, ok := pu.mutation.URL(); ok { + vv, err := posting.ValueScanner.URL.Value(value) + if err != nil { + return 0, err + } + _spec.SetField(posting.FieldURL, field.TypeString, vv) + } + if value, ok := pu.mutation.PublishedAt(); ok { + _spec.SetField(posting.FieldPublishedAt, field.TypeTime, value) + } + if value, ok := pu.mutation.Tags(); ok { + _spec.SetField(posting.FieldTags, field.TypeOther, value) + } + if pu.mutation.TagsCleared() { + _spec.ClearField(posting.FieldTags, field.TypeOther) + } + if pu.mutation.CompanyCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: posting.CompanyTable, + Columns: []string{posting.CompanyColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(company.FieldID, field.TypeInt), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := pu.mutation.CompanyIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: posting.CompanyTable, + Columns: []string{posting.CompanyColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(company.FieldID, field.TypeInt), + }, + } + 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, pu.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{posting.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + pu.mutation.done = true + return n, nil +} + +// PostingUpdateOne is the builder for updating a single Posting entity. +type PostingUpdateOne struct { + config + fields []string + hooks []Hook + mutation *PostingMutation +} + +// SetTitle sets the "title" field. +func (puo *PostingUpdateOne) SetTitle(s string) *PostingUpdateOne { + puo.mutation.SetTitle(s) + return puo +} + +// SetNillableTitle sets the "title" field if the given value is not nil. +func (puo *PostingUpdateOne) SetNillableTitle(s *string) *PostingUpdateOne { + if s != nil { + puo.SetTitle(*s) + } + return puo +} + +// SetURL sets the "url" field. +func (puo *PostingUpdateOne) SetURL(u *url.URL) *PostingUpdateOne { + puo.mutation.SetURL(u) + return puo +} + +// SetPublishedAt sets the "published_at" field. +func (puo *PostingUpdateOne) SetPublishedAt(t time.Time) *PostingUpdateOne { + puo.mutation.SetPublishedAt(t) + return puo +} + +// SetNillablePublishedAt sets the "published_at" field if the given value is not nil. +func (puo *PostingUpdateOne) SetNillablePublishedAt(t *time.Time) *PostingUpdateOne { + if t != nil { + puo.SetPublishedAt(*t) + } + return puo +} + +// SetTags sets the "tags" field. +func (puo *PostingUpdateOne) SetTags(st *schemasupport.PostingTags) *PostingUpdateOne { + puo.mutation.SetTags(st) + return puo +} + +// ClearTags clears the value of the "tags" field. +func (puo *PostingUpdateOne) ClearTags() *PostingUpdateOne { + puo.mutation.ClearTags() + return puo +} + +// SetCompanyID sets the "company" edge to the Company entity by ID. +func (puo *PostingUpdateOne) SetCompanyID(id int) *PostingUpdateOne { + puo.mutation.SetCompanyID(id) + return puo +} + +// SetNillableCompanyID sets the "company" edge to the Company entity by ID if the given value is not nil. +func (puo *PostingUpdateOne) SetNillableCompanyID(id *int) *PostingUpdateOne { + if id != nil { + puo = puo.SetCompanyID(*id) + } + return puo +} + +// SetCompany sets the "company" edge to the Company entity. +func (puo *PostingUpdateOne) SetCompany(c *Company) *PostingUpdateOne { + return puo.SetCompanyID(c.ID) +} + +// Mutation returns the PostingMutation object of the builder. +func (puo *PostingUpdateOne) Mutation() *PostingMutation { + return puo.mutation +} + +// ClearCompany clears the "company" edge to the Company entity. +func (puo *PostingUpdateOne) ClearCompany() *PostingUpdateOne { + puo.mutation.ClearCompany() + return puo +} + +// Where appends a list predicates to the PostingUpdate builder. +func (puo *PostingUpdateOne) Where(ps ...predicate.Posting) *PostingUpdateOne { + puo.mutation.Where(ps...) + return puo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (puo *PostingUpdateOne) Select(field string, fields ...string) *PostingUpdateOne { + puo.fields = append([]string{field}, fields...) + return puo +} + +// Save executes the query and returns the updated Posting entity. +func (puo *PostingUpdateOne) Save(ctx context.Context) (*Posting, error) { + return withHooks(ctx, puo.sqlSave, puo.mutation, puo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (puo *PostingUpdateOne) SaveX(ctx context.Context) *Posting { + node, err := puo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (puo *PostingUpdateOne) Exec(ctx context.Context) error { + _, err := puo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (puo *PostingUpdateOne) ExecX(ctx context.Context) { + if err := puo.Exec(ctx); err != nil { + panic(err) + } +} + +func (puo *PostingUpdateOne) sqlSave(ctx context.Context) (_node *Posting, err error) { + _spec := sqlgraph.NewUpdateSpec(posting.Table, posting.Columns, sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt)) + id, ok := puo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Posting.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := puo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, posting.FieldID) + for _, f := range fields { + if !posting.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != posting.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := puo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := puo.mutation.Title(); ok { + _spec.SetField(posting.FieldTitle, field.TypeString, value) + } + if value, ok := puo.mutation.URL(); ok { + vv, err := posting.ValueScanner.URL.Value(value) + if err != nil { + return nil, err + } + _spec.SetField(posting.FieldURL, field.TypeString, vv) + } + if value, ok := puo.mutation.PublishedAt(); ok { + _spec.SetField(posting.FieldPublishedAt, field.TypeTime, value) + } + if value, ok := puo.mutation.Tags(); ok { + _spec.SetField(posting.FieldTags, field.TypeOther, value) + } + if puo.mutation.TagsCleared() { + _spec.ClearField(posting.FieldTags, field.TypeOther) + } + if puo.mutation.CompanyCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: posting.CompanyTable, + Columns: []string{posting.CompanyColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(company.FieldID, field.TypeInt), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := puo.mutation.CompanyIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: posting.CompanyTable, + Columns: []string{posting.CompanyColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(company.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &Posting{config: puo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, puo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{posting.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + puo.mutation.done = true + return _node, nil +} diff --git a/ent/predicate/predicate.go b/ent/predicate/predicate.go index cb80009..ef0ea4c 100644 --- a/ent/predicate/predicate.go +++ b/ent/predicate/predicate.go @@ -20,5 +20,19 @@ func CompanyOrErr(p Company, err error) Company { } } +// Posting is the predicate function for posting builders. +type Posting func(*sql.Selector) + +// PostingOrErr calls the predicate only if the error is not nit. +func PostingOrErr(p Posting, err error) Posting { + return func(s *sql.Selector) { + if err != nil { + s.AddError(err) + return + } + p(s) + } +} + // Tag is the predicate function for tag builders. type Tag func(*sql.Selector) diff --git a/ent/runtime/runtime.go b/ent/runtime/runtime.go index 85cc2c2..1192a11 100644 --- a/ent/runtime/runtime.go +++ b/ent/runtime/runtime.go @@ -7,6 +7,7 @@ import ( "time" "github.com/techbloghub/server/ent/company" + "github.com/techbloghub/server/ent/posting" "github.com/techbloghub/server/ent/schema" "github.com/techbloghub/server/ent/tag" @@ -45,6 +46,11 @@ func init() { // companyDescRssURL is the schema descriptor for rss_url field. companyDescRssURL := companyFields[3].Descriptor() company.ValueScanner.RssURL = companyDescRssURL.ValueScanner.(field.TypeValueScanner[*url.URL]) + postingFields := schema.Posting{}.Fields() + _ = postingFields + // postingDescURL is the schema descriptor for url field. + postingDescURL := postingFields[1].Descriptor() + posting.ValueScanner.URL = postingDescURL.ValueScanner.(field.TypeValueScanner[*url.URL]) tagMixin := schema.Tag{}.Mixin() tagMixinHooks1 := tagMixin[1].Hooks() tag.Hooks[0] = tagMixinHooks1[0] diff --git a/ent/tx.go b/ent/tx.go index eb5d870..bf95be1 100644 --- a/ent/tx.go +++ b/ent/tx.go @@ -14,6 +14,8 @@ type Tx struct { config // Company is the client for interacting with the Company builders. Company *CompanyClient + // Posting is the client for interacting with the Posting builders. + Posting *PostingClient // Tag is the client for interacting with the Tag builders. Tag *TagClient @@ -148,6 +150,7 @@ func (tx *Tx) Client() *Client { func (tx *Tx) init() { tx.Company = NewCompanyClient(tx.config) + tx.Posting = NewPostingClient(tx.config) tx.Tag = NewTagClient(tx.config) } diff --git a/internal/schemasupport/posting_tags.go b/internal/schemasupport/posting_tags.go new file mode 100644 index 0000000..ea5f197 --- /dev/null +++ b/internal/schemasupport/posting_tags.go @@ -0,0 +1,17 @@ +package schemasupport + +import ( + "database/sql/driver" + + "github.com/lib/pq" +) + +type PostingTags []string + +func (s PostingTags) Value() (driver.Value, error) { + return pq.Array(s).Value() +} + +func (s *PostingTags) Scan(value interface{}) error { + return pq.Array(s).Scan(value) +} From 9751ceeead5d9a63db95d2c6e7c7590e87881059 Mon Sep 17 00:00:00 2001 From: pilyang Date: Sat, 15 Feb 2025 23:01:06 +0900 Subject: [PATCH 3/6] chore: create migraiont by atlas --- ent/migrate/migrations/20250215135939_create_posting.sql | 4 ++++ ent/migrate/migrations/atlas.sum | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 ent/migrate/migrations/20250215135939_create_posting.sql diff --git a/ent/migrate/migrations/20250215135939_create_posting.sql b/ent/migrate/migrations/20250215135939_create_posting.sql new file mode 100644 index 0000000..df25753 --- /dev/null +++ b/ent/migrate/migrations/20250215135939_create_posting.sql @@ -0,0 +1,4 @@ +-- Create "postings" table +CREATE TABLE "postings" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "title" character varying NOT NULL, "url" character varying NOT NULL, "published_at" timestamptz NOT NULL, "tags" text[] NULL, "company_postings" bigint NULL, PRIMARY KEY ("id"), CONSTRAINT "postings_companies_postings" FOREIGN KEY ("company_postings") REFERENCES "companies" ("id") ON UPDATE NO ACTION ON DELETE SET NULL); +-- Create index "postings_url_key" to table: "postings" +CREATE UNIQUE INDEX "postings_url_key" ON "postings" ("url"); diff --git a/ent/migrate/migrations/atlas.sum b/ent/migrate/migrations/atlas.sum index 41562da..8860854 100644 --- a/ent/migrate/migrations/atlas.sum +++ b/ent/migrate/migrations/atlas.sum @@ -1,3 +1,4 @@ -h1:alOmJfaGEBI+WU4MkAO/eJouQLYqLbPL+RxYOjF4eCc= +h1:h455WQyMRJnQV+jKLUeCAv2dNBQ8Nc9Bp4P1w+JZ7Qc= 20250118142329_create_company.sql h1:HDbigYfm6G4w1+Kzgwl+rMabQjLnctFRgIdyKGRxsKc= 20250202031149_create-tag.sql h1:0hc8Co99P4bEvB9KZT3OUZflUCnjScW+UdrTR/WC0vA= +20250215135939_create_posting.sql h1:hTh6qFzC24ZPJURyGBaHI8lzi60FYMarYpZUN5yV2tg= From e6aeda60f0c68e8891739b2c38c629c3a9e99b10 Mon Sep 17 00:00:00 2001 From: pilyang Date: Sun, 16 Feb 2025 18:49:00 +0900 Subject: [PATCH 4/6] feat: add time mixin to posting --- ent/schema/posting.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ent/schema/posting.go b/ent/schema/posting.go index 08177f5..a256263 100644 --- a/ent/schema/posting.go +++ b/ent/schema/posting.go @@ -7,6 +7,7 @@ import ( "entgo.io/ent/dialect" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" + "entgo.io/ent/schema/mixin" "github.com/techbloghub/server/internal/schemasupport" ) @@ -16,6 +17,12 @@ type Posting struct { ent.Schema } +func (Posting) Mixin() []ent.Mixin { + return []ent.Mixin{ + mixin.Time{}, + } +} + // Fields of the Posting. func (Posting) Fields() []ent.Field { return []ent.Field{ From 521976a67d2a7d1e97e62b316bcdb81c6e1b73ee Mon Sep 17 00:00:00 2001 From: pilyang Date: Sun, 16 Feb 2025 18:49:09 +0900 Subject: [PATCH 5/6] chore: generate by ent --- ent/internal/schema.go | 2 +- ent/migrate/schema.go | 4 +- ent/mutation.go | 110 ++++++++++++++++++++++++++++++++++++++++- ent/posting.go | 24 ++++++++- ent/posting/posting.go | 23 +++++++++ ent/posting/where.go | 90 +++++++++++++++++++++++++++++++++ ent/posting_create.go | 56 +++++++++++++++++++++ ent/posting_query.go | 8 +-- ent/posting_update.go | 36 ++++++++++++++ ent/runtime/runtime.go | 13 +++++ 10 files changed, 358 insertions(+), 8 deletions(-) diff --git a/ent/internal/schema.go b/ent/internal/schema.go index f942142..5b4aebf 100644 --- a/ent/internal/schema.go +++ b/ent/internal/schema.go @@ -6,4 +6,4 @@ // Package internal holds a loadable version of the latest schema. package internal -const Schema = "{\"Schema\":\"github.com/techbloghub/server/ent/schema\",\"Package\":\"github.com/techbloghub/server/ent\",\"Schemas\":[{\"name\":\"Company\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"postings\",\"type\":\"Posting\"}],\"fields\":[{\"name\":\"create_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"update_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"delete_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"logo_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"blog_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"rss_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}]},{\"name\":\"Posting\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"company\",\"type\":\"Company\",\"ref_name\":\"postings\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"title\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"unique\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"published_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"tags\",\"type\":{\"Type\":8,\"Ident\":\"*schemasupport.PostingTags\",\"PkgPath\":\"github.com/techbloghub/server/internal/schemasupport\",\"PkgName\":\"schemasupport\",\"Nillable\":true,\"RType\":{\"Name\":\"PostingTags\",\"Ident\":\"schemasupport.PostingTags\",\"Kind\":22,\"PkgPath\":\"github.com/techbloghub/server/internal/schemasupport\",\"Methods\":{\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"postgres\":\"text[]\"}}]},{\"name\":\"Tag\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"create_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"update_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"delete_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}]}],\"Features\":[\"intercept\",\"schema/snapshot\"]}" +const Schema = "{\"Schema\":\"github.com/techbloghub/server/ent/schema\",\"Package\":\"github.com/techbloghub/server/ent\",\"Schemas\":[{\"name\":\"Company\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"postings\",\"type\":\"Posting\"}],\"fields\":[{\"name\":\"create_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"update_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"delete_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"logo_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"blog_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"rss_url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}]},{\"name\":\"Posting\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"company\",\"type\":\"Company\",\"ref_name\":\"postings\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"create_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"update_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"title\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"url\",\"type\":{\"Type\":7,\"Ident\":\"*url.URL\",\"PkgPath\":\"net/url\",\"PkgName\":\"url\",\"Nillable\":true,\"RType\":{\"Name\":\"URL\",\"Ident\":\"url.URL\",\"Kind\":22,\"PkgPath\":\"net/url\",\"Methods\":{\"EscapedFragment\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"EscapedPath\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Hostname\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"IsAbs\":{\"In\":[],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"JoinPath\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Parse\":{\"In\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Port\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"Query\":{\"In\":[],\"Out\":[{\"Name\":\"Values\",\"Ident\":\"url.Values\",\"Kind\":21,\"PkgPath\":\"net/url\",\"Methods\":null}]},\"Redacted\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"RequestURI\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"ResolveReference\":{\"In\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"\",\"Ident\":\"*url.URL\",\"Kind\":22,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"value_scanner\":true,\"unique\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"published_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"tags\",\"type\":{\"Type\":8,\"Ident\":\"*schemasupport.PostingTags\",\"PkgPath\":\"github.com/techbloghub/server/internal/schemasupport\",\"PkgName\":\"schemasupport\",\"Nillable\":true,\"RType\":{\"Name\":\"PostingTags\",\"Ident\":\"schemasupport.PostingTags\",\"Kind\":22,\"PkgPath\":\"github.com/techbloghub/server/internal/schemasupport\",\"Methods\":{\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"postgres\":\"text[]\"}}]},{\"name\":\"Tag\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"create_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"update_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0}},{\"name\":\"delete_time\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":1}]}],\"Features\":[\"intercept\",\"schema/snapshot\"]}" diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 3e5d8fd..6033a52 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -28,6 +28,8 @@ var ( // PostingsColumns holds the columns for the "postings" table. PostingsColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, + {Name: "create_time", Type: field.TypeTime}, + {Name: "update_time", Type: field.TypeTime}, {Name: "title", Type: field.TypeString}, {Name: "url", Type: field.TypeString, Unique: true}, {Name: "published_at", Type: field.TypeTime}, @@ -42,7 +44,7 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "postings_companies_postings", - Columns: []*schema.Column{PostingsColumns[5]}, + Columns: []*schema.Column{PostingsColumns[7]}, RefColumns: []*schema.Column{CompaniesColumns[0]}, OnDelete: schema.SetNull, }, diff --git a/ent/mutation.go b/ent/mutation.go index dcdd093..40bf076 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -804,6 +804,8 @@ type PostingMutation struct { op Op typ string id *int + create_time *time.Time + update_time *time.Time title *string url **url.URL published_at *time.Time @@ -914,6 +916,78 @@ func (m *PostingMutation) IDs(ctx context.Context) ([]int, error) { } } +// SetCreateTime sets the "create_time" field. +func (m *PostingMutation) SetCreateTime(t time.Time) { + m.create_time = &t +} + +// CreateTime returns the value of the "create_time" field in the mutation. +func (m *PostingMutation) CreateTime() (r time.Time, exists bool) { + v := m.create_time + if v == nil { + return + } + return *v, true +} + +// OldCreateTime returns the old "create_time" field's value of the Posting entity. +// If the Posting 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 *PostingMutation) OldCreateTime(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreateTime is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreateTime requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreateTime: %w", err) + } + return oldValue.CreateTime, nil +} + +// ResetCreateTime resets all changes to the "create_time" field. +func (m *PostingMutation) ResetCreateTime() { + m.create_time = nil +} + +// SetUpdateTime sets the "update_time" field. +func (m *PostingMutation) SetUpdateTime(t time.Time) { + m.update_time = &t +} + +// UpdateTime returns the value of the "update_time" field in the mutation. +func (m *PostingMutation) UpdateTime() (r time.Time, exists bool) { + v := m.update_time + if v == nil { + return + } + return *v, true +} + +// OldUpdateTime returns the old "update_time" field's value of the Posting entity. +// If the Posting 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 *PostingMutation) OldUpdateTime(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUpdateTime is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUpdateTime requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUpdateTime: %w", err) + } + return oldValue.UpdateTime, nil +} + +// ResetUpdateTime resets all changes to the "update_time" field. +func (m *PostingMutation) ResetUpdateTime() { + m.update_time = nil +} + // SetTitle sets the "title" field. func (m *PostingMutation) SetTitle(s string) { m.title = &s @@ -1144,7 +1218,13 @@ func (m *PostingMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *PostingMutation) Fields() []string { - fields := make([]string, 0, 4) + fields := make([]string, 0, 6) + if m.create_time != nil { + fields = append(fields, posting.FieldCreateTime) + } + if m.update_time != nil { + fields = append(fields, posting.FieldUpdateTime) + } if m.title != nil { fields = append(fields, posting.FieldTitle) } @@ -1165,6 +1245,10 @@ func (m *PostingMutation) Fields() []string { // schema. func (m *PostingMutation) Field(name string) (ent.Value, bool) { switch name { + case posting.FieldCreateTime: + return m.CreateTime() + case posting.FieldUpdateTime: + return m.UpdateTime() case posting.FieldTitle: return m.Title() case posting.FieldURL: @@ -1182,6 +1266,10 @@ func (m *PostingMutation) Field(name string) (ent.Value, bool) { // database failed. func (m *PostingMutation) OldField(ctx context.Context, name string) (ent.Value, error) { switch name { + case posting.FieldCreateTime: + return m.OldCreateTime(ctx) + case posting.FieldUpdateTime: + return m.OldUpdateTime(ctx) case posting.FieldTitle: return m.OldTitle(ctx) case posting.FieldURL: @@ -1199,6 +1287,20 @@ func (m *PostingMutation) OldField(ctx context.Context, name string) (ent.Value, // type. func (m *PostingMutation) SetField(name string, value ent.Value) error { switch name { + case posting.FieldCreateTime: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreateTime(v) + return nil + case posting.FieldUpdateTime: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdateTime(v) + return nil case posting.FieldTitle: v, ok := value.(string) if !ok { @@ -1285,6 +1387,12 @@ func (m *PostingMutation) ClearField(name string) error { // It returns an error if the field is not defined in the schema. func (m *PostingMutation) ResetField(name string) error { switch name { + case posting.FieldCreateTime: + m.ResetCreateTime() + return nil + case posting.FieldUpdateTime: + m.ResetUpdateTime() + return nil case posting.FieldTitle: m.ResetTitle() return nil diff --git a/ent/posting.go b/ent/posting.go index 704cdd7..a7c3675 100644 --- a/ent/posting.go +++ b/ent/posting.go @@ -20,6 +20,10 @@ type Posting struct { config `json:"-"` // ID of the ent. ID int `json:"id,omitempty"` + // CreateTime holds the value of the "create_time" field. + CreateTime time.Time `json:"create_time,omitempty"` + // UpdateTime holds the value of the "update_time" field. + UpdateTime time.Time `json:"update_time,omitempty"` // Title holds the value of the "title" field. Title string `json:"title,omitempty"` // URL holds the value of the "url" field. @@ -66,7 +70,7 @@ func (*Posting) scanValues(columns []string) ([]any, error) { values[i] = new(sql.NullInt64) case posting.FieldTitle: values[i] = new(sql.NullString) - case posting.FieldPublishedAt: + case posting.FieldCreateTime, posting.FieldUpdateTime, posting.FieldPublishedAt: values[i] = new(sql.NullTime) case posting.FieldURL: values[i] = posting.ValueScanner.URL.ScanValue() @@ -93,6 +97,18 @@ func (po *Posting) assignValues(columns []string, values []any) error { return fmt.Errorf("unexpected type %T for field id", value) } po.ID = int(value.Int64) + case posting.FieldCreateTime: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field create_time", values[i]) + } else if value.Valid { + po.CreateTime = value.Time + } + case posting.FieldUpdateTime: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field update_time", values[i]) + } else if value.Valid { + po.UpdateTime = value.Time + } case posting.FieldTitle: if value, ok := values[i].(*sql.NullString); !ok { return fmt.Errorf("unexpected type %T for field title", values[i]) @@ -165,6 +181,12 @@ func (po *Posting) String() string { var builder strings.Builder builder.WriteString("Posting(") builder.WriteString(fmt.Sprintf("id=%v, ", po.ID)) + builder.WriteString("create_time=") + builder.WriteString(po.CreateTime.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("update_time=") + builder.WriteString(po.UpdateTime.Format(time.ANSIC)) + builder.WriteString(", ") builder.WriteString("title=") builder.WriteString(po.Title) builder.WriteString(", ") diff --git a/ent/posting/posting.go b/ent/posting/posting.go index 11044f1..085127c 100644 --- a/ent/posting/posting.go +++ b/ent/posting/posting.go @@ -4,6 +4,7 @@ package posting import ( "net/url" + "time" "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" @@ -15,6 +16,10 @@ const ( Label = "posting" // FieldID holds the string denoting the id field in the database. FieldID = "id" + // FieldCreateTime holds the string denoting the create_time field in the database. + FieldCreateTime = "create_time" + // FieldUpdateTime holds the string denoting the update_time field in the database. + FieldUpdateTime = "update_time" // FieldTitle holds the string denoting the title field in the database. FieldTitle = "title" // FieldURL holds the string denoting the url field in the database. @@ -39,6 +44,8 @@ const ( // Columns holds all SQL columns for posting fields. var Columns = []string{ FieldID, + FieldCreateTime, + FieldUpdateTime, FieldTitle, FieldURL, FieldPublishedAt, @@ -67,6 +74,12 @@ func ValidColumn(column string) bool { } var ( + // DefaultCreateTime holds the default value on creation for the "create_time" field. + DefaultCreateTime func() time.Time + // DefaultUpdateTime holds the default value on creation for the "update_time" field. + DefaultUpdateTime func() time.Time + // UpdateDefaultUpdateTime holds the default value on update for the "update_time" field. + UpdateDefaultUpdateTime func() time.Time // ValueScanner of all Posting fields. ValueScanner struct { URL field.TypeValueScanner[*url.URL] @@ -81,6 +94,16 @@ func ByID(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldID, opts...).ToFunc() } +// ByCreateTime orders the results by the create_time field. +func ByCreateTime(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreateTime, opts...).ToFunc() +} + +// ByUpdateTime orders the results by the update_time field. +func ByUpdateTime(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldUpdateTime, opts...).ToFunc() +} + // ByTitle orders the results by the title field. func ByTitle(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldTitle, opts...).ToFunc() diff --git a/ent/posting/where.go b/ent/posting/where.go index 074a994..e9777fd 100644 --- a/ent/posting/where.go +++ b/ent/posting/where.go @@ -58,6 +58,16 @@ func IDLTE(id int) predicate.Posting { return predicate.Posting(sql.FieldLTE(FieldID, id)) } +// CreateTime applies equality check predicate on the "create_time" field. It's identical to CreateTimeEQ. +func CreateTime(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldCreateTime, v)) +} + +// UpdateTime applies equality check predicate on the "update_time" field. It's identical to UpdateTimeEQ. +func UpdateTime(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldUpdateTime, v)) +} + // Title applies equality check predicate on the "title" field. It's identical to TitleEQ. func Title(v string) predicate.Posting { return predicate.Posting(sql.FieldEQ(FieldTitle, v)) @@ -79,6 +89,86 @@ func Tags(v *schemasupport.PostingTags) predicate.Posting { return predicate.Posting(sql.FieldEQ(FieldTags, v)) } +// CreateTimeEQ applies the EQ predicate on the "create_time" field. +func CreateTimeEQ(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldCreateTime, v)) +} + +// CreateTimeNEQ applies the NEQ predicate on the "create_time" field. +func CreateTimeNEQ(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldNEQ(FieldCreateTime, v)) +} + +// CreateTimeIn applies the In predicate on the "create_time" field. +func CreateTimeIn(vs ...time.Time) predicate.Posting { + return predicate.Posting(sql.FieldIn(FieldCreateTime, vs...)) +} + +// CreateTimeNotIn applies the NotIn predicate on the "create_time" field. +func CreateTimeNotIn(vs ...time.Time) predicate.Posting { + return predicate.Posting(sql.FieldNotIn(FieldCreateTime, vs...)) +} + +// CreateTimeGT applies the GT predicate on the "create_time" field. +func CreateTimeGT(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldGT(FieldCreateTime, v)) +} + +// CreateTimeGTE applies the GTE predicate on the "create_time" field. +func CreateTimeGTE(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldGTE(FieldCreateTime, v)) +} + +// CreateTimeLT applies the LT predicate on the "create_time" field. +func CreateTimeLT(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldLT(FieldCreateTime, v)) +} + +// CreateTimeLTE applies the LTE predicate on the "create_time" field. +func CreateTimeLTE(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldLTE(FieldCreateTime, v)) +} + +// UpdateTimeEQ applies the EQ predicate on the "update_time" field. +func UpdateTimeEQ(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldEQ(FieldUpdateTime, v)) +} + +// UpdateTimeNEQ applies the NEQ predicate on the "update_time" field. +func UpdateTimeNEQ(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldNEQ(FieldUpdateTime, v)) +} + +// UpdateTimeIn applies the In predicate on the "update_time" field. +func UpdateTimeIn(vs ...time.Time) predicate.Posting { + return predicate.Posting(sql.FieldIn(FieldUpdateTime, vs...)) +} + +// UpdateTimeNotIn applies the NotIn predicate on the "update_time" field. +func UpdateTimeNotIn(vs ...time.Time) predicate.Posting { + return predicate.Posting(sql.FieldNotIn(FieldUpdateTime, vs...)) +} + +// UpdateTimeGT applies the GT predicate on the "update_time" field. +func UpdateTimeGT(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldGT(FieldUpdateTime, v)) +} + +// UpdateTimeGTE applies the GTE predicate on the "update_time" field. +func UpdateTimeGTE(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldGTE(FieldUpdateTime, v)) +} + +// UpdateTimeLT applies the LT predicate on the "update_time" field. +func UpdateTimeLT(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldLT(FieldUpdateTime, v)) +} + +// UpdateTimeLTE applies the LTE predicate on the "update_time" field. +func UpdateTimeLTE(v time.Time) predicate.Posting { + return predicate.Posting(sql.FieldLTE(FieldUpdateTime, v)) +} + // TitleEQ applies the EQ predicate on the "title" field. func TitleEQ(v string) predicate.Posting { return predicate.Posting(sql.FieldEQ(FieldTitle, v)) diff --git a/ent/posting_create.go b/ent/posting_create.go index f57616a..7accb73 100644 --- a/ent/posting_create.go +++ b/ent/posting_create.go @@ -23,6 +23,34 @@ type PostingCreate struct { hooks []Hook } +// SetCreateTime sets the "create_time" field. +func (pc *PostingCreate) SetCreateTime(t time.Time) *PostingCreate { + pc.mutation.SetCreateTime(t) + return pc +} + +// SetNillableCreateTime sets the "create_time" field if the given value is not nil. +func (pc *PostingCreate) SetNillableCreateTime(t *time.Time) *PostingCreate { + if t != nil { + pc.SetCreateTime(*t) + } + return pc +} + +// SetUpdateTime sets the "update_time" field. +func (pc *PostingCreate) SetUpdateTime(t time.Time) *PostingCreate { + pc.mutation.SetUpdateTime(t) + return pc +} + +// SetNillableUpdateTime sets the "update_time" field if the given value is not nil. +func (pc *PostingCreate) SetNillableUpdateTime(t *time.Time) *PostingCreate { + if t != nil { + pc.SetUpdateTime(*t) + } + return pc +} + // SetTitle sets the "title" field. func (pc *PostingCreate) SetTitle(s string) *PostingCreate { pc.mutation.SetTitle(s) @@ -73,6 +101,7 @@ func (pc *PostingCreate) Mutation() *PostingMutation { // Save creates the Posting in the database. func (pc *PostingCreate) Save(ctx context.Context) (*Posting, error) { + pc.defaults() return withHooks(ctx, pc.sqlSave, pc.mutation, pc.hooks) } @@ -98,8 +127,26 @@ func (pc *PostingCreate) ExecX(ctx context.Context) { } } +// defaults sets the default values of the builder before save. +func (pc *PostingCreate) defaults() { + if _, ok := pc.mutation.CreateTime(); !ok { + v := posting.DefaultCreateTime() + pc.mutation.SetCreateTime(v) + } + if _, ok := pc.mutation.UpdateTime(); !ok { + v := posting.DefaultUpdateTime() + pc.mutation.SetUpdateTime(v) + } +} + // check runs all checks and user-defined validators on the builder. func (pc *PostingCreate) check() error { + if _, ok := pc.mutation.CreateTime(); !ok { + return &ValidationError{Name: "create_time", err: errors.New(`ent: missing required field "Posting.create_time"`)} + } + if _, ok := pc.mutation.UpdateTime(); !ok { + return &ValidationError{Name: "update_time", err: errors.New(`ent: missing required field "Posting.update_time"`)} + } if _, ok := pc.mutation.Title(); !ok { return &ValidationError{Name: "title", err: errors.New(`ent: missing required field "Posting.title"`)} } @@ -138,6 +185,14 @@ func (pc *PostingCreate) createSpec() (*Posting, *sqlgraph.CreateSpec, error) { _node = &Posting{config: pc.config} _spec = sqlgraph.NewCreateSpec(posting.Table, sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt)) ) + if value, ok := pc.mutation.CreateTime(); ok { + _spec.SetField(posting.FieldCreateTime, field.TypeTime, value) + _node.CreateTime = value + } + if value, ok := pc.mutation.UpdateTime(); ok { + _spec.SetField(posting.FieldUpdateTime, field.TypeTime, value) + _node.UpdateTime = value + } if value, ok := pc.mutation.Title(); ok { _spec.SetField(posting.FieldTitle, field.TypeString, value) _node.Title = value @@ -196,6 +251,7 @@ func (pcb *PostingCreateBulk) Save(ctx context.Context) ([]*Posting, error) { for i := range pcb.builders { func(i int, root context.Context) { builder := pcb.builders[i] + builder.defaults() var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { mutation, ok := m.(*PostingMutation) if !ok { diff --git a/ent/posting_query.go b/ent/posting_query.go index e2f7345..d97ca22 100644 --- a/ent/posting_query.go +++ b/ent/posting_query.go @@ -299,12 +299,12 @@ func (pq *PostingQuery) WithCompany(opts ...func(*CompanyQuery)) *PostingQuery { // Example: // // var v []struct { -// Title string `json:"title,omitempty"` +// CreateTime time.Time `json:"create_time,omitempty"` // Count int `json:"count,omitempty"` // } // // client.Posting.Query(). -// GroupBy(posting.FieldTitle). +// GroupBy(posting.FieldCreateTime). // Aggregate(ent.Count()). // Scan(ctx, &v) func (pq *PostingQuery) GroupBy(field string, fields ...string) *PostingGroupBy { @@ -322,11 +322,11 @@ func (pq *PostingQuery) GroupBy(field string, fields ...string) *PostingGroupBy // Example: // // var v []struct { -// Title string `json:"title,omitempty"` +// CreateTime time.Time `json:"create_time,omitempty"` // } // // client.Posting.Query(). -// Select(posting.FieldTitle). +// Select(posting.FieldCreateTime). // Scan(ctx, &v) func (pq *PostingQuery) Select(fields ...string) *PostingSelect { pq.ctx.Fields = append(pq.ctx.Fields, fields...) diff --git a/ent/posting_update.go b/ent/posting_update.go index cfa7839..2ceb4ec 100644 --- a/ent/posting_update.go +++ b/ent/posting_update.go @@ -31,6 +31,12 @@ func (pu *PostingUpdate) Where(ps ...predicate.Posting) *PostingUpdate { return pu } +// SetUpdateTime sets the "update_time" field. +func (pu *PostingUpdate) SetUpdateTime(t time.Time) *PostingUpdate { + pu.mutation.SetUpdateTime(t) + return pu +} + // SetTitle sets the "title" field. func (pu *PostingUpdate) SetTitle(s string) *PostingUpdate { pu.mutation.SetTitle(s) @@ -109,6 +115,7 @@ func (pu *PostingUpdate) ClearCompany() *PostingUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (pu *PostingUpdate) Save(ctx context.Context) (int, error) { + pu.defaults() return withHooks(ctx, pu.sqlSave, pu.mutation, pu.hooks) } @@ -134,6 +141,14 @@ func (pu *PostingUpdate) ExecX(ctx context.Context) { } } +// defaults sets the default values of the builder before save. +func (pu *PostingUpdate) defaults() { + if _, ok := pu.mutation.UpdateTime(); !ok { + v := posting.UpdateDefaultUpdateTime() + pu.mutation.SetUpdateTime(v) + } +} + func (pu *PostingUpdate) sqlSave(ctx context.Context) (n int, err error) { _spec := sqlgraph.NewUpdateSpec(posting.Table, posting.Columns, sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt)) if ps := pu.mutation.predicates; len(ps) > 0 { @@ -143,6 +158,9 @@ func (pu *PostingUpdate) sqlSave(ctx context.Context) (n int, err error) { } } } + if value, ok := pu.mutation.UpdateTime(); ok { + _spec.SetField(posting.FieldUpdateTime, field.TypeTime, value) + } if value, ok := pu.mutation.Title(); ok { _spec.SetField(posting.FieldTitle, field.TypeString, value) } @@ -211,6 +229,12 @@ type PostingUpdateOne struct { mutation *PostingMutation } +// SetUpdateTime sets the "update_time" field. +func (puo *PostingUpdateOne) SetUpdateTime(t time.Time) *PostingUpdateOne { + puo.mutation.SetUpdateTime(t) + return puo +} + // SetTitle sets the "title" field. func (puo *PostingUpdateOne) SetTitle(s string) *PostingUpdateOne { puo.mutation.SetTitle(s) @@ -302,6 +326,7 @@ func (puo *PostingUpdateOne) Select(field string, fields ...string) *PostingUpda // Save executes the query and returns the updated Posting entity. func (puo *PostingUpdateOne) Save(ctx context.Context) (*Posting, error) { + puo.defaults() return withHooks(ctx, puo.sqlSave, puo.mutation, puo.hooks) } @@ -327,6 +352,14 @@ func (puo *PostingUpdateOne) ExecX(ctx context.Context) { } } +// defaults sets the default values of the builder before save. +func (puo *PostingUpdateOne) defaults() { + if _, ok := puo.mutation.UpdateTime(); !ok { + v := posting.UpdateDefaultUpdateTime() + puo.mutation.SetUpdateTime(v) + } +} + func (puo *PostingUpdateOne) sqlSave(ctx context.Context) (_node *Posting, err error) { _spec := sqlgraph.NewUpdateSpec(posting.Table, posting.Columns, sqlgraph.NewFieldSpec(posting.FieldID, field.TypeInt)) id, ok := puo.mutation.ID() @@ -353,6 +386,9 @@ func (puo *PostingUpdateOne) sqlSave(ctx context.Context) (_node *Posting, err e } } } + if value, ok := puo.mutation.UpdateTime(); ok { + _spec.SetField(posting.FieldUpdateTime, field.TypeTime, value) + } if value, ok := puo.mutation.Title(); ok { _spec.SetField(posting.FieldTitle, field.TypeString, value) } diff --git a/ent/runtime/runtime.go b/ent/runtime/runtime.go index 1192a11..c71bdb7 100644 --- a/ent/runtime/runtime.go +++ b/ent/runtime/runtime.go @@ -46,8 +46,21 @@ func init() { // companyDescRssURL is the schema descriptor for rss_url field. companyDescRssURL := companyFields[3].Descriptor() company.ValueScanner.RssURL = companyDescRssURL.ValueScanner.(field.TypeValueScanner[*url.URL]) + postingMixin := schema.Posting{}.Mixin() + postingMixinFields0 := postingMixin[0].Fields() + _ = postingMixinFields0 postingFields := schema.Posting{}.Fields() _ = postingFields + // postingDescCreateTime is the schema descriptor for create_time field. + postingDescCreateTime := postingMixinFields0[0].Descriptor() + // posting.DefaultCreateTime holds the default value on creation for the create_time field. + posting.DefaultCreateTime = postingDescCreateTime.Default.(func() time.Time) + // postingDescUpdateTime is the schema descriptor for update_time field. + postingDescUpdateTime := postingMixinFields0[1].Descriptor() + // posting.DefaultUpdateTime holds the default value on creation for the update_time field. + posting.DefaultUpdateTime = postingDescUpdateTime.Default.(func() time.Time) + // posting.UpdateDefaultUpdateTime holds the default value on update for the update_time field. + posting.UpdateDefaultUpdateTime = postingDescUpdateTime.UpdateDefault.(func() time.Time) // postingDescURL is the schema descriptor for url field. postingDescURL := postingFields[1].Descriptor() posting.ValueScanner.URL = postingDescURL.ValueScanner.(field.TypeValueScanner[*url.URL]) From 43d2ee9d8cc3de224d1ca7a0f41d410204ba266a Mon Sep 17 00:00:00 2001 From: pilyang Date: Sun, 16 Feb 2025 18:50:24 +0900 Subject: [PATCH 6/6] chore: regenerate migration file by atlas --- ent/migrate/migrations/20250215135939_create_posting.sql | 4 ---- ent/migrate/migrations/20250216095000_create_posting.sql | 4 ++++ ent/migrate/migrations/atlas.sum | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 ent/migrate/migrations/20250215135939_create_posting.sql create mode 100644 ent/migrate/migrations/20250216095000_create_posting.sql diff --git a/ent/migrate/migrations/20250215135939_create_posting.sql b/ent/migrate/migrations/20250215135939_create_posting.sql deleted file mode 100644 index df25753..0000000 --- a/ent/migrate/migrations/20250215135939_create_posting.sql +++ /dev/null @@ -1,4 +0,0 @@ --- Create "postings" table -CREATE TABLE "postings" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "title" character varying NOT NULL, "url" character varying NOT NULL, "published_at" timestamptz NOT NULL, "tags" text[] NULL, "company_postings" bigint NULL, PRIMARY KEY ("id"), CONSTRAINT "postings_companies_postings" FOREIGN KEY ("company_postings") REFERENCES "companies" ("id") ON UPDATE NO ACTION ON DELETE SET NULL); --- Create index "postings_url_key" to table: "postings" -CREATE UNIQUE INDEX "postings_url_key" ON "postings" ("url"); diff --git a/ent/migrate/migrations/20250216095000_create_posting.sql b/ent/migrate/migrations/20250216095000_create_posting.sql new file mode 100644 index 0000000..ef4e051 --- /dev/null +++ b/ent/migrate/migrations/20250216095000_create_posting.sql @@ -0,0 +1,4 @@ +-- Create "postings" table +CREATE TABLE "postings" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "create_time" timestamptz NOT NULL, "update_time" timestamptz NOT NULL, "title" character varying NOT NULL, "url" character varying NOT NULL, "published_at" timestamptz NOT NULL, "tags" text[] NULL, "company_postings" bigint NULL, PRIMARY KEY ("id"), CONSTRAINT "postings_companies_postings" FOREIGN KEY ("company_postings") REFERENCES "companies" ("id") ON UPDATE NO ACTION ON DELETE SET NULL); +-- Create index "postings_url_key" to table: "postings" +CREATE UNIQUE INDEX "postings_url_key" ON "postings" ("url"); diff --git a/ent/migrate/migrations/atlas.sum b/ent/migrate/migrations/atlas.sum index 8860854..ecd21a7 100644 --- a/ent/migrate/migrations/atlas.sum +++ b/ent/migrate/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:h455WQyMRJnQV+jKLUeCAv2dNBQ8Nc9Bp4P1w+JZ7Qc= +h1:bjZTs6dWWzQuay+XzFnQhkrKLW1EWt1dIV4fWDFkQEg= 20250118142329_create_company.sql h1:HDbigYfm6G4w1+Kzgwl+rMabQjLnctFRgIdyKGRxsKc= 20250202031149_create-tag.sql h1:0hc8Co99P4bEvB9KZT3OUZflUCnjScW+UdrTR/WC0vA= -20250215135939_create_posting.sql h1:hTh6qFzC24ZPJURyGBaHI8lzi60FYMarYpZUN5yV2tg= +20250216095000_create_posting.sql h1:3LYyiwyagI8dYXnCOABB51IXXbXZwezGr16iy8I8qZY=