Files
homebox/backend/internal/data/ent/group_query.go
Logan Miller cc66330a74 feat: Add item templates feature (#435) (#1099)
* feat: Add item templates feature (#435)

   Add ability to create and manage item templates for quick item creation.
   Templates store default values and custom fields that can be applied
   when creating new items.

   Backend changes:
   - New ItemTemplate and TemplateField Ent schemas
   - Template CRUD API endpoints
   - Create item from template endpoint

   Frontend changes:
   - Templates management page with create/edit/delete
   - Template selector in item creation modal
   - 'Use as Template' action on item detail page
   - Templates link in navigation menu

* refactor: Improve template item creation with a single query

- Add `CreateFromTemplate` method to ItemsRepository that creates items with all template data (including custom fields) in a single atomic transaction, replacing the previous two-phase create-then-update pattern
- Fix `GetOne` to require group ID parameter so templates can only be accessed by users in the owning group (security fix)
- Simplify `HandleItemTemplatesCreateItem` handler using the new transactional method

* Refactor item template types and formatting

Updated type annotations in CreateModal.vue to use specific ItemTemplate types instead of 'any'. Improved code formatting for template fields and manufacturer display. Also refactored warranty field logic in item details page for better readability. This resolves the linter issues as well that the bot in github keeps nagging at.

* Add 'id' property to template fields

Introduces an 'id' property to each field object in CreateModal.vue and item details page to support unique identification of fields. This change prepares the codebase for future enhancements that may require field-level identification.

* Removed redundant SQL migrations.

Removed redundant SQL migrations per @tankerkiller125's findings.

* Updates to PR #1099.

Regarding pull #1099. Fixed an issue causing some conflict with GUIDs and old rows in the migration files.

* Add new fields and location edge to ItemTemplate

Addresses recommendations from @tonyaellie.

* Relocated add template button
* Added more default fields to the template
* Added translation of all strings (think so?)
* Make oval buttons round
* Added duplicate button to the template (this required a rewrite of the migration files, I made sure only 1 exists per DB type)
* Added a Save as template button to a item detail view (this creates a template with all the current data of that item)
* Changed all occurrences of space to gap and flex where applicable.
* Made template selection persistent after item created.
* Collapsible template info on creation view.

* Updates to translation and fix for labels/locations

I also added a test in here because I keep missing small function tests. That should prevent that from happening again.

* Linted

* Bring up to date with main, fix some lint/type check issues

* In theory fix playwright tests

* Fix defaults being unable to be nullable/empty (and thus limiting flexibility)

* Last few fixes I think

* Forgot to fix the golang tests

---------

Co-authored-by: Matthew Kilgore <matthew@kilgore.dev>
2025-12-06 16:21:43 -05:00

1060 lines
32 KiB
Go
Generated

// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"database/sql/driver"
"fmt"
"math"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/group"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/groupinvitationtoken"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/item"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/itemtemplate"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/label"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/location"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/notifier"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/user"
)
// GroupQuery is the builder for querying Group entities.
type GroupQuery struct {
config
ctx *QueryContext
order []group.OrderOption
inters []Interceptor
predicates []predicate.Group
withUsers *UserQuery
withLocations *LocationQuery
withItems *ItemQuery
withLabels *LabelQuery
withInvitationTokens *GroupInvitationTokenQuery
withNotifiers *NotifierQuery
withItemTemplates *ItemTemplateQuery
// intermediate query (i.e. traversal path).
sql *sql.Selector
path func(context.Context) (*sql.Selector, error)
}
// Where adds a new predicate for the GroupQuery builder.
func (_q *GroupQuery) Where(ps ...predicate.Group) *GroupQuery {
_q.predicates = append(_q.predicates, ps...)
return _q
}
// Limit the number of records to be returned by this query.
func (_q *GroupQuery) Limit(limit int) *GroupQuery {
_q.ctx.Limit = &limit
return _q
}
// Offset to start from.
func (_q *GroupQuery) Offset(offset int) *GroupQuery {
_q.ctx.Offset = &offset
return _q
}
// 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 (_q *GroupQuery) Unique(unique bool) *GroupQuery {
_q.ctx.Unique = &unique
return _q
}
// Order specifies how the records should be ordered.
func (_q *GroupQuery) Order(o ...group.OrderOption) *GroupQuery {
_q.order = append(_q.order, o...)
return _q
}
// QueryUsers chains the current query on the "users" edge.
func (_q *GroupQuery) QueryUsers() *UserQuery {
query := (&UserClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(group.Table, group.FieldID, selector),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, group.UsersTable, group.UsersColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryLocations chains the current query on the "locations" edge.
func (_q *GroupQuery) QueryLocations() *LocationQuery {
query := (&LocationClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(group.Table, group.FieldID, selector),
sqlgraph.To(location.Table, location.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, group.LocationsTable, group.LocationsColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryItems chains the current query on the "items" edge.
func (_q *GroupQuery) QueryItems() *ItemQuery {
query := (&ItemClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(group.Table, group.FieldID, selector),
sqlgraph.To(item.Table, item.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, group.ItemsTable, group.ItemsColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryLabels chains the current query on the "labels" edge.
func (_q *GroupQuery) QueryLabels() *LabelQuery {
query := (&LabelClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(group.Table, group.FieldID, selector),
sqlgraph.To(label.Table, label.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, group.LabelsTable, group.LabelsColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryInvitationTokens chains the current query on the "invitation_tokens" edge.
func (_q *GroupQuery) QueryInvitationTokens() *GroupInvitationTokenQuery {
query := (&GroupInvitationTokenClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(group.Table, group.FieldID, selector),
sqlgraph.To(groupinvitationtoken.Table, groupinvitationtoken.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, group.InvitationTokensTable, group.InvitationTokensColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryNotifiers chains the current query on the "notifiers" edge.
func (_q *GroupQuery) QueryNotifiers() *NotifierQuery {
query := (&NotifierClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(group.Table, group.FieldID, selector),
sqlgraph.To(notifier.Table, notifier.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, group.NotifiersTable, group.NotifiersColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryItemTemplates chains the current query on the "item_templates" edge.
func (_q *GroupQuery) QueryItemTemplates() *ItemTemplateQuery {
query := (&ItemTemplateClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(group.Table, group.FieldID, selector),
sqlgraph.To(itemtemplate.Table, itemtemplate.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, group.ItemTemplatesTable, group.ItemTemplatesColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
return fromU, nil
}
return query
}
// First returns the first Group entity from the query.
// Returns a *NotFoundError when no Group was found.
func (_q *GroupQuery) First(ctx context.Context) (*Group, error) {
nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))
if err != nil {
return nil, err
}
if len(nodes) == 0 {
return nil, &NotFoundError{group.Label}
}
return nodes[0], nil
}
// FirstX is like First, but panics if an error occurs.
func (_q *GroupQuery) FirstX(ctx context.Context) *Group {
node, err := _q.First(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return node
}
// FirstID returns the first Group ID from the query.
// Returns a *NotFoundError when no Group ID was found.
func (_q *GroupQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {
return
}
if len(ids) == 0 {
err = &NotFoundError{group.Label}
return
}
return ids[0], nil
}
// FirstIDX is like FirstID, but panics if an error occurs.
func (_q *GroupQuery) FirstIDX(ctx context.Context) uuid.UUID {
id, err := _q.FirstID(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return id
}
// Only returns a single Group entity found by the query, ensuring it only returns one.
// Returns a *NotSingularError when more than one Group entity is found.
// Returns a *NotFoundError when no Group entities are found.
func (_q *GroupQuery) Only(ctx context.Context) (*Group, error) {
nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))
if err != nil {
return nil, err
}
switch len(nodes) {
case 1:
return nodes[0], nil
case 0:
return nil, &NotFoundError{group.Label}
default:
return nil, &NotSingularError{group.Label}
}
}
// OnlyX is like Only, but panics if an error occurs.
func (_q *GroupQuery) OnlyX(ctx context.Context) *Group {
node, err := _q.Only(ctx)
if err != nil {
panic(err)
}
return node
}
// OnlyID is like Only, but returns the only Group ID in the query.
// Returns a *NotSingularError when more than one Group ID is found.
// Returns a *NotFoundError when no entities are found.
func (_q *GroupQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {
return
}
switch len(ids) {
case 1:
id = ids[0]
case 0:
err = &NotFoundError{group.Label}
default:
err = &NotSingularError{group.Label}
}
return
}
// OnlyIDX is like OnlyID, but panics if an error occurs.
func (_q *GroupQuery) OnlyIDX(ctx context.Context) uuid.UUID {
id, err := _q.OnlyID(ctx)
if err != nil {
panic(err)
}
return id
}
// All executes the query and returns a list of Groups.
func (_q *GroupQuery) All(ctx context.Context) ([]*Group, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)
if err := _q.prepareQuery(ctx); err != nil {
return nil, err
}
qr := querierAll[[]*Group, *GroupQuery]()
return withInterceptors[[]*Group](ctx, _q, qr, _q.inters)
}
// AllX is like All, but panics if an error occurs.
func (_q *GroupQuery) AllX(ctx context.Context) []*Group {
nodes, err := _q.All(ctx)
if err != nil {
panic(err)
}
return nodes
}
// IDs executes the query and returns a list of Group IDs.
func (_q *GroupQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
if _q.ctx.Unique == nil && _q.path != nil {
_q.Unique(true)
}
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs)
if err = _q.Select(group.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
return ids, nil
}
// IDsX is like IDs, but panics if an error occurs.
func (_q *GroupQuery) IDsX(ctx context.Context) []uuid.UUID {
ids, err := _q.IDs(ctx)
if err != nil {
panic(err)
}
return ids
}
// Count returns the count of the given query.
func (_q *GroupQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)
if err := _q.prepareQuery(ctx); err != nil {
return 0, err
}
return withInterceptors[int](ctx, _q, querierCount[*GroupQuery](), _q.inters)
}
// CountX is like Count, but panics if an error occurs.
func (_q *GroupQuery) CountX(ctx context.Context) int {
count, err := _q.Count(ctx)
if err != nil {
panic(err)
}
return count
}
// Exist returns true if the query has elements in the graph.
func (_q *GroupQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)
switch _, err := _q.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 (_q *GroupQuery) ExistX(ctx context.Context) bool {
exist, err := _q.Exist(ctx)
if err != nil {
panic(err)
}
return exist
}
// Clone returns a duplicate of the GroupQuery builder, including all associated steps. It can be
// used to prepare common query builders and use them differently after the clone is made.
func (_q *GroupQuery) Clone() *GroupQuery {
if _q == nil {
return nil
}
return &GroupQuery{
config: _q.config,
ctx: _q.ctx.Clone(),
order: append([]group.OrderOption{}, _q.order...),
inters: append([]Interceptor{}, _q.inters...),
predicates: append([]predicate.Group{}, _q.predicates...),
withUsers: _q.withUsers.Clone(),
withLocations: _q.withLocations.Clone(),
withItems: _q.withItems.Clone(),
withLabels: _q.withLabels.Clone(),
withInvitationTokens: _q.withInvitationTokens.Clone(),
withNotifiers: _q.withNotifiers.Clone(),
withItemTemplates: _q.withItemTemplates.Clone(),
// clone intermediate query.
sql: _q.sql.Clone(),
path: _q.path,
}
}
// WithUsers tells the query-builder to eager-load the nodes that are connected to
// the "users" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *GroupQuery) WithUsers(opts ...func(*UserQuery)) *GroupQuery {
query := (&UserClient{config: _q.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withUsers = query
return _q
}
// WithLocations tells the query-builder to eager-load the nodes that are connected to
// the "locations" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *GroupQuery) WithLocations(opts ...func(*LocationQuery)) *GroupQuery {
query := (&LocationClient{config: _q.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withLocations = query
return _q
}
// WithItems tells the query-builder to eager-load the nodes that are connected to
// the "items" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *GroupQuery) WithItems(opts ...func(*ItemQuery)) *GroupQuery {
query := (&ItemClient{config: _q.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withItems = query
return _q
}
// WithLabels tells the query-builder to eager-load the nodes that are connected to
// the "labels" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *GroupQuery) WithLabels(opts ...func(*LabelQuery)) *GroupQuery {
query := (&LabelClient{config: _q.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withLabels = query
return _q
}
// WithInvitationTokens tells the query-builder to eager-load the nodes that are connected to
// the "invitation_tokens" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *GroupQuery) WithInvitationTokens(opts ...func(*GroupInvitationTokenQuery)) *GroupQuery {
query := (&GroupInvitationTokenClient{config: _q.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withInvitationTokens = query
return _q
}
// WithNotifiers tells the query-builder to eager-load the nodes that are connected to
// the "notifiers" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *GroupQuery) WithNotifiers(opts ...func(*NotifierQuery)) *GroupQuery {
query := (&NotifierClient{config: _q.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withNotifiers = query
return _q
}
// WithItemTemplates tells the query-builder to eager-load the nodes that are connected to
// the "item_templates" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *GroupQuery) WithItemTemplates(opts ...func(*ItemTemplateQuery)) *GroupQuery {
query := (&ItemTemplateClient{config: _q.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withItemTemplates = query
return _q
}
// GroupBy is used to group vertices by one or more fields/columns.
// It is often used with aggregate functions, like: count, max, mean, min, sum.
//
// Example:
//
// var v []struct {
// CreatedAt time.Time `json:"created_at,omitempty"`
// Count int `json:"count,omitempty"`
// }
//
// client.Group.Query().
// GroupBy(group.FieldCreatedAt).
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (_q *GroupQuery) GroupBy(field string, fields ...string) *GroupGroupBy {
_q.ctx.Fields = append([]string{field}, fields...)
grbuild := &GroupGroupBy{build: _q}
grbuild.flds = &_q.ctx.Fields
grbuild.label = group.Label
grbuild.scan = grbuild.Scan
return grbuild
}
// Select allows the selection one or more fields/columns for the given query,
// instead of selecting all fields in the entity.
//
// Example:
//
// var v []struct {
// CreatedAt time.Time `json:"created_at,omitempty"`
// }
//
// client.Group.Query().
// Select(group.FieldCreatedAt).
// Scan(ctx, &v)
func (_q *GroupQuery) Select(fields ...string) *GroupSelect {
_q.ctx.Fields = append(_q.ctx.Fields, fields...)
sbuild := &GroupSelect{GroupQuery: _q}
sbuild.label = group.Label
sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan
return sbuild
}
// Aggregate returns a GroupSelect configured with the given aggregations.
func (_q *GroupQuery) Aggregate(fns ...AggregateFunc) *GroupSelect {
return _q.Select().Aggregate(fns...)
}
func (_q *GroupQuery) prepareQuery(ctx context.Context) error {
for _, inter := range _q.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, _q); err != nil {
return err
}
}
}
for _, f := range _q.ctx.Fields {
if !group.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
}
if _q.path != nil {
prev, err := _q.path(ctx)
if err != nil {
return err
}
_q.sql = prev
}
return nil
}
func (_q *GroupQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Group, error) {
var (
nodes = []*Group{}
_spec = _q.querySpec()
loadedTypes = [7]bool{
_q.withUsers != nil,
_q.withLocations != nil,
_q.withItems != nil,
_q.withLabels != nil,
_q.withInvitationTokens != nil,
_q.withNotifiers != nil,
_q.withItemTemplates != nil,
}
)
_spec.ScanValues = func(columns []string) ([]any, error) {
return (*Group).scanValues(nil, columns)
}
_spec.Assign = func(columns []string, values []any) error {
node := &Group{config: _q.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, _q.driver, _spec); err != nil {
return nil, err
}
if len(nodes) == 0 {
return nodes, nil
}
if query := _q.withUsers; query != nil {
if err := _q.loadUsers(ctx, query, nodes,
func(n *Group) { n.Edges.Users = []*User{} },
func(n *Group, e *User) { n.Edges.Users = append(n.Edges.Users, e) }); err != nil {
return nil, err
}
}
if query := _q.withLocations; query != nil {
if err := _q.loadLocations(ctx, query, nodes,
func(n *Group) { n.Edges.Locations = []*Location{} },
func(n *Group, e *Location) { n.Edges.Locations = append(n.Edges.Locations, e) }); err != nil {
return nil, err
}
}
if query := _q.withItems; query != nil {
if err := _q.loadItems(ctx, query, nodes,
func(n *Group) { n.Edges.Items = []*Item{} },
func(n *Group, e *Item) { n.Edges.Items = append(n.Edges.Items, e) }); err != nil {
return nil, err
}
}
if query := _q.withLabels; query != nil {
if err := _q.loadLabels(ctx, query, nodes,
func(n *Group) { n.Edges.Labels = []*Label{} },
func(n *Group, e *Label) { n.Edges.Labels = append(n.Edges.Labels, e) }); err != nil {
return nil, err
}
}
if query := _q.withInvitationTokens; query != nil {
if err := _q.loadInvitationTokens(ctx, query, nodes,
func(n *Group) { n.Edges.InvitationTokens = []*GroupInvitationToken{} },
func(n *Group, e *GroupInvitationToken) {
n.Edges.InvitationTokens = append(n.Edges.InvitationTokens, e)
}); err != nil {
return nil, err
}
}
if query := _q.withNotifiers; query != nil {
if err := _q.loadNotifiers(ctx, query, nodes,
func(n *Group) { n.Edges.Notifiers = []*Notifier{} },
func(n *Group, e *Notifier) { n.Edges.Notifiers = append(n.Edges.Notifiers, e) }); err != nil {
return nil, err
}
}
if query := _q.withItemTemplates; query != nil {
if err := _q.loadItemTemplates(ctx, query, nodes,
func(n *Group) { n.Edges.ItemTemplates = []*ItemTemplate{} },
func(n *Group, e *ItemTemplate) { n.Edges.ItemTemplates = append(n.Edges.ItemTemplates, e) }); err != nil {
return nil, err
}
}
return nodes, nil
}
func (_q *GroupQuery) loadUsers(ctx context.Context, query *UserQuery, nodes []*Group, init func(*Group), assign func(*Group, *User)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Group)
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.User(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(group.UsersColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.group_users
if fk == nil {
return fmt.Errorf(`foreign-key "group_users" is nil for node %v`, n.ID)
}
node, ok := nodeids[*fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "group_users" returned %v for node %v`, *fk, n.ID)
}
assign(node, n)
}
return nil
}
func (_q *GroupQuery) loadLocations(ctx context.Context, query *LocationQuery, nodes []*Group, init func(*Group), assign func(*Group, *Location)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Group)
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.Location(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(group.LocationsColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.group_locations
if fk == nil {
return fmt.Errorf(`foreign-key "group_locations" is nil for node %v`, n.ID)
}
node, ok := nodeids[*fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "group_locations" returned %v for node %v`, *fk, n.ID)
}
assign(node, n)
}
return nil
}
func (_q *GroupQuery) loadItems(ctx context.Context, query *ItemQuery, nodes []*Group, init func(*Group), assign func(*Group, *Item)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Group)
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.Item(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(group.ItemsColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.group_items
if fk == nil {
return fmt.Errorf(`foreign-key "group_items" is nil for node %v`, n.ID)
}
node, ok := nodeids[*fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "group_items" returned %v for node %v`, *fk, n.ID)
}
assign(node, n)
}
return nil
}
func (_q *GroupQuery) loadLabels(ctx context.Context, query *LabelQuery, nodes []*Group, init func(*Group), assign func(*Group, *Label)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Group)
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.Label(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(group.LabelsColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.group_labels
if fk == nil {
return fmt.Errorf(`foreign-key "group_labels" is nil for node %v`, n.ID)
}
node, ok := nodeids[*fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "group_labels" returned %v for node %v`, *fk, n.ID)
}
assign(node, n)
}
return nil
}
func (_q *GroupQuery) loadInvitationTokens(ctx context.Context, query *GroupInvitationTokenQuery, nodes []*Group, init func(*Group), assign func(*Group, *GroupInvitationToken)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Group)
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.GroupInvitationToken(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(group.InvitationTokensColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.group_invitation_tokens
if fk == nil {
return fmt.Errorf(`foreign-key "group_invitation_tokens" is nil for node %v`, n.ID)
}
node, ok := nodeids[*fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "group_invitation_tokens" returned %v for node %v`, *fk, n.ID)
}
assign(node, n)
}
return nil
}
func (_q *GroupQuery) loadNotifiers(ctx context.Context, query *NotifierQuery, nodes []*Group, init func(*Group), assign func(*Group, *Notifier)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Group)
for i := range nodes {
fks = append(fks, nodes[i].ID)
nodeids[nodes[i].ID] = nodes[i]
if init != nil {
init(nodes[i])
}
}
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(notifier.FieldGroupID)
}
query.Where(predicate.Notifier(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(group.NotifiersColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.GroupID
node, ok := nodeids[fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "group_id" returned %v for node %v`, fk, n.ID)
}
assign(node, n)
}
return nil
}
func (_q *GroupQuery) loadItemTemplates(ctx context.Context, query *ItemTemplateQuery, nodes []*Group, init func(*Group), assign func(*Group, *ItemTemplate)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Group)
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.ItemTemplate(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(group.ItemTemplatesColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.group_item_templates
if fk == nil {
return fmt.Errorf(`foreign-key "group_item_templates" is nil for node %v`, n.ID)
}
node, ok := nodeids[*fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "group_item_templates" returned %v for node %v`, *fk, n.ID)
}
assign(node, n)
}
return nil
}
func (_q *GroupQuery) sqlCount(ctx context.Context) (int, error) {
_spec := _q.querySpec()
_spec.Node.Columns = _q.ctx.Fields
if len(_q.ctx.Fields) > 0 {
_spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique
}
return sqlgraph.CountNodes(ctx, _q.driver, _spec)
}
func (_q *GroupQuery) querySpec() *sqlgraph.QuerySpec {
_spec := sqlgraph.NewQuerySpec(group.Table, group.Columns, sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID))
_spec.From = _q.sql
if unique := _q.ctx.Unique; unique != nil {
_spec.Unique = *unique
} else if _q.path != nil {
_spec.Unique = true
}
if fields := _q.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, group.FieldID)
for i := range fields {
if fields[i] != group.FieldID {
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
}
}
}
if ps := _q.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if limit := _q.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := _q.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := _q.order; len(ps) > 0 {
_spec.Order = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
return _spec
}
func (_q *GroupQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(_q.driver.Dialect())
t1 := builder.Table(group.Table)
columns := _q.ctx.Fields
if len(columns) == 0 {
columns = group.Columns
}
selector := builder.Select(t1.Columns(columns...)...).From(t1)
if _q.sql != nil {
selector = _q.sql
selector.Select(selector.Columns(columns...)...)
}
if _q.ctx.Unique != nil && *_q.ctx.Unique {
selector.Distinct()
}
for _, p := range _q.predicates {
p(selector)
}
for _, p := range _q.order {
p(selector)
}
if offset := _q.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 := _q.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
}
// GroupGroupBy is the group-by builder for Group entities.
type GroupGroupBy struct {
selector
build *GroupQuery
}
// Aggregate adds the given aggregation functions to the group-by query.
func (_g *GroupGroupBy) Aggregate(fns ...AggregateFunc) *GroupGroupBy {
_g.fns = append(_g.fns, fns...)
return _g
}
// Scan applies the selector query and scans the result into the given value.
func (_g *GroupGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)
if err := _g.build.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*GroupQuery, *GroupGroupBy](ctx, _g.build, _g, _g.build.inters, v)
}
func (_g *GroupGroupBy) sqlScan(ctx context.Context, root *GroupQuery, v any) error {
selector := root.sqlQuery(ctx).Select()
aggregation := make([]string, 0, len(_g.fns))
for _, fn := range _g.fns {
aggregation = append(aggregation, fn(selector))
}
if len(selector.SelectedColumns()) == 0 {
columns := make([]string, 0, len(*_g.flds)+len(_g.fns))
for _, f := range *_g.flds {
columns = append(columns, selector.C(f))
}
columns = append(columns, aggregation...)
selector.Select(columns...)
}
selector.GroupBy(selector.Columns(*_g.flds...)...)
if err := selector.Err(); err != nil {
return err
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := _g.build.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}
// GroupSelect is the builder for selecting fields of Group entities.
type GroupSelect struct {
*GroupQuery
selector
}
// Aggregate adds the given aggregation functions to the selector query.
func (_s *GroupSelect) Aggregate(fns ...AggregateFunc) *GroupSelect {
_s.fns = append(_s.fns, fns...)
return _s
}
// Scan applies the selector query and scans the result into the given value.
func (_s *GroupSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)
if err := _s.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*GroupQuery, *GroupSelect](ctx, _s.GroupQuery, _s, _s.inters, v)
}
func (_s *GroupSelect) sqlScan(ctx context.Context, root *GroupQuery, v any) error {
selector := root.sqlQuery(ctx)
aggregation := make([]string, 0, len(_s.fns))
for _, fn := range _s.fns {
aggregation = append(aggregation, fn(selector))
}
switch n := len(*_s.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 := _s.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}