feat: allow nested relationships for locations and items (#102)

Basic implementation that allows organizing Locations and Items within each other.
This commit is contained in:
Hayden 2022-10-23 20:54:39 -08:00 committed by GitHub
parent fe6cd431a6
commit a4b4fe3454
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 2329 additions and 126 deletions

View file

@ -845,6 +845,15 @@ const docTemplate = `{
"name": "id",
"in": "path",
"required": true
},
{
"description": "Location Data",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repo.LocationUpdate"
}
}
],
"responses": {
@ -1232,6 +1241,10 @@ const docTemplate = `{
},
"name": {
"type": "string"
},
"parentId": {
"type": "string",
"x-nullable": true
}
}
},
@ -1270,6 +1283,12 @@ const docTemplate = `{
"$ref": "#/definitions/repo.ItemAttachment"
}
},
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"createdAt": {
"type": "string"
},
@ -1277,7 +1296,6 @@ const docTemplate = `{
"type": "string"
},
"fields": {
"description": "Future",
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemField"
@ -1301,6 +1319,8 @@ const docTemplate = `{
},
"location": {
"description": "Edges",
"x-nullable": true,
"x-omitempty": true,
"$ref": "#/definitions/repo.LocationSummary"
},
"manufacturer": {
@ -1316,6 +1336,11 @@ const docTemplate = `{
"description": "Extras",
"type": "string"
},
"parent": {
"x-nullable": true,
"x-omitempty": true,
"$ref": "#/definitions/repo.ItemSummary"
},
"purchaseFrom": {
"type": "string"
},
@ -1381,6 +1406,8 @@ const docTemplate = `{
},
"location": {
"description": "Edges",
"x-nullable": true,
"x-omitempty": true,
"$ref": "#/definitions/repo.LocationSummary"
},
"name": {
@ -1439,6 +1466,11 @@ const docTemplate = `{
"description": "Extras",
"type": "string"
},
"parentId": {
"type": "string",
"x-nullable": true,
"x-omitempty": true
},
"purchaseFrom": {
"type": "string"
},
@ -1553,6 +1585,12 @@ const docTemplate = `{
"repo.LocationOut": {
"type": "object",
"properties": {
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.LocationSummary"
}
},
"createdAt": {
"type": "string"
},
@ -1571,6 +1609,9 @@ const docTemplate = `{
"name": {
"type": "string"
},
"parent": {
"$ref": "#/definitions/repo.LocationSummary"
},
"updatedAt": {
"type": "string"
}
@ -1619,6 +1660,24 @@ const docTemplate = `{
}
}
},
"repo.LocationUpdate": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"parentId": {
"type": "string",
"x-nullable": true
}
}
},
"repo.PaginationResult-repo_ItemSummary": {
"type": "object",
"properties": {

View file

@ -837,6 +837,15 @@
"name": "id",
"in": "path",
"required": true
},
{
"description": "Location Data",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/repo.LocationUpdate"
}
}
],
"responses": {
@ -1224,6 +1233,10 @@
},
"name": {
"type": "string"
},
"parentId": {
"type": "string",
"x-nullable": true
}
}
},
@ -1262,6 +1275,12 @@
"$ref": "#/definitions/repo.ItemAttachment"
}
},
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"createdAt": {
"type": "string"
},
@ -1269,7 +1288,6 @@
"type": "string"
},
"fields": {
"description": "Future",
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemField"
@ -1293,6 +1311,8 @@
},
"location": {
"description": "Edges",
"x-nullable": true,
"x-omitempty": true,
"$ref": "#/definitions/repo.LocationSummary"
},
"manufacturer": {
@ -1308,6 +1328,11 @@
"description": "Extras",
"type": "string"
},
"parent": {
"x-nullable": true,
"x-omitempty": true,
"$ref": "#/definitions/repo.ItemSummary"
},
"purchaseFrom": {
"type": "string"
},
@ -1373,6 +1398,8 @@
},
"location": {
"description": "Edges",
"x-nullable": true,
"x-omitempty": true,
"$ref": "#/definitions/repo.LocationSummary"
},
"name": {
@ -1431,6 +1458,11 @@
"description": "Extras",
"type": "string"
},
"parentId": {
"type": "string",
"x-nullable": true,
"x-omitempty": true
},
"purchaseFrom": {
"type": "string"
},
@ -1545,6 +1577,12 @@
"repo.LocationOut": {
"type": "object",
"properties": {
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.LocationSummary"
}
},
"createdAt": {
"type": "string"
},
@ -1563,6 +1601,9 @@
"name": {
"type": "string"
},
"parent": {
"$ref": "#/definitions/repo.LocationSummary"
},
"updatedAt": {
"type": "string"
}
@ -1611,6 +1652,24 @@
}
}
},
"repo.LocationUpdate": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"parentId": {
"type": "string",
"x-nullable": true
}
}
},
"repo.PaginationResult-repo_ItemSummary": {
"type": "object",
"properties": {

View file

@ -62,6 +62,9 @@ definitions:
type: string
name:
type: string
parentId:
type: string
x-nullable: true
type: object
repo.ItemField:
properties:
@ -86,12 +89,15 @@ definitions:
items:
$ref: '#/definitions/repo.ItemAttachment'
type: array
children:
items:
$ref: '#/definitions/repo.ItemSummary'
type: array
createdAt:
type: string
description:
type: string
fields:
description: Future
items:
$ref: '#/definitions/repo.ItemField'
type: array
@ -109,6 +115,8 @@ definitions:
location:
$ref: '#/definitions/repo.LocationSummary'
description: Edges
x-nullable: true
x-omitempty: true
manufacturer:
type: string
modelNumber:
@ -118,6 +126,10 @@ definitions:
notes:
description: Extras
type: string
parent:
$ref: '#/definitions/repo.ItemSummary'
x-nullable: true
x-omitempty: true
purchaseFrom:
type: string
purchasePrice:
@ -164,6 +176,8 @@ definitions:
location:
$ref: '#/definitions/repo.LocationSummary'
description: Edges
x-nullable: true
x-omitempty: true
name:
type: string
quantity:
@ -202,6 +216,10 @@ definitions:
notes:
description: Extras
type: string
parentId:
type: string
x-nullable: true
x-omitempty: true
purchaseFrom:
type: string
purchasePrice:
@ -278,6 +296,10 @@ definitions:
type: object
repo.LocationOut:
properties:
children:
items:
$ref: '#/definitions/repo.LocationSummary'
type: array
createdAt:
type: string
description:
@ -290,6 +312,8 @@ definitions:
type: array
name:
type: string
parent:
$ref: '#/definitions/repo.LocationSummary'
updatedAt:
type: string
type: object
@ -321,6 +345,18 @@ definitions:
updatedAt:
type: string
type: object
repo.LocationUpdate:
properties:
description:
type: string
id:
type: string
name:
type: string
parentId:
type: string
x-nullable: true
type: object
repo.PaginationResult-repo_ItemSummary:
properties:
items:
@ -976,6 +1012,12 @@ paths:
name: id
required: true
type: string
- description: Location Data
in: body
name: payload
required: true
schema:
$ref: '#/definitions/repo.LocationUpdate'
produces:
- application/json
responses:

View file

@ -88,8 +88,9 @@ func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc {
// @Summary updates a location
// @Tags Locations
// @Produce json
// @Param id path string true "Location ID"
// @Success 200 {object} repo.LocationOut
// @Param id path string true "Location ID"
// @Param payload body repo.LocationUpdate true "Location Data"
// @Success 200 {object} repo.LocationOut
// @Router /v1/locations/{id} [PUT]
// @Security Bearer
func (ctrl *V1Controller) HandleLocationUpdate() http.HandlerFunc {

View file

@ -1043,6 +1043,38 @@ func (c *ItemClient) GetX(ctx context.Context, id uuid.UUID) *Item {
return obj
}
// QueryParent queries the parent edge of a Item.
func (c *ItemClient) QueryParent(i *Item) *ItemQuery {
query := &ItemQuery{config: c.config}
query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) {
id := i.ID
step := sqlgraph.NewStep(
sqlgraph.From(item.Table, item.FieldID, id),
sqlgraph.To(item.Table, item.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, item.ParentTable, item.ParentColumn),
)
fromV = sqlgraph.Neighbors(i.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryChildren queries the children edge of a Item.
func (c *ItemClient) QueryChildren(i *Item) *ItemQuery {
query := &ItemQuery{config: c.config}
query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) {
id := i.ID
step := sqlgraph.NewStep(
sqlgraph.From(item.Table, item.FieldID, id),
sqlgraph.To(item.Table, item.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, item.ChildrenTable, item.ChildrenColumn),
)
fromV = sqlgraph.Neighbors(i.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryGroup queries the group edge of a Item.
func (c *ItemClient) QueryGroup(i *Item) *GroupQuery {
query := &GroupQuery{config: c.config}
@ -1441,6 +1473,38 @@ func (c *LocationClient) GetX(ctx context.Context, id uuid.UUID) *Location {
return obj
}
// QueryParent queries the parent edge of a Location.
func (c *LocationClient) QueryParent(l *Location) *LocationQuery {
query := &LocationQuery{config: c.config}
query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) {
id := l.ID
step := sqlgraph.NewStep(
sqlgraph.From(location.Table, location.FieldID, id),
sqlgraph.To(location.Table, location.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, location.ParentTable, location.ParentColumn),
)
fromV = sqlgraph.Neighbors(l.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryChildren queries the children edge of a Location.
func (c *LocationClient) QueryChildren(l *Location) *LocationQuery {
query := &LocationQuery{config: c.config}
query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) {
id := l.ID
step := sqlgraph.NewStep(
sqlgraph.From(location.Table, location.FieldID, id),
sqlgraph.To(location.Table, location.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, location.ChildrenTable, location.ChildrenColumn),
)
fromV = sqlgraph.Neighbors(l.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryGroup queries the group edge of a Location.
func (c *LocationClient) QueryGroup(l *Location) *GroupQuery {
query := &GroupQuery{config: c.config}

View file

@ -65,11 +65,16 @@ type Item struct {
// The values are being populated by the ItemQuery when eager-loading is set.
Edges ItemEdges `json:"edges"`
group_items *uuid.UUID
item_children *uuid.UUID
location_items *uuid.UUID
}
// ItemEdges holds the relations/edges for other nodes in the graph.
type ItemEdges struct {
// Parent holds the value of the parent edge.
Parent *Item `json:"parent,omitempty"`
// Children holds the value of the children edge.
Children []*Item `json:"children,omitempty"`
// Group holds the value of the group edge.
Group *Group `json:"group,omitempty"`
// Label holds the value of the label edge.
@ -82,13 +87,35 @@ type ItemEdges struct {
Attachments []*Attachment `json:"attachments,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [5]bool
loadedTypes [7]bool
}
// ParentOrErr returns the Parent value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e ItemEdges) ParentOrErr() (*Item, error) {
if e.loadedTypes[0] {
if e.Parent == nil {
// Edge was loaded but was not found.
return nil, &NotFoundError{label: item.Label}
}
return e.Parent, nil
}
return nil, &NotLoadedError{edge: "parent"}
}
// ChildrenOrErr returns the Children value or an error if the edge
// was not loaded in eager-loading.
func (e ItemEdges) ChildrenOrErr() ([]*Item, error) {
if e.loadedTypes[1] {
return e.Children, nil
}
return nil, &NotLoadedError{edge: "children"}
}
// GroupOrErr returns the Group value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e ItemEdges) GroupOrErr() (*Group, error) {
if e.loadedTypes[0] {
if e.loadedTypes[2] {
if e.Group == nil {
// Edge was loaded but was not found.
return nil, &NotFoundError{label: group.Label}
@ -101,7 +128,7 @@ func (e ItemEdges) GroupOrErr() (*Group, error) {
// LabelOrErr returns the Label value or an error if the edge
// was not loaded in eager-loading.
func (e ItemEdges) LabelOrErr() ([]*Label, error) {
if e.loadedTypes[1] {
if e.loadedTypes[3] {
return e.Label, nil
}
return nil, &NotLoadedError{edge: "label"}
@ -110,7 +137,7 @@ func (e ItemEdges) LabelOrErr() ([]*Label, error) {
// LocationOrErr returns the Location value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e ItemEdges) LocationOrErr() (*Location, error) {
if e.loadedTypes[2] {
if e.loadedTypes[4] {
if e.Location == nil {
// Edge was loaded but was not found.
return nil, &NotFoundError{label: location.Label}
@ -123,7 +150,7 @@ func (e ItemEdges) LocationOrErr() (*Location, error) {
// FieldsOrErr returns the Fields value or an error if the edge
// was not loaded in eager-loading.
func (e ItemEdges) FieldsOrErr() ([]*ItemField, error) {
if e.loadedTypes[3] {
if e.loadedTypes[5] {
return e.Fields, nil
}
return nil, &NotLoadedError{edge: "fields"}
@ -132,7 +159,7 @@ func (e ItemEdges) FieldsOrErr() ([]*ItemField, error) {
// AttachmentsOrErr returns the Attachments value or an error if the edge
// was not loaded in eager-loading.
func (e ItemEdges) AttachmentsOrErr() ([]*Attachment, error) {
if e.loadedTypes[4] {
if e.loadedTypes[6] {
return e.Attachments, nil
}
return nil, &NotLoadedError{edge: "attachments"}
@ -157,7 +184,9 @@ func (*Item) scanValues(columns []string) ([]any, error) {
values[i] = new(uuid.UUID)
case item.ForeignKeys[0]: // group_items
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
case item.ForeignKeys[1]: // location_items
case item.ForeignKeys[1]: // item_children
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
case item.ForeignKeys[2]: // location_items
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
default:
return nil, fmt.Errorf("unexpected column %q for type Item", columns[i])
@ -314,6 +343,13 @@ func (i *Item) assignValues(columns []string, values []any) error {
*i.group_items = *value.S.(*uuid.UUID)
}
case item.ForeignKeys[1]:
if value, ok := values[j].(*sql.NullScanner); !ok {
return fmt.Errorf("unexpected type %T for field item_children", values[j])
} else if value.Valid {
i.item_children = new(uuid.UUID)
*i.item_children = *value.S.(*uuid.UUID)
}
case item.ForeignKeys[2]:
if value, ok := values[j].(*sql.NullScanner); !ok {
return fmt.Errorf("unexpected type %T for field location_items", values[j])
} else if value.Valid {
@ -325,6 +361,16 @@ func (i *Item) assignValues(columns []string, values []any) error {
return nil
}
// QueryParent queries the "parent" edge of the Item entity.
func (i *Item) QueryParent() *ItemQuery {
return (&ItemClient{config: i.config}).QueryParent(i)
}
// QueryChildren queries the "children" edge of the Item entity.
func (i *Item) QueryChildren() *ItemQuery {
return (&ItemClient{config: i.config}).QueryChildren(i)
}
// QueryGroup queries the "group" edge of the Item entity.
func (i *Item) QueryGroup() *GroupQuery {
return (&ItemClient{config: i.config}).QueryGroup(i)

View file

@ -55,6 +55,10 @@ const (
FieldSoldPrice = "sold_price"
// FieldSoldNotes holds the string denoting the sold_notes field in the database.
FieldSoldNotes = "sold_notes"
// EdgeParent holds the string denoting the parent edge name in mutations.
EdgeParent = "parent"
// EdgeChildren holds the string denoting the children edge name in mutations.
EdgeChildren = "children"
// EdgeGroup holds the string denoting the group edge name in mutations.
EdgeGroup = "group"
// EdgeLabel holds the string denoting the label edge name in mutations.
@ -67,6 +71,14 @@ const (
EdgeAttachments = "attachments"
// Table holds the table name of the item in the database.
Table = "items"
// ParentTable is the table that holds the parent relation/edge.
ParentTable = "items"
// ParentColumn is the table column denoting the parent relation/edge.
ParentColumn = "item_children"
// ChildrenTable is the table that holds the children relation/edge.
ChildrenTable = "items"
// ChildrenColumn is the table column denoting the children relation/edge.
ChildrenColumn = "item_children"
// GroupTable is the table that holds the group relation/edge.
GroupTable = "items"
// GroupInverseTable is the table name for the Group entity.
@ -132,6 +144,7 @@ var Columns = []string{
// table and are not defined as standalone fields in the schema.
var ForeignKeys = []string{
"group_items",
"item_children",
"location_items",
}

View file

@ -2040,6 +2040,62 @@ func SoldNotesContainsFold(v string) predicate.Item {
})
}
// HasParent applies the HasEdge predicate on the "parent" edge.
func HasParent() predicate.Item {
return predicate.Item(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(ParentTable, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, ParentTable, ParentColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasParentWith applies the HasEdge predicate on the "parent" edge with a given conditions (other predicates).
func HasParentWith(preds ...predicate.Item) predicate.Item {
return predicate.Item(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, ParentTable, ParentColumn),
)
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// HasChildren applies the HasEdge predicate on the "children" edge.
func HasChildren() predicate.Item {
return predicate.Item(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(ChildrenTable, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, ChildrenTable, ChildrenColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasChildrenWith applies the HasEdge predicate on the "children" edge with a given conditions (other predicates).
func HasChildrenWith(preds ...predicate.Item) predicate.Item {
return predicate.Item(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(Table, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, ChildrenTable, ChildrenColumn),
)
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// HasGroup applies the HasEdge predicate on the "group" edge.
func HasGroup() predicate.Item {
return predicate.Item(func(s *sql.Selector) {

View file

@ -326,6 +326,40 @@ func (ic *ItemCreate) SetNillableID(u *uuid.UUID) *ItemCreate {
return ic
}
// SetParentID sets the "parent" edge to the Item entity by ID.
func (ic *ItemCreate) SetParentID(id uuid.UUID) *ItemCreate {
ic.mutation.SetParentID(id)
return ic
}
// SetNillableParentID sets the "parent" edge to the Item entity by ID if the given value is not nil.
func (ic *ItemCreate) SetNillableParentID(id *uuid.UUID) *ItemCreate {
if id != nil {
ic = ic.SetParentID(*id)
}
return ic
}
// SetParent sets the "parent" edge to the Item entity.
func (ic *ItemCreate) SetParent(i *Item) *ItemCreate {
return ic.SetParentID(i.ID)
}
// AddChildIDs adds the "children" edge to the Item entity by IDs.
func (ic *ItemCreate) AddChildIDs(ids ...uuid.UUID) *ItemCreate {
ic.mutation.AddChildIDs(ids...)
return ic
}
// AddChildren adds the "children" edges to the Item entity.
func (ic *ItemCreate) AddChildren(i ...*Item) *ItemCreate {
ids := make([]uuid.UUID, len(i))
for j := range i {
ids[j] = i[j].ID
}
return ic.AddChildIDs(ids...)
}
// SetGroupID sets the "group" edge to the Group entity by ID.
func (ic *ItemCreate) SetGroupID(id uuid.UUID) *ItemCreate {
ic.mutation.SetGroupID(id)
@ -790,6 +824,45 @@ func (ic *ItemCreate) createSpec() (*Item, *sqlgraph.CreateSpec) {
})
_node.SoldNotes = value
}
if nodes := ic.mutation.ParentIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: item.ParentTable,
Columns: []string{item.ParentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_node.item_children = &nodes[0]
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := ic.mutation.ChildrenIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: item.ChildrenTable,
Columns: []string{item.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := ic.mutation.GroupIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,

View file

@ -30,6 +30,8 @@ type ItemQuery struct {
order []OrderFunc
fields []string
predicates []predicate.Item
withParent *ItemQuery
withChildren *ItemQuery
withGroup *GroupQuery
withLabel *LabelQuery
withLocation *LocationQuery
@ -72,6 +74,50 @@ func (iq *ItemQuery) Order(o ...OrderFunc) *ItemQuery {
return iq
}
// QueryParent chains the current query on the "parent" edge.
func (iq *ItemQuery) QueryParent() *ItemQuery {
query := &ItemQuery{config: iq.config}
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := iq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := iq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(item.Table, item.FieldID, selector),
sqlgraph.To(item.Table, item.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, item.ParentTable, item.ParentColumn),
)
fromU = sqlgraph.SetNeighbors(iq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryChildren chains the current query on the "children" edge.
func (iq *ItemQuery) QueryChildren() *ItemQuery {
query := &ItemQuery{config: iq.config}
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := iq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := iq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(item.Table, item.FieldID, selector),
sqlgraph.To(item.Table, item.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, item.ChildrenTable, item.ChildrenColumn),
)
fromU = sqlgraph.SetNeighbors(iq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryGroup chains the current query on the "group" edge.
func (iq *ItemQuery) QueryGroup() *GroupQuery {
query := &GroupQuery{config: iq.config}
@ -363,6 +409,8 @@ func (iq *ItemQuery) Clone() *ItemQuery {
offset: iq.offset,
order: append([]OrderFunc{}, iq.order...),
predicates: append([]predicate.Item{}, iq.predicates...),
withParent: iq.withParent.Clone(),
withChildren: iq.withChildren.Clone(),
withGroup: iq.withGroup.Clone(),
withLabel: iq.withLabel.Clone(),
withLocation: iq.withLocation.Clone(),
@ -375,6 +423,28 @@ func (iq *ItemQuery) Clone() *ItemQuery {
}
}
// WithParent tells the query-builder to eager-load the nodes that are connected to
// the "parent" edge. The optional arguments are used to configure the query builder of the edge.
func (iq *ItemQuery) WithParent(opts ...func(*ItemQuery)) *ItemQuery {
query := &ItemQuery{config: iq.config}
for _, opt := range opts {
opt(query)
}
iq.withParent = query
return iq
}
// WithChildren tells the query-builder to eager-load the nodes that are connected to
// the "children" edge. The optional arguments are used to configure the query builder of the edge.
func (iq *ItemQuery) WithChildren(opts ...func(*ItemQuery)) *ItemQuery {
query := &ItemQuery{config: iq.config}
for _, opt := range opts {
opt(query)
}
iq.withChildren = query
return iq
}
// WithGroup tells the query-builder to eager-load the nodes that are connected to
// the "group" edge. The optional arguments are used to configure the query builder of the edge.
func (iq *ItemQuery) WithGroup(opts ...func(*GroupQuery)) *ItemQuery {
@ -499,7 +569,9 @@ func (iq *ItemQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Item, e
nodes = []*Item{}
withFKs = iq.withFKs
_spec = iq.querySpec()
loadedTypes = [5]bool{
loadedTypes = [7]bool{
iq.withParent != nil,
iq.withChildren != nil,
iq.withGroup != nil,
iq.withLabel != nil,
iq.withLocation != nil,
@ -507,7 +579,7 @@ func (iq *ItemQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Item, e
iq.withAttachments != nil,
}
)
if iq.withGroup != nil || iq.withLocation != nil {
if iq.withParent != nil || iq.withGroup != nil || iq.withLocation != nil {
withFKs = true
}
if withFKs {
@ -531,6 +603,19 @@ func (iq *ItemQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Item, e
if len(nodes) == 0 {
return nodes, nil
}
if query := iq.withParent; query != nil {
if err := iq.loadParent(ctx, query, nodes, nil,
func(n *Item, e *Item) { n.Edges.Parent = e }); err != nil {
return nil, err
}
}
if query := iq.withChildren; query != nil {
if err := iq.loadChildren(ctx, query, nodes,
func(n *Item) { n.Edges.Children = []*Item{} },
func(n *Item, e *Item) { n.Edges.Children = append(n.Edges.Children, e) }); err != nil {
return nil, err
}
}
if query := iq.withGroup; query != nil {
if err := iq.loadGroup(ctx, query, nodes, nil,
func(n *Item, e *Group) { n.Edges.Group = e }); err != nil {
@ -567,6 +652,66 @@ func (iq *ItemQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Item, e
return nodes, nil
}
func (iq *ItemQuery) loadParent(ctx context.Context, query *ItemQuery, nodes []*Item, init func(*Item), assign func(*Item, *Item)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*Item)
for i := range nodes {
if nodes[i].item_children == nil {
continue
}
fk := *nodes[i].item_children
if _, ok := nodeids[fk]; !ok {
ids = append(ids, fk)
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
query.Where(item.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 "item_children" returned %v`, n.ID)
}
for i := range nodes {
assign(nodes[i], n)
}
}
return nil
}
func (iq *ItemQuery) loadChildren(ctx context.Context, query *ItemQuery, nodes []*Item, init func(*Item), assign func(*Item, *Item)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Item)
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(item.ChildrenColumn, fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.item_children
if fk == nil {
return fmt.Errorf(`foreign-key "item_children" is nil for node %v`, n.ID)
}
node, ok := nodeids[*fk]
if !ok {
return fmt.Errorf(`unexpected foreign-key "item_children" returned %v for node %v`, *fk, n.ID)
}
assign(node, n)
}
return nil
}
func (iq *ItemQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*Item, init func(*Item), assign func(*Item, *Group)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*Item)

View file

@ -377,6 +377,40 @@ func (iu *ItemUpdate) ClearSoldNotes() *ItemUpdate {
return iu
}
// SetParentID sets the "parent" edge to the Item entity by ID.
func (iu *ItemUpdate) SetParentID(id uuid.UUID) *ItemUpdate {
iu.mutation.SetParentID(id)
return iu
}
// SetNillableParentID sets the "parent" edge to the Item entity by ID if the given value is not nil.
func (iu *ItemUpdate) SetNillableParentID(id *uuid.UUID) *ItemUpdate {
if id != nil {
iu = iu.SetParentID(*id)
}
return iu
}
// SetParent sets the "parent" edge to the Item entity.
func (iu *ItemUpdate) SetParent(i *Item) *ItemUpdate {
return iu.SetParentID(i.ID)
}
// AddChildIDs adds the "children" edge to the Item entity by IDs.
func (iu *ItemUpdate) AddChildIDs(ids ...uuid.UUID) *ItemUpdate {
iu.mutation.AddChildIDs(ids...)
return iu
}
// AddChildren adds the "children" edges to the Item entity.
func (iu *ItemUpdate) AddChildren(i ...*Item) *ItemUpdate {
ids := make([]uuid.UUID, len(i))
for j := range i {
ids[j] = i[j].ID
}
return iu.AddChildIDs(ids...)
}
// SetGroupID sets the "group" edge to the Group entity by ID.
func (iu *ItemUpdate) SetGroupID(id uuid.UUID) *ItemUpdate {
iu.mutation.SetGroupID(id)
@ -457,6 +491,33 @@ func (iu *ItemUpdate) Mutation() *ItemMutation {
return iu.mutation
}
// ClearParent clears the "parent" edge to the Item entity.
func (iu *ItemUpdate) ClearParent() *ItemUpdate {
iu.mutation.ClearParent()
return iu
}
// ClearChildren clears all "children" edges to the Item entity.
func (iu *ItemUpdate) ClearChildren() *ItemUpdate {
iu.mutation.ClearChildren()
return iu
}
// RemoveChildIDs removes the "children" edge to Item entities by IDs.
func (iu *ItemUpdate) RemoveChildIDs(ids ...uuid.UUID) *ItemUpdate {
iu.mutation.RemoveChildIDs(ids...)
return iu
}
// RemoveChildren removes "children" edges to Item entities.
func (iu *ItemUpdate) RemoveChildren(i ...*Item) *ItemUpdate {
ids := make([]uuid.UUID, len(i))
for j := range i {
ids[j] = i[j].ID
}
return iu.RemoveChildIDs(ids...)
}
// ClearGroup clears the "group" edge to the Group entity.
func (iu *ItemUpdate) ClearGroup() *ItemUpdate {
iu.mutation.ClearGroup()
@ -899,6 +960,95 @@ func (iu *ItemUpdate) sqlSave(ctx context.Context) (n int, err error) {
Column: item.FieldSoldNotes,
})
}
if iu.mutation.ParentCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: item.ParentTable,
Columns: []string{item.ParentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := iu.mutation.ParentIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: item.ParentTable,
Columns: []string{item.ParentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if iu.mutation.ChildrenCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: item.ChildrenTable,
Columns: []string{item.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := iu.mutation.RemovedChildrenIDs(); len(nodes) > 0 && !iu.mutation.ChildrenCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: item.ChildrenTable,
Columns: []string{item.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := iu.mutation.ChildrenIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: item.ChildrenTable,
Columns: []string{item.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if iu.mutation.GroupCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
@ -1493,6 +1643,40 @@ func (iuo *ItemUpdateOne) ClearSoldNotes() *ItemUpdateOne {
return iuo
}
// SetParentID sets the "parent" edge to the Item entity by ID.
func (iuo *ItemUpdateOne) SetParentID(id uuid.UUID) *ItemUpdateOne {
iuo.mutation.SetParentID(id)
return iuo
}
// SetNillableParentID sets the "parent" edge to the Item entity by ID if the given value is not nil.
func (iuo *ItemUpdateOne) SetNillableParentID(id *uuid.UUID) *ItemUpdateOne {
if id != nil {
iuo = iuo.SetParentID(*id)
}
return iuo
}
// SetParent sets the "parent" edge to the Item entity.
func (iuo *ItemUpdateOne) SetParent(i *Item) *ItemUpdateOne {
return iuo.SetParentID(i.ID)
}
// AddChildIDs adds the "children" edge to the Item entity by IDs.
func (iuo *ItemUpdateOne) AddChildIDs(ids ...uuid.UUID) *ItemUpdateOne {
iuo.mutation.AddChildIDs(ids...)
return iuo
}
// AddChildren adds the "children" edges to the Item entity.
func (iuo *ItemUpdateOne) AddChildren(i ...*Item) *ItemUpdateOne {
ids := make([]uuid.UUID, len(i))
for j := range i {
ids[j] = i[j].ID
}
return iuo.AddChildIDs(ids...)
}
// SetGroupID sets the "group" edge to the Group entity by ID.
func (iuo *ItemUpdateOne) SetGroupID(id uuid.UUID) *ItemUpdateOne {
iuo.mutation.SetGroupID(id)
@ -1573,6 +1757,33 @@ func (iuo *ItemUpdateOne) Mutation() *ItemMutation {
return iuo.mutation
}
// ClearParent clears the "parent" edge to the Item entity.
func (iuo *ItemUpdateOne) ClearParent() *ItemUpdateOne {
iuo.mutation.ClearParent()
return iuo
}
// ClearChildren clears all "children" edges to the Item entity.
func (iuo *ItemUpdateOne) ClearChildren() *ItemUpdateOne {
iuo.mutation.ClearChildren()
return iuo
}
// RemoveChildIDs removes the "children" edge to Item entities by IDs.
func (iuo *ItemUpdateOne) RemoveChildIDs(ids ...uuid.UUID) *ItemUpdateOne {
iuo.mutation.RemoveChildIDs(ids...)
return iuo
}
// RemoveChildren removes "children" edges to Item entities.
func (iuo *ItemUpdateOne) RemoveChildren(i ...*Item) *ItemUpdateOne {
ids := make([]uuid.UUID, len(i))
for j := range i {
ids[j] = i[j].ID
}
return iuo.RemoveChildIDs(ids...)
}
// ClearGroup clears the "group" edge to the Group entity.
func (iuo *ItemUpdateOne) ClearGroup() *ItemUpdateOne {
iuo.mutation.ClearGroup()
@ -2045,6 +2256,95 @@ func (iuo *ItemUpdateOne) sqlSave(ctx context.Context) (_node *Item, err error)
Column: item.FieldSoldNotes,
})
}
if iuo.mutation.ParentCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: item.ParentTable,
Columns: []string{item.ParentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := iuo.mutation.ParentIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: item.ParentTable,
Columns: []string{item.ParentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if iuo.mutation.ChildrenCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: item.ChildrenTable,
Columns: []string{item.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := iuo.mutation.RemovedChildrenIDs(); len(nodes) > 0 && !iuo.mutation.ChildrenCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: item.ChildrenTable,
Columns: []string{item.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := iuo.mutation.ChildrenIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: item.ChildrenTable,
Columns: []string{item.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: item.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if iuo.mutation.GroupCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,

View file

@ -28,25 +28,52 @@ type Location struct {
Description string `json:"description,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the LocationQuery when eager-loading is set.
Edges LocationEdges `json:"edges"`
group_locations *uuid.UUID
Edges LocationEdges `json:"edges"`
group_locations *uuid.UUID
location_children *uuid.UUID
}
// LocationEdges holds the relations/edges for other nodes in the graph.
type LocationEdges struct {
// Parent holds the value of the parent edge.
Parent *Location `json:"parent,omitempty"`
// Children holds the value of the children edge.
Children []*Location `json:"children,omitempty"`
// Group holds the value of the group edge.
Group *Group `json:"group,omitempty"`
// Items holds the value of the items edge.
Items []*Item `json:"items,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [2]bool
loadedTypes [4]bool
}
// ParentOrErr returns the Parent value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e LocationEdges) ParentOrErr() (*Location, error) {
if e.loadedTypes[0] {
if e.Parent == nil {
// Edge was loaded but was not found.
return nil, &NotFoundError{label: location.Label}
}
return e.Parent, nil
}
return nil, &NotLoadedError{edge: "parent"}
}
// ChildrenOrErr returns the Children value or an error if the edge
// was not loaded in eager-loading.
func (e LocationEdges) ChildrenOrErr() ([]*Location, error) {
if e.loadedTypes[1] {
return e.Children, nil
}
return nil, &NotLoadedError{edge: "children"}
}
// GroupOrErr returns the Group value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e LocationEdges) GroupOrErr() (*Group, error) {
if e.loadedTypes[0] {
if e.loadedTypes[2] {
if e.Group == nil {
// Edge was loaded but was not found.
return nil, &NotFoundError{label: group.Label}
@ -59,7 +86,7 @@ func (e LocationEdges) GroupOrErr() (*Group, error) {
// ItemsOrErr returns the Items value or an error if the edge
// was not loaded in eager-loading.
func (e LocationEdges) ItemsOrErr() ([]*Item, error) {
if e.loadedTypes[1] {
if e.loadedTypes[3] {
return e.Items, nil
}
return nil, &NotLoadedError{edge: "items"}
@ -78,6 +105,8 @@ func (*Location) scanValues(columns []string) ([]any, error) {
values[i] = new(uuid.UUID)
case location.ForeignKeys[0]: // group_locations
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
case location.ForeignKeys[1]: // location_children
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
default:
return nil, fmt.Errorf("unexpected column %q for type Location", columns[i])
}
@ -130,11 +159,28 @@ func (l *Location) assignValues(columns []string, values []any) error {
l.group_locations = new(uuid.UUID)
*l.group_locations = *value.S.(*uuid.UUID)
}
case location.ForeignKeys[1]:
if value, ok := values[i].(*sql.NullScanner); !ok {
return fmt.Errorf("unexpected type %T for field location_children", values[i])
} else if value.Valid {
l.location_children = new(uuid.UUID)
*l.location_children = *value.S.(*uuid.UUID)
}
}
}
return nil
}
// QueryParent queries the "parent" edge of the Location entity.
func (l *Location) QueryParent() *LocationQuery {
return (&LocationClient{config: l.config}).QueryParent(l)
}
// QueryChildren queries the "children" edge of the Location entity.
func (l *Location) QueryChildren() *LocationQuery {
return (&LocationClient{config: l.config}).QueryChildren(l)
}
// QueryGroup queries the "group" edge of the Location entity.
func (l *Location) QueryGroup() *GroupQuery {
return (&LocationClient{config: l.config}).QueryGroup(l)

View file

@ -21,12 +21,24 @@ const (
FieldName = "name"
// FieldDescription holds the string denoting the description field in the database.
FieldDescription = "description"
// EdgeParent holds the string denoting the parent edge name in mutations.
EdgeParent = "parent"
// EdgeChildren holds the string denoting the children edge name in mutations.
EdgeChildren = "children"
// EdgeGroup holds the string denoting the group edge name in mutations.
EdgeGroup = "group"
// EdgeItems holds the string denoting the items edge name in mutations.
EdgeItems = "items"
// Table holds the table name of the location in the database.
Table = "locations"
// ParentTable is the table that holds the parent relation/edge.
ParentTable = "locations"
// ParentColumn is the table column denoting the parent relation/edge.
ParentColumn = "location_children"
// ChildrenTable is the table that holds the children relation/edge.
ChildrenTable = "locations"
// ChildrenColumn is the table column denoting the children relation/edge.
ChildrenColumn = "location_children"
// GroupTable is the table that holds the group relation/edge.
GroupTable = "locations"
// GroupInverseTable is the table name for the Group entity.
@ -56,6 +68,7 @@ var Columns = []string{
// table and are not defined as standalone fields in the schema.
var ForeignKeys = []string{
"group_locations",
"location_children",
}
// ValidColumn reports if the column name is valid (part of the table columns).

View file

@ -450,6 +450,62 @@ func DescriptionContainsFold(v string) predicate.Location {
})
}
// HasParent applies the HasEdge predicate on the "parent" edge.
func HasParent() predicate.Location {
return predicate.Location(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(ParentTable, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, ParentTable, ParentColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasParentWith applies the HasEdge predicate on the "parent" edge with a given conditions (other predicates).
func HasParentWith(preds ...predicate.Location) predicate.Location {
return predicate.Location(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, ParentTable, ParentColumn),
)
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// HasChildren applies the HasEdge predicate on the "children" edge.
func HasChildren() predicate.Location {
return predicate.Location(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(ChildrenTable, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, ChildrenTable, ChildrenColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasChildrenWith applies the HasEdge predicate on the "children" edge with a given conditions (other predicates).
func HasChildrenWith(preds ...predicate.Location) predicate.Location {
return predicate.Location(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(Table, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, ChildrenTable, ChildrenColumn),
)
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// HasGroup applies the HasEdge predicate on the "group" edge.
func HasGroup() predicate.Location {
return predicate.Location(func(s *sql.Selector) {

View file

@ -85,6 +85,40 @@ func (lc *LocationCreate) SetNillableID(u *uuid.UUID) *LocationCreate {
return lc
}
// SetParentID sets the "parent" edge to the Location entity by ID.
func (lc *LocationCreate) SetParentID(id uuid.UUID) *LocationCreate {
lc.mutation.SetParentID(id)
return lc
}
// SetNillableParentID sets the "parent" edge to the Location entity by ID if the given value is not nil.
func (lc *LocationCreate) SetNillableParentID(id *uuid.UUID) *LocationCreate {
if id != nil {
lc = lc.SetParentID(*id)
}
return lc
}
// SetParent sets the "parent" edge to the Location entity.
func (lc *LocationCreate) SetParent(l *Location) *LocationCreate {
return lc.SetParentID(l.ID)
}
// AddChildIDs adds the "children" edge to the Location entity by IDs.
func (lc *LocationCreate) AddChildIDs(ids ...uuid.UUID) *LocationCreate {
lc.mutation.AddChildIDs(ids...)
return lc
}
// AddChildren adds the "children" edges to the Location entity.
func (lc *LocationCreate) AddChildren(l ...*Location) *LocationCreate {
ids := make([]uuid.UUID, len(l))
for i := range l {
ids[i] = l[i].ID
}
return lc.AddChildIDs(ids...)
}
// SetGroupID sets the "group" edge to the Group entity by ID.
func (lc *LocationCreate) SetGroupID(id uuid.UUID) *LocationCreate {
lc.mutation.SetGroupID(id)
@ -294,6 +328,45 @@ func (lc *LocationCreate) createSpec() (*Location, *sqlgraph.CreateSpec) {
})
_node.Description = value
}
if nodes := lc.mutation.ParentIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: location.ParentTable,
Columns: []string{location.ParentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_node.location_children = &nodes[0]
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := lc.mutation.ChildrenIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: location.ChildrenTable,
Columns: []string{location.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := lc.mutation.GroupIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,

View file

@ -21,15 +21,17 @@ import (
// LocationQuery is the builder for querying Location entities.
type LocationQuery struct {
config
limit *int
offset *int
unique *bool
order []OrderFunc
fields []string
predicates []predicate.Location
withGroup *GroupQuery
withItems *ItemQuery
withFKs bool
limit *int
offset *int
unique *bool
order []OrderFunc
fields []string
predicates []predicate.Location
withParent *LocationQuery
withChildren *LocationQuery
withGroup *GroupQuery
withItems *ItemQuery
withFKs bool
// intermediate query (i.e. traversal path).
sql *sql.Selector
path func(context.Context) (*sql.Selector, error)
@ -66,6 +68,50 @@ func (lq *LocationQuery) Order(o ...OrderFunc) *LocationQuery {
return lq
}
// QueryParent chains the current query on the "parent" edge.
func (lq *LocationQuery) QueryParent() *LocationQuery {
query := &LocationQuery{config: lq.config}
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := lq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := lq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(location.Table, location.FieldID, selector),
sqlgraph.To(location.Table, location.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, location.ParentTable, location.ParentColumn),
)
fromU = sqlgraph.SetNeighbors(lq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryChildren chains the current query on the "children" edge.
func (lq *LocationQuery) QueryChildren() *LocationQuery {
query := &LocationQuery{config: lq.config}
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := lq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := lq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(location.Table, location.FieldID, selector),
sqlgraph.To(location.Table, location.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, location.ChildrenTable, location.ChildrenColumn),
)
fromU = sqlgraph.SetNeighbors(lq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryGroup chains the current query on the "group" edge.
func (lq *LocationQuery) QueryGroup() *GroupQuery {
query := &GroupQuery{config: lq.config}
@ -286,13 +332,15 @@ func (lq *LocationQuery) Clone() *LocationQuery {
return nil
}
return &LocationQuery{
config: lq.config,
limit: lq.limit,
offset: lq.offset,
order: append([]OrderFunc{}, lq.order...),
predicates: append([]predicate.Location{}, lq.predicates...),
withGroup: lq.withGroup.Clone(),
withItems: lq.withItems.Clone(),
config: lq.config,
limit: lq.limit,
offset: lq.offset,
order: append([]OrderFunc{}, lq.order...),
predicates: append([]predicate.Location{}, lq.predicates...),
withParent: lq.withParent.Clone(),
withChildren: lq.withChildren.Clone(),
withGroup: lq.withGroup.Clone(),
withItems: lq.withItems.Clone(),
// clone intermediate query.
sql: lq.sql.Clone(),
path: lq.path,
@ -300,6 +348,28 @@ func (lq *LocationQuery) Clone() *LocationQuery {
}
}
// WithParent tells the query-builder to eager-load the nodes that are connected to
// the "parent" edge. The optional arguments are used to configure the query builder of the edge.
func (lq *LocationQuery) WithParent(opts ...func(*LocationQuery)) *LocationQuery {
query := &LocationQuery{config: lq.config}
for _, opt := range opts {
opt(query)
}
lq.withParent = query
return lq
}
// WithChildren tells the query-builder to eager-load the nodes that are connected to
// the "children" edge. The optional arguments are used to configure the query builder of the edge.
func (lq *LocationQuery) WithChildren(opts ...func(*LocationQuery)) *LocationQuery {
query := &LocationQuery{config: lq.config}
for _, opt := range opts {
opt(query)
}
lq.withChildren = query
return lq
}
// WithGroup tells the query-builder to eager-load the nodes that are connected to
// the "group" edge. The optional arguments are used to configure the query builder of the edge.
func (lq *LocationQuery) WithGroup(opts ...func(*GroupQuery)) *LocationQuery {
@ -391,12 +461,14 @@ func (lq *LocationQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Loc
nodes = []*Location{}
withFKs = lq.withFKs
_spec = lq.querySpec()
loadedTypes = [2]bool{
loadedTypes = [4]bool{
lq.withParent != nil,
lq.withChildren != nil,
lq.withGroup != nil,
lq.withItems != nil,
}
)
if lq.withGroup != nil {
if lq.withParent != nil || lq.withGroup != nil {
withFKs = true
}
if withFKs {
@ -420,6 +492,19 @@ func (lq *LocationQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Loc
if len(nodes) == 0 {
return nodes, nil
}
if query := lq.withParent; query != nil {
if err := lq.loadParent(ctx, query, nodes, nil,
func(n *Location, e *Location) { n.Edges.Parent = e }); err != nil {
return nil, err
}
}
if query := lq.withChildren; query != nil {
if err := lq.loadChildren(ctx, query, nodes,
func(n *Location) { n.Edges.Children = []*Location{} },
func(n *Location, e *Location) { n.Edges.Children = append(n.Edges.Children, e) }); err != nil {
return nil, err
}
}
if query := lq.withGroup; query != nil {
if err := lq.loadGroup(ctx, query, nodes, nil,
func(n *Location, e *Group) { n.Edges.Group = e }); err != nil {
@ -436,6 +521,66 @@ func (lq *LocationQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Loc
return nodes, nil
}
func (lq *LocationQuery) loadParent(ctx context.Context, query *LocationQuery, nodes []*Location, init func(*Location), assign func(*Location, *Location)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*Location)
for i := range nodes {
if nodes[i].location_children == nil {
continue
}
fk := *nodes[i].location_children
if _, ok := nodeids[fk]; !ok {
ids = append(ids, fk)
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
query.Where(location.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 "location_children" returned %v`, n.ID)
}
for i := range nodes {
assign(nodes[i], n)
}
}
return nil
}
func (lq *LocationQuery) loadChildren(ctx context.Context, query *LocationQuery, nodes []*Location, init func(*Location), assign func(*Location, *Location)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Location)
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(location.ChildrenColumn, fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.location_children
if fk == nil {
return fmt.Errorf(`foreign-key "location_children" is nil for node %v`, n.ID)
}
node, ok := nodeids[*fk]
if !ok {
return fmt.Errorf(`unexpected foreign-key "location_children" returned %v for node %v`, *fk, n.ID)
}
assign(node, n)
}
return nil
}
func (lq *LocationQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*Location, init func(*Location), assign func(*Location, *Group)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*Location)

View file

@ -63,6 +63,40 @@ func (lu *LocationUpdate) ClearDescription() *LocationUpdate {
return lu
}
// SetParentID sets the "parent" edge to the Location entity by ID.
func (lu *LocationUpdate) SetParentID(id uuid.UUID) *LocationUpdate {
lu.mutation.SetParentID(id)
return lu
}
// SetNillableParentID sets the "parent" edge to the Location entity by ID if the given value is not nil.
func (lu *LocationUpdate) SetNillableParentID(id *uuid.UUID) *LocationUpdate {
if id != nil {
lu = lu.SetParentID(*id)
}
return lu
}
// SetParent sets the "parent" edge to the Location entity.
func (lu *LocationUpdate) SetParent(l *Location) *LocationUpdate {
return lu.SetParentID(l.ID)
}
// AddChildIDs adds the "children" edge to the Location entity by IDs.
func (lu *LocationUpdate) AddChildIDs(ids ...uuid.UUID) *LocationUpdate {
lu.mutation.AddChildIDs(ids...)
return lu
}
// AddChildren adds the "children" edges to the Location entity.
func (lu *LocationUpdate) AddChildren(l ...*Location) *LocationUpdate {
ids := make([]uuid.UUID, len(l))
for i := range l {
ids[i] = l[i].ID
}
return lu.AddChildIDs(ids...)
}
// SetGroupID sets the "group" edge to the Group entity by ID.
func (lu *LocationUpdate) SetGroupID(id uuid.UUID) *LocationUpdate {
lu.mutation.SetGroupID(id)
@ -94,6 +128,33 @@ func (lu *LocationUpdate) Mutation() *LocationMutation {
return lu.mutation
}
// ClearParent clears the "parent" edge to the Location entity.
func (lu *LocationUpdate) ClearParent() *LocationUpdate {
lu.mutation.ClearParent()
return lu
}
// ClearChildren clears all "children" edges to the Location entity.
func (lu *LocationUpdate) ClearChildren() *LocationUpdate {
lu.mutation.ClearChildren()
return lu
}
// RemoveChildIDs removes the "children" edge to Location entities by IDs.
func (lu *LocationUpdate) RemoveChildIDs(ids ...uuid.UUID) *LocationUpdate {
lu.mutation.RemoveChildIDs(ids...)
return lu
}
// RemoveChildren removes "children" edges to Location entities.
func (lu *LocationUpdate) RemoveChildren(l ...*Location) *LocationUpdate {
ids := make([]uuid.UUID, len(l))
for i := range l {
ids[i] = l[i].ID
}
return lu.RemoveChildIDs(ids...)
}
// ClearGroup clears the "group" edge to the Group entity.
func (lu *LocationUpdate) ClearGroup() *LocationUpdate {
lu.mutation.ClearGroup()
@ -253,6 +314,95 @@ func (lu *LocationUpdate) sqlSave(ctx context.Context) (n int, err error) {
Column: location.FieldDescription,
})
}
if lu.mutation.ParentCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: location.ParentTable,
Columns: []string{location.ParentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := lu.mutation.ParentIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: location.ParentTable,
Columns: []string{location.ParentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if lu.mutation.ChildrenCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: location.ChildrenTable,
Columns: []string{location.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := lu.mutation.RemovedChildrenIDs(); len(nodes) > 0 && !lu.mutation.ChildrenCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: location.ChildrenTable,
Columns: []string{location.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := lu.mutation.ChildrenIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: location.ChildrenTable,
Columns: []string{location.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if lu.mutation.GroupCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
@ -393,6 +543,40 @@ func (luo *LocationUpdateOne) ClearDescription() *LocationUpdateOne {
return luo
}
// SetParentID sets the "parent" edge to the Location entity by ID.
func (luo *LocationUpdateOne) SetParentID(id uuid.UUID) *LocationUpdateOne {
luo.mutation.SetParentID(id)
return luo
}
// SetNillableParentID sets the "parent" edge to the Location entity by ID if the given value is not nil.
func (luo *LocationUpdateOne) SetNillableParentID(id *uuid.UUID) *LocationUpdateOne {
if id != nil {
luo = luo.SetParentID(*id)
}
return luo
}
// SetParent sets the "parent" edge to the Location entity.
func (luo *LocationUpdateOne) SetParent(l *Location) *LocationUpdateOne {
return luo.SetParentID(l.ID)
}
// AddChildIDs adds the "children" edge to the Location entity by IDs.
func (luo *LocationUpdateOne) AddChildIDs(ids ...uuid.UUID) *LocationUpdateOne {
luo.mutation.AddChildIDs(ids...)
return luo
}
// AddChildren adds the "children" edges to the Location entity.
func (luo *LocationUpdateOne) AddChildren(l ...*Location) *LocationUpdateOne {
ids := make([]uuid.UUID, len(l))
for i := range l {
ids[i] = l[i].ID
}
return luo.AddChildIDs(ids...)
}
// SetGroupID sets the "group" edge to the Group entity by ID.
func (luo *LocationUpdateOne) SetGroupID(id uuid.UUID) *LocationUpdateOne {
luo.mutation.SetGroupID(id)
@ -424,6 +608,33 @@ func (luo *LocationUpdateOne) Mutation() *LocationMutation {
return luo.mutation
}
// ClearParent clears the "parent" edge to the Location entity.
func (luo *LocationUpdateOne) ClearParent() *LocationUpdateOne {
luo.mutation.ClearParent()
return luo
}
// ClearChildren clears all "children" edges to the Location entity.
func (luo *LocationUpdateOne) ClearChildren() *LocationUpdateOne {
luo.mutation.ClearChildren()
return luo
}
// RemoveChildIDs removes the "children" edge to Location entities by IDs.
func (luo *LocationUpdateOne) RemoveChildIDs(ids ...uuid.UUID) *LocationUpdateOne {
luo.mutation.RemoveChildIDs(ids...)
return luo
}
// RemoveChildren removes "children" edges to Location entities.
func (luo *LocationUpdateOne) RemoveChildren(l ...*Location) *LocationUpdateOne {
ids := make([]uuid.UUID, len(l))
for i := range l {
ids[i] = l[i].ID
}
return luo.RemoveChildIDs(ids...)
}
// ClearGroup clears the "group" edge to the Group entity.
func (luo *LocationUpdateOne) ClearGroup() *LocationUpdateOne {
luo.mutation.ClearGroup()
@ -613,6 +824,95 @@ func (luo *LocationUpdateOne) sqlSave(ctx context.Context) (_node *Location, err
Column: location.FieldDescription,
})
}
if luo.mutation.ParentCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: location.ParentTable,
Columns: []string{location.ParentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := luo.mutation.ParentIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: location.ParentTable,
Columns: []string{location.ParentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if luo.mutation.ChildrenCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: location.ChildrenTable,
Columns: []string{location.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := luo.mutation.RemovedChildrenIDs(); len(nodes) > 0 && !luo.mutation.ChildrenCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: location.ChildrenTable,
Columns: []string{location.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := luo.mutation.ChildrenIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: location.ChildrenTable,
Columns: []string{location.ChildrenColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: &sqlgraph.FieldSpec{
Type: field.TypeUUID,
Column: location.FieldID,
},
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if luo.mutation.GroupCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,

View file

@ -184,6 +184,7 @@ var (
{Name: "sold_price", Type: field.TypeFloat64, Default: 0},
{Name: "sold_notes", Type: field.TypeString, Nullable: true, Size: 1000},
{Name: "group_items", Type: field.TypeUUID},
{Name: "item_children", Type: field.TypeUUID, Nullable: true},
{Name: "location_items", Type: field.TypeUUID, Nullable: true},
}
// ItemsTable holds the schema information for the "items" table.
@ -199,8 +200,14 @@ var (
OnDelete: schema.Cascade,
},
{
Symbol: "items_locations_items",
Symbol: "items_items_children",
Columns: []*schema.Column{ItemsColumns[23]},
RefColumns: []*schema.Column{ItemsColumns[0]},
OnDelete: schema.SetNull,
},
{
Symbol: "items_locations_items",
Columns: []*schema.Column{ItemsColumns[24]},
RefColumns: []*schema.Column{LocationsColumns[0]},
OnDelete: schema.Cascade,
},
@ -288,6 +295,7 @@ var (
{Name: "name", Type: field.TypeString, Size: 255},
{Name: "description", Type: field.TypeString, Nullable: true, Size: 1000},
{Name: "group_locations", Type: field.TypeUUID},
{Name: "location_children", Type: field.TypeUUID, Nullable: true},
}
// LocationsTable holds the schema information for the "locations" table.
LocationsTable = &schema.Table{
@ -301,6 +309,12 @@ var (
RefColumns: []*schema.Column{GroupsColumns[0]},
OnDelete: schema.Cascade,
},
{
Symbol: "locations_locations_children",
Columns: []*schema.Column{LocationsColumns[6]},
RefColumns: []*schema.Column{LocationsColumns[0]},
OnDelete: schema.SetNull,
},
},
}
// UsersColumns holds the columns for the "users" table.
@ -381,10 +395,12 @@ func init() {
DocumentTokensTable.ForeignKeys[0].RefTable = DocumentsTable
GroupInvitationTokensTable.ForeignKeys[0].RefTable = GroupsTable
ItemsTable.ForeignKeys[0].RefTable = GroupsTable
ItemsTable.ForeignKeys[1].RefTable = LocationsTable
ItemsTable.ForeignKeys[1].RefTable = ItemsTable
ItemsTable.ForeignKeys[2].RefTable = LocationsTable
ItemFieldsTable.ForeignKeys[0].RefTable = ItemsTable
LabelsTable.ForeignKeys[0].RefTable = GroupsTable
LocationsTable.ForeignKeys[0].RefTable = GroupsTable
LocationsTable.ForeignKeys[1].RefTable = LocationsTable
UsersTable.ForeignKeys[0].RefTable = GroupsTable
LabelItemsTable.ForeignKeys[0].RefTable = LabelsTable
LabelItemsTable.ForeignKeys[1].RefTable = ItemsTable

View file

@ -4149,6 +4149,11 @@ type ItemMutation struct {
addsold_price *float64
sold_notes *string
clearedFields map[string]struct{}
parent *uuid.UUID
clearedparent bool
children map[uuid.UUID]struct{}
removedchildren map[uuid.UUID]struct{}
clearedchildren bool
group *uuid.UUID
clearedgroup bool
label map[uuid.UUID]struct{}
@ -5256,6 +5261,99 @@ func (m *ItemMutation) ResetSoldNotes() {
delete(m.clearedFields, item.FieldSoldNotes)
}
// SetParentID sets the "parent" edge to the Item entity by id.
func (m *ItemMutation) SetParentID(id uuid.UUID) {
m.parent = &id
}
// ClearParent clears the "parent" edge to the Item entity.
func (m *ItemMutation) ClearParent() {
m.clearedparent = true
}
// ParentCleared reports if the "parent" edge to the Item entity was cleared.
func (m *ItemMutation) ParentCleared() bool {
return m.clearedparent
}
// ParentID returns the "parent" edge ID in the mutation.
func (m *ItemMutation) ParentID() (id uuid.UUID, exists bool) {
if m.parent != nil {
return *m.parent, true
}
return
}
// ParentIDs returns the "parent" edge IDs in the mutation.
// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
// ParentID instead. It exists only for internal usage by the builders.
func (m *ItemMutation) ParentIDs() (ids []uuid.UUID) {
if id := m.parent; id != nil {
ids = append(ids, *id)
}
return
}
// ResetParent resets all changes to the "parent" edge.
func (m *ItemMutation) ResetParent() {
m.parent = nil
m.clearedparent = false
}
// AddChildIDs adds the "children" edge to the Item entity by ids.
func (m *ItemMutation) AddChildIDs(ids ...uuid.UUID) {
if m.children == nil {
m.children = make(map[uuid.UUID]struct{})
}
for i := range ids {
m.children[ids[i]] = struct{}{}
}
}
// ClearChildren clears the "children" edge to the Item entity.
func (m *ItemMutation) ClearChildren() {
m.clearedchildren = true
}
// ChildrenCleared reports if the "children" edge to the Item entity was cleared.
func (m *ItemMutation) ChildrenCleared() bool {
return m.clearedchildren
}
// RemoveChildIDs removes the "children" edge to the Item entity by IDs.
func (m *ItemMutation) RemoveChildIDs(ids ...uuid.UUID) {
if m.removedchildren == nil {
m.removedchildren = make(map[uuid.UUID]struct{})
}
for i := range ids {
delete(m.children, ids[i])
m.removedchildren[ids[i]] = struct{}{}
}
}
// RemovedChildren returns the removed IDs of the "children" edge to the Item entity.
func (m *ItemMutation) RemovedChildrenIDs() (ids []uuid.UUID) {
for id := range m.removedchildren {
ids = append(ids, id)
}
return
}
// ChildrenIDs returns the "children" edge IDs in the mutation.
func (m *ItemMutation) ChildrenIDs() (ids []uuid.UUID) {
for id := range m.children {
ids = append(ids, id)
}
return
}
// ResetChildren resets all changes to the "children" edge.
func (m *ItemMutation) ResetChildren() {
m.children = nil
m.clearedchildren = false
m.removedchildren = nil
}
// SetGroupID sets the "group" edge to the Group entity by id.
func (m *ItemMutation) SetGroupID(id uuid.UUID) {
m.group = &id
@ -6074,7 +6172,13 @@ func (m *ItemMutation) ResetField(name string) error {
// AddedEdges returns all edge names that were set/added in this mutation.
func (m *ItemMutation) AddedEdges() []string {
edges := make([]string, 0, 5)
edges := make([]string, 0, 7)
if m.parent != nil {
edges = append(edges, item.EdgeParent)
}
if m.children != nil {
edges = append(edges, item.EdgeChildren)
}
if m.group != nil {
edges = append(edges, item.EdgeGroup)
}
@ -6097,6 +6201,16 @@ func (m *ItemMutation) AddedEdges() []string {
// name in this mutation.
func (m *ItemMutation) AddedIDs(name string) []ent.Value {
switch name {
case item.EdgeParent:
if id := m.parent; id != nil {
return []ent.Value{*id}
}
case item.EdgeChildren:
ids := make([]ent.Value, 0, len(m.children))
for id := range m.children {
ids = append(ids, id)
}
return ids
case item.EdgeGroup:
if id := m.group; id != nil {
return []ent.Value{*id}
@ -6129,7 +6243,10 @@ func (m *ItemMutation) AddedIDs(name string) []ent.Value {
// RemovedEdges returns all edge names that were removed in this mutation.
func (m *ItemMutation) RemovedEdges() []string {
edges := make([]string, 0, 5)
edges := make([]string, 0, 7)
if m.removedchildren != nil {
edges = append(edges, item.EdgeChildren)
}
if m.removedlabel != nil {
edges = append(edges, item.EdgeLabel)
}
@ -6146,6 +6263,12 @@ func (m *ItemMutation) RemovedEdges() []string {
// the given name in this mutation.
func (m *ItemMutation) RemovedIDs(name string) []ent.Value {
switch name {
case item.EdgeChildren:
ids := make([]ent.Value, 0, len(m.removedchildren))
for id := range m.removedchildren {
ids = append(ids, id)
}
return ids
case item.EdgeLabel:
ids := make([]ent.Value, 0, len(m.removedlabel))
for id := range m.removedlabel {
@ -6170,7 +6293,13 @@ func (m *ItemMutation) RemovedIDs(name string) []ent.Value {
// ClearedEdges returns all edge names that were cleared in this mutation.
func (m *ItemMutation) ClearedEdges() []string {
edges := make([]string, 0, 5)
edges := make([]string, 0, 7)
if m.clearedparent {
edges = append(edges, item.EdgeParent)
}
if m.clearedchildren {
edges = append(edges, item.EdgeChildren)
}
if m.clearedgroup {
edges = append(edges, item.EdgeGroup)
}
@ -6193,6 +6322,10 @@ func (m *ItemMutation) ClearedEdges() []string {
// was cleared in this mutation.
func (m *ItemMutation) EdgeCleared(name string) bool {
switch name {
case item.EdgeParent:
return m.clearedparent
case item.EdgeChildren:
return m.clearedchildren
case item.EdgeGroup:
return m.clearedgroup
case item.EdgeLabel:
@ -6211,6 +6344,9 @@ func (m *ItemMutation) EdgeCleared(name string) bool {
// if that edge is not defined in the schema.
func (m *ItemMutation) ClearEdge(name string) error {
switch name {
case item.EdgeParent:
m.ClearParent()
return nil
case item.EdgeGroup:
m.ClearGroup()
return nil
@ -6225,6 +6361,12 @@ func (m *ItemMutation) ClearEdge(name string) error {
// It returns an error if the edge is not defined in the schema.
func (m *ItemMutation) ResetEdge(name string) error {
switch name {
case item.EdgeParent:
m.ResetParent()
return nil
case item.EdgeChildren:
m.ResetChildren()
return nil
case item.EdgeGroup:
m.ResetGroup()
return nil
@ -7886,22 +8028,27 @@ func (m *LabelMutation) ResetEdge(name string) error {
// LocationMutation represents an operation that mutates the Location nodes in the graph.
type LocationMutation struct {
config
op Op
typ string
id *uuid.UUID
created_at *time.Time
updated_at *time.Time
name *string
description *string
clearedFields map[string]struct{}
group *uuid.UUID
clearedgroup bool
items map[uuid.UUID]struct{}
removeditems map[uuid.UUID]struct{}
cleareditems bool
done bool
oldValue func(context.Context) (*Location, error)
predicates []predicate.Location
op Op
typ string
id *uuid.UUID
created_at *time.Time
updated_at *time.Time
name *string
description *string
clearedFields map[string]struct{}
parent *uuid.UUID
clearedparent bool
children map[uuid.UUID]struct{}
removedchildren map[uuid.UUID]struct{}
clearedchildren bool
group *uuid.UUID
clearedgroup bool
items map[uuid.UUID]struct{}
removeditems map[uuid.UUID]struct{}
cleareditems bool
done bool
oldValue func(context.Context) (*Location, error)
predicates []predicate.Location
}
var _ ent.Mutation = (*LocationMutation)(nil)
@ -8165,6 +8312,99 @@ func (m *LocationMutation) ResetDescription() {
delete(m.clearedFields, location.FieldDescription)
}
// SetParentID sets the "parent" edge to the Location entity by id.
func (m *LocationMutation) SetParentID(id uuid.UUID) {
m.parent = &id
}
// ClearParent clears the "parent" edge to the Location entity.
func (m *LocationMutation) ClearParent() {
m.clearedparent = true
}
// ParentCleared reports if the "parent" edge to the Location entity was cleared.
func (m *LocationMutation) ParentCleared() bool {
return m.clearedparent
}
// ParentID returns the "parent" edge ID in the mutation.
func (m *LocationMutation) ParentID() (id uuid.UUID, exists bool) {
if m.parent != nil {
return *m.parent, true
}
return
}
// ParentIDs returns the "parent" edge IDs in the mutation.
// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
// ParentID instead. It exists only for internal usage by the builders.
func (m *LocationMutation) ParentIDs() (ids []uuid.UUID) {
if id := m.parent; id != nil {
ids = append(ids, *id)
}
return
}
// ResetParent resets all changes to the "parent" edge.
func (m *LocationMutation) ResetParent() {
m.parent = nil
m.clearedparent = false
}
// AddChildIDs adds the "children" edge to the Location entity by ids.
func (m *LocationMutation) AddChildIDs(ids ...uuid.UUID) {
if m.children == nil {
m.children = make(map[uuid.UUID]struct{})
}
for i := range ids {
m.children[ids[i]] = struct{}{}
}
}
// ClearChildren clears the "children" edge to the Location entity.
func (m *LocationMutation) ClearChildren() {
m.clearedchildren = true
}
// ChildrenCleared reports if the "children" edge to the Location entity was cleared.
func (m *LocationMutation) ChildrenCleared() bool {
return m.clearedchildren
}
// RemoveChildIDs removes the "children" edge to the Location entity by IDs.
func (m *LocationMutation) RemoveChildIDs(ids ...uuid.UUID) {
if m.removedchildren == nil {
m.removedchildren = make(map[uuid.UUID]struct{})
}
for i := range ids {
delete(m.children, ids[i])
m.removedchildren[ids[i]] = struct{}{}
}
}
// RemovedChildren returns the removed IDs of the "children" edge to the Location entity.
func (m *LocationMutation) RemovedChildrenIDs() (ids []uuid.UUID) {
for id := range m.removedchildren {
ids = append(ids, id)
}
return
}
// ChildrenIDs returns the "children" edge IDs in the mutation.
func (m *LocationMutation) ChildrenIDs() (ids []uuid.UUID) {
for id := range m.children {
ids = append(ids, id)
}
return
}
// ResetChildren resets all changes to the "children" edge.
func (m *LocationMutation) ResetChildren() {
m.children = nil
m.clearedchildren = false
m.removedchildren = nil
}
// SetGroupID sets the "group" edge to the Group entity by id.
func (m *LocationMutation) SetGroupID(id uuid.UUID) {
m.group = &id
@ -8436,7 +8676,13 @@ func (m *LocationMutation) ResetField(name string) error {
// AddedEdges returns all edge names that were set/added in this mutation.
func (m *LocationMutation) AddedEdges() []string {
edges := make([]string, 0, 2)
edges := make([]string, 0, 4)
if m.parent != nil {
edges = append(edges, location.EdgeParent)
}
if m.children != nil {
edges = append(edges, location.EdgeChildren)
}
if m.group != nil {
edges = append(edges, location.EdgeGroup)
}
@ -8450,6 +8696,16 @@ func (m *LocationMutation) AddedEdges() []string {
// name in this mutation.
func (m *LocationMutation) AddedIDs(name string) []ent.Value {
switch name {
case location.EdgeParent:
if id := m.parent; id != nil {
return []ent.Value{*id}
}
case location.EdgeChildren:
ids := make([]ent.Value, 0, len(m.children))
for id := range m.children {
ids = append(ids, id)
}
return ids
case location.EdgeGroup:
if id := m.group; id != nil {
return []ent.Value{*id}
@ -8466,7 +8722,10 @@ func (m *LocationMutation) AddedIDs(name string) []ent.Value {
// RemovedEdges returns all edge names that were removed in this mutation.
func (m *LocationMutation) RemovedEdges() []string {
edges := make([]string, 0, 2)
edges := make([]string, 0, 4)
if m.removedchildren != nil {
edges = append(edges, location.EdgeChildren)
}
if m.removeditems != nil {
edges = append(edges, location.EdgeItems)
}
@ -8477,6 +8736,12 @@ func (m *LocationMutation) RemovedEdges() []string {
// the given name in this mutation.
func (m *LocationMutation) RemovedIDs(name string) []ent.Value {
switch name {
case location.EdgeChildren:
ids := make([]ent.Value, 0, len(m.removedchildren))
for id := range m.removedchildren {
ids = append(ids, id)
}
return ids
case location.EdgeItems:
ids := make([]ent.Value, 0, len(m.removeditems))
for id := range m.removeditems {
@ -8489,7 +8754,13 @@ func (m *LocationMutation) RemovedIDs(name string) []ent.Value {
// ClearedEdges returns all edge names that were cleared in this mutation.
func (m *LocationMutation) ClearedEdges() []string {
edges := make([]string, 0, 2)
edges := make([]string, 0, 4)
if m.clearedparent {
edges = append(edges, location.EdgeParent)
}
if m.clearedchildren {
edges = append(edges, location.EdgeChildren)
}
if m.clearedgroup {
edges = append(edges, location.EdgeGroup)
}
@ -8503,6 +8774,10 @@ func (m *LocationMutation) ClearedEdges() []string {
// was cleared in this mutation.
func (m *LocationMutation) EdgeCleared(name string) bool {
switch name {
case location.EdgeParent:
return m.clearedparent
case location.EdgeChildren:
return m.clearedchildren
case location.EdgeGroup:
return m.clearedgroup
case location.EdgeItems:
@ -8515,6 +8790,9 @@ func (m *LocationMutation) EdgeCleared(name string) bool {
// if that edge is not defined in the schema.
func (m *LocationMutation) ClearEdge(name string) error {
switch name {
case location.EdgeParent:
m.ClearParent()
return nil
case location.EdgeGroup:
m.ClearGroup()
return nil
@ -8526,6 +8804,12 @@ func (m *LocationMutation) ClearEdge(name string) error {
// It returns an error if the edge is not defined in the schema.
func (m *LocationMutation) ResetEdge(name string) error {
switch name {
case location.EdgeParent:
m.ResetParent()
return nil
case location.EdgeChildren:
m.ResetChildren()
return nil
case location.EdgeGroup:
m.ResetGroup()
return nil

View file

@ -94,6 +94,9 @@ func (Item) Fields() []ent.Field {
// Edges of the Item.
func (Item) Edges() []ent.Edge {
return []ent.Edge{
edge.To("children", Item.Type).
From("parent").
Unique(),
edge.From("group", Group.Type).
Ref("items").
Required().

View file

@ -27,6 +27,9 @@ func (Location) Fields() []ent.Field {
// Edges of the Location.
func (Location) Edges() []ent.Edge {
return []ent.Edge{
edge.To("children", Location.Type).
From("parent").
Unique(),
edge.From("group", Group.Type).
Ref("locations").
Unique().

View file

@ -61,11 +61,13 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -75,6 +77,8 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=

View file

@ -0,0 +1,28 @@
-- disable the enforcement of foreign-keys constraints
PRAGMA foreign_keys = off;
-- create "new_items" table
CREATE TABLE `new_items` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `import_ref` text NULL, `notes` text NULL, `quantity` integer NOT NULL DEFAULT 1, `insured` bool NOT NULL DEFAULT false, `serial_number` text NULL, `model_number` text NULL, `manufacturer` text NULL, `lifetime_warranty` bool NOT NULL DEFAULT false, `warranty_expires` datetime NULL, `warranty_details` text NULL, `purchase_time` datetime NULL, `purchase_from` text NULL, `purchase_price` real NOT NULL DEFAULT 0, `sold_time` datetime NULL, `sold_to` text NULL, `sold_price` real NOT NULL DEFAULT 0, `sold_notes` text NULL, `group_items` uuid NOT NULL, `item_children` uuid NULL, `location_items` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `items_groups_items` FOREIGN KEY (`group_items`) REFERENCES `groups` (`id`) ON DELETE CASCADE, CONSTRAINT `items_items_children` FOREIGN KEY (`item_children`) REFERENCES `items` (`id`) ON DELETE SET NULL, CONSTRAINT `items_locations_items` FOREIGN KEY (`location_items`) REFERENCES `locations` (`id`) ON DELETE CASCADE);
-- copy rows from old table "items" to new temporary table "new_items"
INSERT INTO `new_items` (`id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `location_items`) SELECT `id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `location_items` FROM `items`;
-- drop "items" table after copying rows
DROP TABLE `items`;
-- rename temporary table "new_items" to "items"
ALTER TABLE `new_items` RENAME TO `items`;
-- create index "item_name" to table: "items"
CREATE INDEX `item_name` ON `items` (`name`);
-- create index "item_manufacturer" to table: "items"
CREATE INDEX `item_manufacturer` ON `items` (`manufacturer`);
-- create index "item_model_number" to table: "items"
CREATE INDEX `item_model_number` ON `items` (`model_number`);
-- create index "item_serial_number" to table: "items"
CREATE INDEX `item_serial_number` ON `items` (`serial_number`);
-- create "new_locations" table
CREATE TABLE `new_locations` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `group_locations` uuid NOT NULL, `location_children` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `locations_groups_locations` FOREIGN KEY (`group_locations`) REFERENCES `groups` (`id`) ON DELETE CASCADE, CONSTRAINT `locations_locations_children` FOREIGN KEY (`location_children`) REFERENCES `locations` (`id`) ON DELETE SET NULL);
-- copy rows from old table "locations" to new temporary table "new_locations"
INSERT INTO `new_locations` (`id`, `created_at`, `updated_at`, `name`, `description`, `group_locations`) SELECT `id`, `created_at`, `updated_at`, `name`, `description`, `group_locations` FROM `locations`;
-- drop "locations" table after copying rows
DROP TABLE `locations`;
-- rename temporary table "new_locations" to "locations"
ALTER TABLE `new_locations` RENAME TO `locations`;
-- enable back the enforcement of foreign-keys constraints
PRAGMA foreign_keys = on;

View file

@ -1,4 +1,5 @@
h1:nN8ZUHScToap+2yJKsb+AnKu8o2DubUoiKc9neQJ93M=
h1:mYTnmyrnBDST/r93NGJM33mIJqhp/U9qR440zI99eqQ=
20220929052825_init.sql h1:ZlCqm1wzjDmofeAcSX3jE4h4VcdTNGpRg2eabztDy9Q=
20221001210956_group_invitations.sql h1:YQKJFtE39wFOcRNbZQ/d+ZlHwrcfcsZlcv/pLEYdpjw=
20221009173029_add_user_roles.sql h1:vWmzAfgEWQeGk0Vn70zfVPCcfEZth3E0JcvyKTjpYyU=
20221020043305_allow_nesting_types.sql h1:4AyJpZ7l7SSJtJAQETYY802FHJ64ufYPJTqvwdiGn3M=

View file

@ -39,15 +39,17 @@ type (
}
ItemCreate struct {
ImportRef string `json:"-"`
Name string `json:"name"`
Description string `json:"description"`
ImportRef string `json:"-"`
ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"`
Name string `json:"name"`
Description string `json:"description"`
// Edges
LocationID uuid.UUID `json:"locationId"`
LabelIDs []uuid.UUID `json:"labelIds"`
}
ItemUpdate struct {
ParentID uuid.UUID `json:"parentId" extensions:"x-nullable,x-omitempty"`
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
@ -95,11 +97,12 @@ type (
UpdatedAt time.Time `json:"updatedAt"`
// Edges
Location LocationSummary `json:"location"`
Labels []LabelSummary `json:"labels"`
Location *LocationSummary `json:"location,omitempty" extensions:"x-nullable,x-omitempty"`
Labels []LabelSummary `json:"labels"`
}
ItemOut struct {
Parent *ItemSummary `json:"parent,omitempty" extensions:"x-nullable,x-omitempty"`
ItemSummary
SerialNumber string `json:"serialNumber"`
@ -126,8 +129,8 @@ type (
Notes string `json:"notes"`
Attachments []ItemAttachment `json:"attachments"`
// Future
Fields []ItemField `json:"fields"`
Fields []ItemField `json:"fields"`
Children []ItemSummary `json:"children"`
}
)
@ -136,12 +139,13 @@ var (
)
func mapItemSummary(item *ent.Item) ItemSummary {
var location LocationSummary
var location *LocationSummary
if item.Edges.Location != nil {
location = mapLocationSummary(item.Edges.Location)
loc := mapLocationSummary(item.Edges.Location)
location = &loc
}
var labels []LabelSummary
labels := make([]LabelSummary, len(item.Edges.Label))
if item.Edges.Label != nil {
labels = mapEach(item.Edges.Label, mapLabelSummary)
}
@ -194,7 +198,19 @@ func mapItemOut(item *ent.Item) ItemOut {
fields = mapFields(item.Edges.Fields)
}
var children []ItemSummary
if item.Edges.Children != nil {
children = mapEach(item.Edges.Children, mapItemSummary)
}
var parent *ItemSummary
if item.Edges.Parent != nil {
v := mapItemSummary(item.Edges.Parent)
parent = &v
}
return ItemOut{
Parent: parent,
ItemSummary: mapItemSummary(item),
LifetimeWarranty: item.LifetimeWarranty,
WarrantyExpires: item.WarrantyExpires,
@ -220,6 +236,7 @@ func mapItemOut(item *ent.Item) ItemOut {
Notes: item.Notes,
Attachments: attachments,
Fields: fields,
Children: children,
}
}
@ -231,6 +248,8 @@ func (e *ItemsRepository) getOne(ctx context.Context, where ...predicate.Item) (
WithLabel().
WithLocation().
WithGroup().
WithChildren().
WithParent().
WithAttachments(func(aq *ent.AttachmentQuery) {
aq.WithDocument()
}).
@ -398,6 +417,12 @@ func (e *ItemsRepository) UpdateByGroup(ctx context.Context, gid uuid.UUID, data
q.RemoveLabelIDs(set.Slice()...)
}
if data.ParentID != uuid.Nil {
q.SetParentID(data.ParentID)
} else {
q.ClearParent()
}
err = q.Exec(ctx)
if err != nil {
return ItemOut{}, err

View file

@ -41,6 +41,42 @@ func useItems(t *testing.T, len int) []ItemOut {
return items
}
func TestItemsRepository_RecursiveRelationships(t *testing.T) {
parent := useItems(t, 1)[0]
children := useItems(t, 3)
for _, child := range children {
update := ItemUpdate{
ID: child.ID,
ParentID: parent.ID,
Name: "note-important",
Description: "This is a note",
LocationID: child.Location.ID,
}
// Append Parent ID
_, err := tRepos.Items.UpdateByGroup(context.Background(), tGroup.ID, update)
assert.NoError(t, err)
// Check Parent ID
updated, err := tRepos.Items.GetOne(context.Background(), child.ID)
assert.NoError(t, err)
assert.Equal(t, parent.ID, updated.Parent.ID)
// Remove Parent ID
update.ParentID = uuid.Nil
_, err = tRepos.Items.UpdateByGroup(context.Background(), tGroup.ID, update)
assert.NoError(t, err)
// Check Parent ID
updated, err = tRepos.Items.GetOne(context.Background(), child.ID)
assert.NoError(t, err)
assert.Nil(t, updated.Parent)
}
}
func TestItemsRepository_GetOne(t *testing.T) {
entity := useItems(t, 3)

View file

@ -22,6 +22,7 @@ type (
}
LocationUpdate struct {
ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"`
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
@ -41,8 +42,10 @@ type (
}
LocationOut struct {
Parent *LocationSummary `json:"parent,omitempty"`
LocationSummary
Items []ItemSummary `json:"items"`
Items []ItemSummary `json:"items"`
Children []LocationSummary `json:"children"`
}
)
@ -61,7 +64,20 @@ var (
)
func mapLocationOut(location *ent.Location) LocationOut {
var parent *LocationSummary
if location.Edges.Parent != nil {
p := mapLocationSummary(location.Edges.Parent)
parent = &p
}
children := make([]LocationSummary, 0, len(location.Edges.Children))
for _, c := range location.Edges.Children {
children = append(children, mapLocationSummary(c))
}
return LocationOut{
Parent: parent,
Children: children,
LocationSummary: LocationSummary{
ID: location.ID,
Name: location.Name,
@ -125,6 +141,8 @@ func (r *LocationRepository) getOne(ctx context.Context, where ...predicate.Loca
WithItems(func(iq *ent.ItemQuery) {
iq.WithLabel()
}).
WithParent().
WithChildren().
Only(ctx))
}
@ -152,10 +170,17 @@ func (r *LocationRepository) Create(ctx context.Context, gid uuid.UUID, data Loc
}
func (r *LocationRepository) Update(ctx context.Context, data LocationUpdate) (LocationOut, error) {
_, err := r.db.Location.UpdateOneID(data.ID).
q := r.db.Location.UpdateOneID(data.ID).
SetName(data.Name).
SetDescription(data.Description).
Save(ctx)
SetDescription(data.Description)
if data.ParentID != uuid.Nil {
q.SetParentID(data.ParentID)
} else {
q.ClearParent()
}
_, err := q.Save(ctx)
if err != nil {
return LocationOut{}, err

View file

@ -3,7 +3,6 @@
v-if="to"
v-bind="attributes"
ref="submitBtn"
:to="to"
class="btn"
:class="{
loading: loading,
@ -64,7 +63,7 @@
const attributes = computed(() => {
if (props.to) {
return {
href: props.to,
to: props.to,
};
}
return {

View file

@ -0,0 +1,149 @@
<template>
<div ref="menu" class="form-control w-full">
<label class="label">
<span class="label-text">{{ label }}</span>
</label>
<div class="dropdown dropdown-top sm:dropdown-end">
<div class="relative">
<input
v-model="isearch"
tabindex="0"
class="input w-full items-center flex flex-wrap border border-gray-400 rounded-lg"
@keyup.enter="selectFirst"
/>
<button
v-if="!!modelValue && Object.keys(modelValue).length !== 0"
style="transform: translateY(-50%)"
class="top-1/2 absolute right-2 btn btn-xs btn-circle no-animation"
@click="clear"
>
x
</button>
</div>
<ul
tabindex="0"
style="display: inline"
class="dropdown-content mb-1 menu shadow border border-gray-400 rounded bg-base-100 w-full z-[9999] max-h-60 overflow-y-scroll"
>
<li v-for="(obj, idx) in filtered" :key="idx">
<button type="button" @click="select(obj)">
{{ usingObjects ? obj[itemText] : obj }}
</button>
</li>
<li class="hidden first:flex">
<button disabled>
{{ noResultsText }}
</button>
</li>
</ul>
</div>
</div>
</template>
<script lang="ts" setup>
type ItemsObject = {
text?: string;
value?: string;
[key: string]: unknown;
};
interface Props {
label: string;
modelValue: string | ItemsObject;
items: ItemsObject[] | string[];
itemText?: keyof ItemsObject;
itemValue?: keyof ItemsObject;
search?: string;
noResultsText?: string;
}
const emit = defineEmits(["update:modelValue", "update:search"]);
const props = withDefaults(defineProps<Props>(), {
label: "",
modelValue: "",
items: () => [],
itemText: "text",
itemValue: "value",
search: "",
noResultsText: "No Results Found",
});
function clear() {
select(value.value);
}
const isearch = ref("");
watch(isearch, () => {
internalSearch.value = isearch.value;
});
const internalSearch = useVModel(props, "search", emit);
const value = useVModel(props, "modelValue", emit);
const usingObjects = computed(() => {
return props.items.length > 0 && typeof props.items[0] === "object";
});
/**
* isStrings is a type guard function to check if the items are an array of string
*/
function isStrings(_arr: string[] | ItemsObject[]): _arr is string[] {
return !usingObjects.value;
}
function selectFirst() {
if (filtered.value.length > 0) {
select(filtered.value[0]);
}
}
watch(
value,
() => {
if (value.value) {
if (typeof value.value === "string") {
isearch.value = value.value;
} else {
isearch.value = value.value[props.itemText] as string;
}
}
},
{
immediate: true,
}
);
function select(obj: string | ItemsObject) {
if (isStrings(props.items)) {
if (obj === value.value) {
value.value = "";
return;
}
value.value = obj;
} else {
if (obj === value.value) {
value.value = {};
return;
}
value.value = obj;
}
}
const filtered = computed(() => {
if (!isearch.value || isearch.value === "") {
return props.items;
}
if (isStrings(props.items)) {
return props.items.filter(item => item.toLowerCase().includes(isearch.value.toLowerCase()));
} else {
return props.items.filter(item => {
if (props.itemText && props.itemText in item) {
return (item[props.itemText] as string).toLowerCase().includes(isearch.value.toLowerCase());
}
return false;
});
}
});
</script>

View file

@ -45,6 +45,10 @@
type: String,
default: "",
},
compareKey: {
type: String,
default: null,
},
});
const selectedIdx = ref(-1);
@ -52,36 +56,34 @@
const internalSelected = useVModel(props, "modelValue", emit);
const internalValue = useVModel(props, "value", emit);
watch(selectedIdx, newVal => {
internalSelected.value = props.items[newVal];
});
watch(selectedIdx, newVal => {
if (props.valueKey) {
internalValue.value = props.items[newVal][props.valueKey];
}
});
watch(
internalSelected,
() => {
const idx = props.items.findIndex(item => compare(item, internalSelected.value));
selectedIdx.value = idx;
selectedIdx,
newVal => {
if (newVal === -1) {
return;
}
if (props.value) {
internalValue.value = props.items[newVal][props.valueKey];
}
internalSelected.value = props.items[newVal];
},
{
immediate: true,
}
{ immediate: true }
);
watch(
internalValue,
[internalSelected, () => props.value],
() => {
const idx = props.items.findIndex(item => compare(item[props.valueKey], internalValue.value));
if (props.valueKey) {
const idx = props.items.findIndex(item => compare(item, internalValue.value));
selectedIdx.value = idx;
return;
}
const idx = props.items.findIndex(item => compare(item, internalSelected.value));
selectedIdx.value = idx;
},
{
immediate: true,
}
{ immediate: true }
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -90,8 +92,13 @@
return true;
}
if (!a || !b) {
return false;
if (props.valueKey) {
return a[props.valueKey] === b;
}
// Try compare key
if (props.compareKey && a && b) {
return a[props.compareKey] === b[props.compareKey];
}
return JSON.stringify(a) === JSON.stringify(b);

View file

@ -17,20 +17,18 @@
<Icon name="heroicons-map-pin" class="swap-off" />
</label>
{{ location.name }}
<span v-if="location.itemCount" class="badge badge-secondary badge-lg ml-auto text-secondary-content">
{{ location.itemCount }}</span
>
<span v-if="hasCount" class="badge badge-secondary badge-lg ml-auto text-secondary-content"> {{ count }}</span>
</h2>
</div>
</NuxtLink>
</template>
<script lang="ts" setup>
import { LocationOutCount } from "~~/lib/api/types/data-contracts";
import { LocationOut, LocationOutCount, LocationSummary } from "~~/lib/api/types/data-contracts";
defineProps({
const props = defineProps({
location: {
type: Object as () => LocationOutCount,
type: Object as () => LocationOutCount | LocationOut | LocationSummary,
required: true,
},
dense: {
@ -39,6 +37,16 @@
},
});
const hasCount = computed(() => {
return !!(props.location as LocationOutCount).itemCount;
});
const count = computed(() => {
if (hasCount.value) {
return (props.location as LocationOutCount).itemCount;
}
});
const card = ref(null);
const isHover = useElementHover(card);
const { focused } = useFocus(card);

View file

@ -0,0 +1,36 @@
import { ItemSummary, LabelSummary, LocationSummary } from "~~/lib/api/types/data-contracts";
import { UserClient } from "~~/lib/api/user";
type SearchOptions = {
immediate?: boolean;
};
export function useItemSearch(client: UserClient, opts?: SearchOptions) {
const query = ref("");
const locations = ref<LocationSummary[]>([]);
const labels = ref<LabelSummary[]>([]);
const results = ref<ItemSummary[]>([]);
watchDebounced(query, search, { debounce: 250, maxWait: 1000 });
async function search() {
const locIds = locations.value.map(l => l.id);
const labelIds = labels.value.map(l => l.id);
const { data, error } = await client.items.getAll({ q: query.value, locations: locIds, labels: labelIds });
if (error) {
return;
}
results.value = data.items;
}
if (opts?.immediate) {
search();
}
return {
query,
results,
locations,
labels,
};
}

View file

@ -1,9 +1,7 @@
import { BaseAPI, route } from "../base";
import { LocationOutCount, LocationCreate, LocationOut } from "../types/data-contracts";
import { LocationOutCount, LocationCreate, LocationOut, LocationUpdate } from "../types/data-contracts";
import { Results } from "../types/non-generated";
export type LocationUpdate = LocationCreate;
export class LocationsApi extends BaseAPI {
getAll() {
return this.http.get<Results<LocationOutCount>>({ url: route("/locations") });

View file

@ -49,6 +49,7 @@ export interface ItemCreate {
/** Edges */
locationId: string;
name: string;
parentId: string | null;
}
export interface ItemField {
@ -63,10 +64,9 @@ export interface ItemField {
export interface ItemOut {
attachments: ItemAttachment[];
children: ItemSummary[];
createdAt: Date;
description: string;
/** Future */
fields: ItemField[];
id: string;
insured: boolean;
@ -76,13 +76,14 @@ export interface ItemOut {
lifetimeWarranty: boolean;
/** Edges */
location: LocationSummary;
location: LocationSummary | null;
manufacturer: string;
modelNumber: string;
name: string;
/** Extras */
notes: string;
parent: ItemSummary | null;
purchaseFrom: string;
/** @example 0 */
@ -113,7 +114,7 @@ export interface ItemSummary {
labels: LabelSummary[];
/** Edges */
location: LocationSummary;
location: LocationSummary | null;
name: string;
quantity: number;
updatedAt: Date;
@ -137,6 +138,7 @@ export interface ItemUpdate {
/** Extras */
notes: string;
parentId: string | null;
purchaseFrom: string;
/** @example 0 */
@ -189,11 +191,13 @@ export interface LocationCreate {
}
export interface LocationOut {
children: LocationSummary[];
createdAt: Date;
description: string;
id: string;
items: ItemSummary[];
name: string;
parent: LocationSummary;
updatedAt: Date;
}
@ -214,6 +218,13 @@ export interface LocationSummary {
updatedAt: Date;
}
export interface LocationUpdate {
description: string;
id: string;
name: string;
parentId: string | null;
}
export interface PaginationResultRepoItemSummary {
items: ItemSummary[];
page: number;

View file

@ -4,6 +4,7 @@
import { useLabelStore } from "~~/stores/labels";
import { useLocationStore } from "~~/stores/locations";
import { capitalize } from "~~/lib/strings";
import Autocomplete from "~~/components/Form/Autocomplete.vue";
definePageMeta({
middleware: ["auth"],
@ -37,8 +38,13 @@
}
}
if (data.parent) {
parent.value = data.parent;
}
return data;
});
onMounted(() => {
refresh();
});
@ -48,6 +54,7 @@
...item.value,
locationId: item.value.location?.id,
labelIds: item.value.labels.map(l => l.id),
parentId: parent.value ? parent.value.id : null,
};
const { error } = await api.items.update(itemId.value, payload);
@ -256,7 +263,6 @@
async function updateAttachment() {
editState.loading = true;
console.log(editState.type);
const { error, data } = await api.items.updateAttachment(itemId.value, editState.id, {
title: editState.title,
type: editState.type,
@ -306,6 +312,9 @@
timeValue: null,
});
}
const { query, results } = useItemSearch(api, { immediate: false });
const parent = ref();
</script>
<template>
@ -314,8 +323,8 @@
<template #title> Attachment Edit </template>
<FormTextField v-model="editState.title" label="Attachment Title" />
{{ editState.type }}
<FormSelect
v-model="editState.obj"
v-model:value="editState.type"
label="Attachment Type"
value-key="value"
@ -354,8 +363,24 @@
</template>
</BaseSectionHeader>
<div class="px-5 mb-6 grid md:grid-cols-2 gap-4">
<FormSelect v-if="item" v-model="item.location" label="Location" :items="locations ?? []" />
<FormSelect
v-if="item"
v-model="item.location"
label="Location"
:items="locations ?? []"
compare-key="id"
/>
<FormMultiselect v-model="item.labels" label="Labels" :items="labels ?? []" />
<Autocomplete
v-if="!preferences.editorSimpleView"
v-model="parent"
v-model:search="query"
:items="results"
item-text="name"
label="Parent Item"
no-results-text="Type to search..."
/>
</div>
<div class="border-t border-gray-300 sm:p-0">

View file

@ -76,6 +76,10 @@
name: "Description",
text: item.value?.description,
},
{
name: "Quantity",
text: item.value?.quantity,
},
{
name: "Serial Number",
text: item.value?.serialNumber,
@ -287,12 +291,23 @@
<span class="text-base-content">
{{ item ? item.name : "" }}
</span>
<div v-if="item.parent" class="text-sm breadcrumbs pb-0">
<ul class="text-base-content/70">
<li>
<NuxtLink :to="`/item/${item.parent.id}`"> {{ item.parent.name }}</NuxtLink>
</li>
<li>{{ item.name }}</li>
</ul>
</div>
<template #description>
<p class="text-sm text-base-content font-bold pb-0 mb-0">
{{ item.location.name }} - Quantity {{ item.quantity }}
</p>
<div v-if="item.labels && item.labels.length > 0" class="flex flex-wrap gap-3 mt-3">
<LabelChip v-for="label in item.labels" :key="label.id" class="badge-primary" :label="label" />
<div class="flex flex-wrap gap-2 mt-3">
<NuxtLink ref="badge" class="badge p-3" :to="`/location/${item.location.id}`">
<Icon name="heroicons-map-pin" class="mr-2 swap-on"></Icon>
{{ item.location.name }}
</NuxtLink>
<template v-if="item.labels && item.labels.length > 0">
<LabelChip v-for="label in item.labels" :key="label.id" class="badge-primary" :label="label" />
</template>
</div>
</template>
</BaseSectionHeader>
@ -378,5 +393,12 @@
</BaseCard>
</div>
</section>
<section class="my-6 px-3">
<BaseSectionHeader v-if="item && item.children && item.children.length > 0"> Child Items </BaseSectionHeader>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<ItemCard v-for="child in item.children" :key="child.id" :item="child" />
</div>
</section>
</BaseContainer>
</template>

View file

@ -1,5 +1,7 @@
<script setup lang="ts">
import { Detail, CustomDetail } from "~~/components/global/DetailsSection/types";
import { LocationSummary, LocationUpdate } from "~~/lib/api/types/data-contracts";
import { useLocationStore } from "~~/stores/locations";
definePageMeta({
middleware: ["auth"],
@ -20,6 +22,11 @@
navigateTo("/home");
return;
}
if (data.parent) {
parent.value = locations.value.find(l => l.id === data.parent.id);
}
return data;
});
@ -62,7 +69,7 @@
async function confirmDelete() {
const { isCanceled } = await confirm.open(
"Are you sure you want to delete this location? This action cannot be undone."
"Are you sure you want to delete this location and all of its items? This action cannot be undone."
);
if (isCanceled) {
return;
@ -80,9 +87,11 @@
const updateModal = ref(false);
const updating = ref(false);
const updateData = reactive({
const updateData = reactive<LocationUpdate>({
id: locationId.value,
name: "",
description: "",
parentId: null,
});
function openUpdate() {
@ -93,6 +102,7 @@
async function update() {
updating.value = true;
updateData.parentId = parent.value?.id || null;
const { error, data } = await api.locations.update(locationId.value, updateData);
if (error) {
@ -105,6 +115,12 @@
updateModal.value = false;
updating.value = false;
}
const locationStore = useLocationStore();
const locations = computed(() => locationStore.locations);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const parent = ref<LocationSummary | any>({});
</script>
<template>
@ -114,6 +130,7 @@
<form v-if="location" @submit.prevent="update">
<FormTextField v-model="updateData.name" :autofocus="true" label="Location Name" />
<FormTextArea v-model="updateData.description" label="Location Description" />
<FormAutocomplete v-model="parent" :items="locations" item-text="name" item-value="id" label="Parent" />
<div class="modal-action">
<BaseButton type="submit" :loading="updating"> Update </BaseButton>
</div>
@ -127,6 +144,14 @@
<span class="text-base-content">
{{ location ? location.name : "" }}
</span>
<div v-if="location && location.parent" class="text-sm breadcrumbs pb-0">
<ul class="text-base-content/70">
<li>
<NuxtLink :to="`/location/${location.parent.id}`"> {{ location.parent.name }}</NuxtLink>
</li>
<li>{{ location.name }}</li>
</ul>
</div>
</BaseSectionHeader>
</template>
@ -152,11 +177,18 @@
<DetailsSection :details="details" />
</BaseCard>
<section v-if="location">
<section v-if="location && location.items.length > 0">
<BaseSectionHeader class="mb-5"> Items </BaseSectionHeader>
<div class="grid gap-2 grid-cols-1 sm:grid-cols-2">
<ItemCard v-for="item in location.items" :key="item.id" :item="item" />
</div>
</section>
<section v-if="location && location.children.length > 0">
<BaseSectionHeader class="mb-5"> Child Locations </BaseSectionHeader>
<div class="grid gap-2 grid-cols-1 sm:grid-cols-3">
<LocationCard v-for="item in location.children" :key="item.id" :location="item" />
</div>
</section>
</BaseContainer>
</template>