Compare commits

...

23 Commits

Author SHA1 Message Date
Hayden
44f13f751a docs: update label generator docs 2023-02-13 10:50:49 -09:00
Hayden
986d2c586e refactor: editor page (#276) 2023-02-13 10:43:09 -09:00
Hayden
9361997a42 feat(reporting): bill of materials (#275)
* new reporting service

* API route

* code gen

* get tsv export from tools page

* fix naming
2023-02-13 10:00:29 -09:00
Hayden
2e96d8c4c2 fix favicon error 2023-02-12 15:14:11 -09:00
Hayden
ff75daf6b3 feat: mvp for label generation/printing (#274)
* initial label generator for QR codes

* use dynamic URL parameter
2023-02-12 15:09:31 -09:00
renovate[bot]
c0953bbd26 fix(deps): update module github.com/go-playground/validator/v10 to v10.11.2 (#253)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-10 19:41:39 -09:00
renovate[bot]
1f7e917c70 fix(deps): update module golang.org/x/crypto to v0.6.0 (#267)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-10 19:41:29 -09:00
Hayden
6ff2d64996 feat: init tools page (#271) 2023-02-10 19:38:50 -09:00
Hayden
ab22ea6a25 feat: rebuild search UI w/ new filters (#269) 2023-02-09 17:47:41 -09:00
Hayden
ce2fc7712a fix: add custom action for fixing broken date/times (#268) 2023-02-08 17:59:04 -09:00
Hayden
bd933af874 feat: implement selectable view + sortable table (#264) 2023-02-05 14:00:33 -09:00
Hayden
f36f17b57d feat: toggle view of password field (#263) 2023-02-05 12:56:47 -09:00
Hayden
504569bed0 fix: prevents re-creating locations and labels when someone joins group (#262)
* closes #258

* remove debug statement
2023-02-05 12:25:30 -09:00
Hayden
bd06fdafaf feat: enhanced search functions (#260)
* make login case insensitive

* expand query to support by Field and By AID search

* type generation

* new API callers

* rework search to support field queries

* improve unnecessary data fetches

* clear stores on logout

* change verbage

* add labels
2023-02-05 12:12:54 -09:00
Hayden
7b28973c60 fix: tree fixes (#252)
* use case insensitive sort

* support new location selector in create item

* fix incorrect date-time parsing logic
2023-01-29 13:20:18 -09:00
Hayden
cbac17c059 feat: use native date picker + align date formats (#251)
* use native date picker

* use YYYY-MM-DD for date formats
2023-01-28 13:32:39 -09:00
Hayden
6ed1f3695a chore: upgrade deps + code-gen (#249) 2023-01-28 12:03:51 -09:00
Hayden
3d295b5132 feat: locations tree viewer (#248)
* location tree API

* test fixes

* initial tree location elements

* locations tree page

* update meta-data

* code-gen

* store item display preferences

* introduce basic table/card view elements

* codegen

* set parent location during location creation

* add item support for tree query

* refactor tree view

* wip: location selector improvements

* type gen

* rename items -> search

* remove various log statements

* fix markdown rendering for description

* update location selectors

* fix tests

* fix currency tests

* formatting
2023-01-28 11:53:00 -09:00
renovate[bot]
4d220cdd9c chore(deps): update dependency vitest to ^0.28.0 (#244)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-26 10:05:09 -09:00
Serios
ad20e4e39b Adding new currency (#243)
Adding Bulgarian lev to list of currencies
2023-01-26 08:59:07 -09:00
renovate[bot]
3e2f6a96bf chore(deps): update dependency nuxt to v3.1.1 (#245)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-26 08:58:21 -09:00
renovate[bot]
2ece97c42a fix(deps): update module github.com/swaggo/swag to v1.8.10 (#246)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-26 08:57:54 -09:00
renovate[bot]
a8ee4d421b fix(deps): update module github.com/rs/zerolog to v1.29.0 (#247)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-26 08:57:45 -09:00
119 changed files with 5333 additions and 1937 deletions

View File

@@ -9,15 +9,15 @@ import (
"github.com/rs/zerolog/log"
)
type EnsureAssetIDResult struct {
type ActionAmountResult struct {
Completed int `json:"completed"`
}
// HandleGroupInvitationsCreate godoc
// @Summary Get the current user
// @Summary Ensures all items in the database have an asset id
// @Tags Group
// @Produce json
// @Success 200 {object} EnsureAssetIDResult
// @Success 200 {object} ActionAmountResult
// @Router /v1/actions/ensure-asset-ids [Post]
// @Security Bearer
func (ctrl *V1Controller) HandleEnsureAssetID() server.HandlerFunc {
@@ -30,6 +30,27 @@ func (ctrl *V1Controller) HandleEnsureAssetID() server.HandlerFunc {
return validate.NewRequestError(err, http.StatusInternalServerError)
}
return server.Respond(w, http.StatusOK, EnsureAssetIDResult{Completed: totalCompleted})
return server.Respond(w, http.StatusOK, ActionAmountResult{Completed: totalCompleted})
}
}
// HandleItemDateZeroOut godoc
// @Summary Resets all item date fields to the beginning of the day
// @Tags Group
// @Produce json
// @Success 200 {object} ActionAmountResult
// @Router /v1/actions/zero-item-time-fields [Post]
// @Security Bearer
func (ctrl *V1Controller) HandleItemDateZeroOut() server.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
ctx := services.NewContext(r.Context())
totalCompleted, err := ctrl.repo.Items.ZeroOutTimeFields(ctx, ctx.GID)
if err != nil {
log.Err(err).Msg("failed to ensure asset id")
return validate.NewRequestError(err, http.StatusInternalServerError)
}
return server.Respond(w, http.StatusOK, ActionAmountResult{Completed: totalCompleted})
}
}

View File

@@ -3,6 +3,7 @@ package v1
import (
"errors"
"net/http"
"strings"
"time"
"github.com/hay-kot/homebox/backend/internal/core/services"
@@ -70,7 +71,7 @@ func (ctrl *V1Controller) HandleAuthLogin() server.HandlerFunc {
)
}
newToken, err := ctrl.svc.User.Login(r.Context(), loginForm.Username, loginForm.Password)
newToken, err := ctrl.svc.User.Login(r.Context(), strings.ToLower(loginForm.Username), loginForm.Password)
if err != nil {
return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError)

View File

@@ -4,6 +4,7 @@ import (
"database/sql"
"errors"
"net/http"
"strings"
"github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/data/repo"
@@ -29,18 +30,48 @@ func (ctrl *V1Controller) HandleItemsGetAll() server.HandlerFunc {
extractQuery := func(r *http.Request) repo.ItemQuery {
params := r.URL.Query()
return repo.ItemQuery{
filterFieldItems := func(raw []string) []repo.FieldQuery {
var items []repo.FieldQuery
for _, v := range raw {
parts := strings.SplitN(v, "=", 2)
if len(parts) == 2 {
items = append(items, repo.FieldQuery{
Name: parts[0],
Value: parts[1],
})
}
}
return items
}
v := repo.ItemQuery{
Page: queryIntOrNegativeOne(params.Get("page")),
PageSize: queryIntOrNegativeOne(params.Get("pageSize")),
Search: params.Get("q"),
LocationIDs: queryUUIDList(params, "locations"),
LabelIDs: queryUUIDList(params, "labels"),
IncludeArchived: queryBool(params.Get("includeArchived")),
Fields: filterFieldItems(params["fields"]),
}
if strings.HasPrefix(v.Search, "#") {
aidStr := strings.TrimPrefix(v.Search, "#")
aid, ok := repo.ParseAssetID(aidStr)
if ok {
v.Search = ""
v.AssetID = aid
}
}
return v
}
return func(w http.ResponseWriter, r *http.Request) error {
ctx := services.NewContext(r.Context())
items, err := ctrl.repo.Items.QueryByGroup(ctx, ctx.GID, extractQuery(r))
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
@@ -161,6 +192,48 @@ func (ctrl *V1Controller) handleItemsGeneral() server.HandlerFunc {
}
}
// HandleGetAllCustomFieldNames godocs
// @Summary imports items into the database
// @Tags Items
// @Produce json
// @Success 200
// @Router /v1/items/fields [GET]
// @Success 200 {object} []string
// @Security Bearer
func (ctrl *V1Controller) HandleGetAllCustomFieldNames() server.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
ctx := services.NewContext(r.Context())
v, err := ctrl.repo.Items.GetAllCustomFieldNames(r.Context(), ctx.GID)
if err != nil {
return err
}
return server.Respond(w, http.StatusOK, v)
}
}
// HandleGetAllCustomFieldValues godocs
// @Summary imports items into the database
// @Tags Items
// @Produce json
// @Success 200
// @Router /v1/items/fields/values [GET]
// @Success 200 {object} []string
// @Security Bearer
func (ctrl *V1Controller) HandleGetAllCustomFieldValues() server.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
ctx := services.NewContext(r.Context())
v, err := ctrl.repo.Items.GetAllCustomFieldValues(r.Context(), ctx.GID, r.URL.Query().Get("field"))
if err != nil {
return err
}
return server.Respond(w, http.StatusOK, v)
}
}
// HandleItemsImport godocs
// @Summary imports items into the database
// @Tags Items

View File

@@ -11,6 +11,39 @@ import (
"github.com/rs/zerolog/log"
)
// HandleLocationTreeQuery godoc
// @Summary Get All Locations
// @Tags Locations
// @Produce json
// @Param withItems query bool false "include items in response tree"
// @Success 200 {object} server.Results{items=[]repo.TreeItem}
// @Router /v1/locations/tree [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleLocationTreeQuery() server.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
user := services.UseUserCtx(r.Context())
q := r.URL.Query()
withItems := queryBool(q.Get("withItems"))
locTree, err := ctrl.repo.Locations.Tree(
r.Context(),
user.GroupID,
repo.TreeQuery{
WithItems: withItems,
},
)
if err != nil {
log.Err(err).Msg("failed to get locations tree")
return validate.NewRequestError(err, http.StatusInternalServerError)
}
return server.Respond(w, http.StatusOK, server.Results{Items: locTree})
}
}
// HandleLocationGetAll godoc
// @Summary Get All Locations
// @Tags Locations

View File

@@ -0,0 +1,32 @@
package v1
import (
"net/http"
"github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/pkgs/server"
)
// HandleBillOfMaterialsExport godoc
//
// @Summary Generates a Bill of Materials CSV
// @Tags Reporting
// @Produce json
// @Success 200 {string} string "text/csv"
// @Router /v1/reporting/bill-of-materials [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleBillOfMaterialsExport() server.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
actor := services.UseUserCtx(r.Context())
csv, err := ctrl.svc.Reporting.BillOfMaterialsTSV(r.Context(), actor.GroupID)
if err != nil {
return err
}
w.Header().Set("Content-Type", "text/csv")
w.Header().Set("Content-Disposition", "attachment; filename=bom.csv")
_, err = w.Write(csv)
return err
}
}

View File

@@ -88,9 +88,11 @@ func (a *app) mountRoutes(repos *repo.AllRepos) {
a.server.Put(v1Base("/groups"), v1Ctrl.HandleGroupUpdate(), userMW...)
a.server.Post(v1Base("/actions/ensure-asset-ids"), v1Ctrl.HandleEnsureAssetID(), userMW...)
a.server.Post(v1Base("/actions/zero-item-time-fields"), v1Ctrl.HandleItemDateZeroOut(), userMW...)
a.server.Get(v1Base("/locations"), v1Ctrl.HandleLocationGetAll(), userMW...)
a.server.Post(v1Base("/locations"), v1Ctrl.HandleLocationCreate(), userMW...)
a.server.Get(v1Base("/locations/tree"), v1Ctrl.HandleLocationTreeQuery(), userMW...)
a.server.Get(v1Base("/locations/{id}"), v1Ctrl.HandleLocationGet(), userMW...)
a.server.Put(v1Base("/locations/{id}"), v1Ctrl.HandleLocationUpdate(), userMW...)
a.server.Delete(v1Base("/locations/{id}"), v1Ctrl.HandleLocationDelete(), userMW...)
@@ -102,8 +104,11 @@ func (a *app) mountRoutes(repos *repo.AllRepos) {
a.server.Delete(v1Base("/labels/{id}"), v1Ctrl.HandleLabelDelete(), userMW...)
a.server.Get(v1Base("/items"), v1Ctrl.HandleItemsGetAll(), userMW...)
a.server.Post(v1Base("/items/import"), v1Ctrl.HandleItemsImport(), userMW...)
a.server.Post(v1Base("/items"), v1Ctrl.HandleItemsCreate(), userMW...)
a.server.Post(v1Base("/items/import"), v1Ctrl.HandleItemsImport(), userMW...)
a.server.Get(v1Base("/items/fields"), v1Ctrl.HandleGetAllCustomFieldNames(), userMW...)
a.server.Get(v1Base("/items/fields/values"), v1Ctrl.HandleGetAllCustomFieldValues(), userMW...)
a.server.Get(v1Base("/items/{id}"), v1Ctrl.HandleItemGet(), userMW...)
a.server.Put(v1Base("/items/{id}"), v1Ctrl.HandleItemUpdate(), userMW...)
a.server.Delete(v1Base("/items/{id}"), v1Ctrl.HandleItemDelete(), userMW...)
@@ -131,6 +136,9 @@ func (a *app) mountRoutes(repos *repo.AllRepos) {
a.mwAuthToken, a.mwRoles(RoleModeOr, authroles.RoleUser.String(), authroles.RoleAttachments.String()),
)
// Reporting Services
a.server.Get(v1Base("/reporting/bill-of-materials"), v1Ctrl.HandleBillOfMaterialsExport(), userMW...)
a.server.NotFound(notFoundHandler())
}

View File

@@ -34,12 +34,36 @@ const docTemplate = `{
"tags": [
"Group"
],
"summary": "Get the current user",
"summary": "Ensures all items in the database have an asset id",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.EnsureAssetIDResult"
"$ref": "#/definitions/v1.ActionAmountResult"
}
}
}
}
},
"/v1/actions/zero-item-time-fields": {
"post": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Group"
],
"summary": "Resets all item date fields to the beginning of the day",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.ActionAmountResult"
}
}
}
@@ -383,6 +407,60 @@ const docTemplate = `{
}
}
},
"/v1/items/fields": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Items"
],
"summary": "imports items into the database",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/items/fields/values": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Items"
],
"summary": "imports items into the database",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/items/import": {
"post": {
"security": [
@@ -1045,6 +1123,53 @@ const docTemplate = `{
}
}
},
"/v1/locations/tree": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Locations"
],
"summary": "Get All Locations",
"parameters": [
{
"type": "boolean",
"description": "include items in response tree",
"name": "withItems",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/server.Results"
},
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.TreeItem"
}
}
}
}
]
}
}
}
}
},
"/v1/locations/{id}": {
"get": {
"security": [
@@ -1178,6 +1303,30 @@ const docTemplate = `{
}
}
},
"/v1/reporting/bill-of-materials": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Reporting"
],
"summary": "Generates a Bill of Materials CSV",
"responses": {
"200": {
"description": "text/csv",
"schema": {
"type": "string"
}
}
}
}
},
"/v1/status": {
"get": {
"produces": [
@@ -1906,6 +2055,10 @@ const docTemplate = `{
},
"name": {
"type": "string"
},
"parentId": {
"type": "string",
"x-nullable": true
}
}
},
@@ -2116,6 +2269,26 @@ const docTemplate = `{
}
}
},
"repo.TreeItem": {
"type": "object",
"properties": {
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.TreeItem"
}
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"repo.UserOut": {
"type": "object",
"properties": {
@@ -2240,6 +2413,14 @@ const docTemplate = `{
}
}
},
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.ApiSummary": {
"type": "object",
"properties": {
@@ -2291,14 +2472,6 @@ const docTemplate = `{
}
}
},
"v1.EnsureAssetIDResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.GroupInvitation": {
"type": "object",
"properties": {

View File

@@ -26,12 +26,36 @@
"tags": [
"Group"
],
"summary": "Get the current user",
"summary": "Ensures all items in the database have an asset id",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.EnsureAssetIDResult"
"$ref": "#/definitions/v1.ActionAmountResult"
}
}
}
}
},
"/v1/actions/zero-item-time-fields": {
"post": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Group"
],
"summary": "Resets all item date fields to the beginning of the day",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.ActionAmountResult"
}
}
}
@@ -375,6 +399,60 @@
}
}
},
"/v1/items/fields": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Items"
],
"summary": "imports items into the database",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/items/fields/values": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Items"
],
"summary": "imports items into the database",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/items/import": {
"post": {
"security": [
@@ -1037,6 +1115,53 @@
}
}
},
"/v1/locations/tree": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Locations"
],
"summary": "Get All Locations",
"parameters": [
{
"type": "boolean",
"description": "include items in response tree",
"name": "withItems",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/server.Results"
},
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.TreeItem"
}
}
}
}
]
}
}
}
}
},
"/v1/locations/{id}": {
"get": {
"security": [
@@ -1170,6 +1295,30 @@
}
}
},
"/v1/reporting/bill-of-materials": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Reporting"
],
"summary": "Generates a Bill of Materials CSV",
"responses": {
"200": {
"description": "text/csv",
"schema": {
"type": "string"
}
}
}
}
},
"/v1/status": {
"get": {
"produces": [
@@ -1898,6 +2047,10 @@
},
"name": {
"type": "string"
},
"parentId": {
"type": "string",
"x-nullable": true
}
}
},
@@ -2108,6 +2261,26 @@
}
}
},
"repo.TreeItem": {
"type": "object",
"properties": {
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.TreeItem"
}
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"repo.UserOut": {
"type": "object",
"properties": {
@@ -2232,6 +2405,14 @@
}
}
},
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.ApiSummary": {
"type": "object",
"properties": {
@@ -2283,14 +2464,6 @@
}
}
},
"v1.EnsureAssetIDResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.GroupInvitation": {
"type": "object",
"properties": {

View File

@@ -322,6 +322,9 @@ definitions:
type: string
name:
type: string
parentId:
type: string
x-nullable: true
type: object
repo.LocationOut:
properties:
@@ -459,6 +462,19 @@ definitions:
total:
type: number
type: object
repo.TreeItem:
properties:
children:
items:
$ref: '#/definitions/repo.TreeItem'
type: array
id:
type: string
name:
type: string
type:
type: string
type: object
repo.UserOut:
properties:
email:
@@ -540,6 +556,11 @@ definitions:
token:
type: string
type: object
v1.ActionAmountResult:
properties:
completed:
type: integer
type: object
v1.ApiSummary:
properties:
build:
@@ -573,11 +594,6 @@ definitions:
new:
type: string
type: object
v1.EnsureAssetIDResult:
properties:
completed:
type: integer
type: object
v1.GroupInvitation:
properties:
expiresAt:
@@ -627,10 +643,24 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/v1.EnsureAssetIDResult'
$ref: '#/definitions/v1.ActionAmountResult'
security:
- Bearer: []
summary: Get the current user
summary: Ensures all items in the database have an asset id
tags:
- Group
/v1/actions/zero-item-time-fields:
post:
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/v1.ActionAmountResult'
security:
- Bearer: []
summary: Resets all item date fields to the beginning of the day
tags:
- Group
/v1/assets/{id}:
@@ -1078,6 +1108,38 @@ paths:
summary: Update Maintenance Entry
tags:
- Maintenance
/v1/items/fields:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
type: string
type: array
security:
- Bearer: []
summary: imports items into the database
tags:
- Items
/v1/items/fields/values:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
type: string
type: array
security:
- Bearer: []
summary: imports items into the database
tags:
- Items
/v1/items/import:
post:
parameters:
@@ -1301,6 +1363,32 @@ paths:
summary: updates a location
tags:
- Locations
/v1/locations/tree:
get:
parameters:
- description: include items in response tree
in: query
name: withItems
type: boolean
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/server.Results'
- properties:
items:
items:
$ref: '#/definitions/repo.TreeItem'
type: array
type: object
security:
- Bearer: []
summary: Get All Locations
tags:
- Locations
/v1/qrcode:
get:
parameters:
@@ -1320,6 +1408,20 @@ paths:
summary: Encode data into QRCode
tags:
- Items
/v1/reporting/bill-of-materials:
get:
produces:
- application/json
responses:
"200":
description: text/csv
schema:
type: string
security:
- Bearer: []
summary: Generates a Bill of Materials CSV
tags:
- Reporting
/v1/status:
get:
produces:

View File

@@ -3,20 +3,21 @@ module github.com/hay-kot/homebox/backend
go 1.19
require (
ariga.io/atlas v0.9.0
entgo.io/ent v0.11.5
github.com/ardanlabs/conf/v2 v2.2.0
ariga.io/atlas v0.9.1-0.20230119145809-92243f7c55cb
entgo.io/ent v0.11.7
github.com/ardanlabs/conf/v3 v3.1.3
github.com/go-chi/chi/v5 v5.0.8
github.com/go-playground/validator/v10 v10.11.1
github.com/go-playground/validator/v10 v10.11.2
github.com/gocarina/gocsv v0.0.0-20230123225133-763e25b40669
github.com/google/uuid v1.3.0
github.com/mattn/go-sqlite3 v1.14.16
github.com/rs/zerolog v1.28.0
github.com/rs/zerolog v1.29.0
github.com/stretchr/testify v1.8.1
github.com/swaggo/http-swagger v1.3.3
github.com/swaggo/swag v1.8.9
github.com/swaggo/swag v1.8.10
github.com/yeqown/go-qrcode/v2 v2.2.1
github.com/yeqown/go-qrcode/writer/standard v1.2.1
golang.org/x/crypto v0.5.0
golang.org/x/crypto v0.6.0
)
require (
@@ -30,8 +31,8 @@ require (
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/spec v0.20.7 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/hashicorp/hcl/v2 v2.15.0 // indirect
@@ -48,9 +49,9 @@ require (
github.com/zclconf/go-cty v1.12.1 // indirect
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/net v0.5.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/text v0.6.0 // indirect
golang.org/x/net v0.6.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/tools v0.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -1,7 +1,7 @@
ariga.io/atlas v0.9.0 h1:q0JMtqyA3X1YWtPcn+E/kVPwLDslb+jAC8Ejl/vW6d0=
ariga.io/atlas v0.9.0/go.mod h1:T230JFcENj4ZZzMkZrXFDSkv+2kXkUgpJ5FQQ5hMcKU=
entgo.io/ent v0.11.5 h1:V2qhG91C4PMQTa82Q4StoESMQ4dzkMNeStCzszxi0jQ=
entgo.io/ent v0.11.5/go.mod h1:u7eKwNWAo/VlHIKxgwbmsFy3J7cKDxwi3jyF5TW/okY=
ariga.io/atlas v0.9.1-0.20230119145809-92243f7c55cb h1:mbsFtavDqGdYwdDpP50LGOOZ2hgyGoJcZeOpbgKMyu4=
ariga.io/atlas v0.9.1-0.20230119145809-92243f7c55cb/go.mod h1:T230JFcENj4ZZzMkZrXFDSkv+2kXkUgpJ5FQQ5hMcKU=
entgo.io/ent v0.11.7 h1:V+wKFh0jhAbY/FoU+PPbdMOf2Ma5vh07R/IdF+N/nFg=
entgo.io/ent v0.11.7/go.mod h1:ericBi6Q8l3wBH1wEIDfKxw7rcQEuRPyBfbIzjtxJ18=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
@@ -9,8 +9,8 @@ github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7l
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/ardanlabs/conf/v2 v2.2.0 h1:ar1+TYIYAh2Tdeg2DQroh7ruR56/vJR8BDfzDIrXgtk=
github.com/ardanlabs/conf/v2 v2.2.0/go.mod h1:m37ZKdW9jwMUEhGX36jRNt8VzSQ/HVmSziLZH2p33nY=
github.com/ardanlabs/conf/v3 v3.1.3 h1:16+Nzfc4PBd/ERtYERUFL/75eVKNyW15Y+vn3W1XZzQ=
github.com/ardanlabs/conf/v3 v3.1.3/go.mod h1:bIacyuGeZjkTdtszdbvOcuq49VhHpV3+IPZ2ewOAK4I=
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -33,15 +33,16 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/gocarina/gocsv v0.0.0-20230123225133-763e25b40669 h1:MvZzCA/mduVWoBSVKJeMdv+AqXQmZZ8i6p8889ejt/Y=
github.com/gocarina/gocsv v0.0.0-20230123225133-763e25b40669/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
@@ -55,9 +56,7 @@ github.com/hashicorp/hcl/v2 v2.15.0/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6Ko
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -84,17 +83,14 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ
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/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
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=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
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/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -103,7 +99,6 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
@@ -112,8 +107,8 @@ github.com/swaggo/files v1.0.0 h1:1gGXVIeUFCS/dta17rnP0iOpr6CXFwKD7EO5ID233e4=
github.com/swaggo/files v1.0.0/go.mod h1:N59U6URJLyU1PQgFqPM7wXLMhJx7QAolnvfQkqO13kc=
github.com/swaggo/http-swagger v1.3.3 h1:Hu5Z0L9ssyBLofaama21iYaF2VbWyA8jdohaaCGpHsc=
github.com/swaggo/http-swagger v1.3.3/go.mod h1:sE+4PjD89IxMPm77FnkDz0sdO+p5lbXzrVWT6OTVVGo=
github.com/swaggo/swag v1.8.9 h1:kHtaBe/Ob9AZzAANfcn5c6RyCke9gG9QpH0jky0I/sA=
github.com/swaggo/swag v1.8.9/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk=
github.com/swaggo/swag v1.8.10 h1:eExW4bFa52WOjqRzRD58bgWsWfdFJso50lpbeTcmTfo=
github.com/swaggo/swag v1.8.10/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk=
github.com/yeqown/go-qrcode/v2 v2.2.1 h1:Jc1Q916fwC05R8C7mpWDbrT9tyLPaLLKDABoC5XBCe8=
github.com/yeqown/go-qrcode/v2 v2.2.1/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24=
github.com/yeqown/go-qrcode/writer/standard v1.2.1 h1:FMRZiur5yApUIe4fqtqmcdl/XQTZAZWt2DhkPx4VIW0=
@@ -125,9 +120,8 @@ github.com/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY
github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -135,36 +129,32 @@ golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
@@ -175,13 +165,10 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -1,11 +1,16 @@
package services
import "github.com/hay-kot/homebox/backend/internal/data/repo"
import (
"github.com/hay-kot/homebox/backend/internal/core/services/reporting"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/rs/zerolog/log"
)
type AllServices struct {
User *UserService
Group *GroupService
Items *ItemService
User *UserService
Group *GroupService
Items *ItemService
Reporting *reporting.ReportingService
}
type OptionsFunc func(*options)
@@ -40,5 +45,7 @@ func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices {
repo: repos,
autoIncrementAssetID: options.autoIncrementAssetID,
},
// TODO: don't use global logger
Reporting: reporting.NewReportingService(repos, &log.Logger),
}
}

View File

@@ -0,0 +1,85 @@
package reporting
import (
"context"
"encoding/csv"
"io"
"time"
"github.com/gocarina/gocsv"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/rs/zerolog"
)
type ReportingService struct {
repos *repo.AllRepos
l *zerolog.Logger
}
func NewReportingService(repos *repo.AllRepos, l *zerolog.Logger) *ReportingService {
gocsv.SetCSVWriter(func(out io.Writer) *gocsv.SafeCSVWriter {
writer := csv.NewWriter(out)
writer.Comma = '\t'
return gocsv.NewSafeCSVWriter(writer)
})
return &ReportingService{
repos: repos,
l: l,
}
}
// =================================================================================================
// NullableTime is a custom type that implements the MarshalCSV interface
// to allow for nullable time.Time fields in the CSV output to be empty
// and not "0001-01-01". It also overrides the default CSV output format
type NullableTime time.Time
func (t NullableTime) MarshalCSV() (string, error) {
if time.Time(t).IsZero() {
return "", nil
}
// YYYY-MM-DD
return time.Time(t).Format("2006-01-02"), nil
}
type BillOfMaterialsEntry struct {
PurchaseDate NullableTime `csv:"Purchase Date"`
Name string `csv:"Name"`
Description string `csv:"Description"`
Manufacturer string `csv:"Manufacturer"`
SerialNumber string `csv:"Serial Number"`
ModelNumber string `csv:"Model Number"`
Quantity int `csv:"Quantity"`
Price float64 `csv:"Price"`
TotalPrice float64 `csv:"Total Price"`
}
// BillOfMaterialsTSV returns a byte slice of the Bill of Materials for a given GID in TSV format
// See BillOfMaterialsEntry for the format of the output
func (rs *ReportingService) BillOfMaterialsTSV(ctx context.Context, GID uuid.UUID) ([]byte, error) {
entities, err := rs.repos.Items.GetAll(ctx, GID)
if err != nil {
rs.l.Debug().Err(err).Msg("failed to get all items for BOM Csv Reporting")
return nil, err
}
bomEntries := make([]BillOfMaterialsEntry, len(entities))
for i, entity := range entities {
bomEntries[i] = BillOfMaterialsEntry{
PurchaseDate: NullableTime(entity.PurchaseTime),
Name: entity.Name,
Description: entity.Description,
Manufacturer: entity.Manufacturer,
SerialNumber: entity.SerialNumber,
ModelNumber: entity.ModelNumber,
Quantity: entity.Quantity,
Price: entity.PurchasePrice,
TotalPrice: entity.PurchasePrice * float64(entity.Quantity),
}
}
return gocsv.MarshalBytes(&bomEntries)
}

View File

@@ -12,10 +12,10 @@ import (
"github.com/stretchr/testify/assert"
)
//go:embed testdata/import.csv
//go:embed .testdata/import.csv
var CSVData_Comma []byte
//go:embed testdata/import.tsv
//go:embed .testdata/import.tsv
var CSVData_Tab []byte
func loadcsv() [][]string {

View File

@@ -51,15 +51,17 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
Msg("Registering new user")
var (
err error
group repo.Group
token repo.GroupInvitation
isOwner = false
err error
group repo.Group
token repo.GroupInvitation
// creatingGroup is true if the user is creating a new group.
creatingGroup = false
)
switch data.GroupToken {
case "":
isOwner = true
creatingGroup = true
group, err = svc.repos.Groups.GroupCreate(ctx, "Home")
if err != nil {
log.Err(err).Msg("Failed to create group")
@@ -81,7 +83,7 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
Password: hashed,
IsSuperuser: false,
GroupID: group.ID,
IsOwner: isOwner,
IsOwner: creatingGroup,
}
usr, err := svc.repos.Users.Create(ctx, usrCreate)
@@ -89,21 +91,24 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
return repo.UserOut{}, err
}
for _, label := range defaultLabels() {
_, err := svc.repos.Labels.Create(ctx, group.ID, label)
if err != nil {
return repo.UserOut{}, err
// Create the default labels and locations for the group.
if creatingGroup {
for _, label := range defaultLabels() {
_, err := svc.repos.Labels.Create(ctx, group.ID, label)
if err != nil {
return repo.UserOut{}, err
}
}
for _, location := range defaultLocations() {
_, err := svc.repos.Locations.Create(ctx, group.ID, location)
if err != nil {
return repo.UserOut{}, err
}
}
}
for _, location := range defaultLocations() {
_, err := svc.repos.Locations.Create(ctx, group.ID, location)
if err != nil {
return repo.UserOut{}, err
}
}
// Decrement the invitation token if it was used
// Decrement the invitation token if it was used.
if token.ID != uuid.Nil {
err = svc.repos.Groups.InvitationUpdate(ctx, token.ID, token.Uses-1)
if err != nil {

View File

@@ -144,19 +144,19 @@ func (a *Attachment) assignValues(columns []string, values []any) error {
// QueryItem queries the "item" edge of the Attachment entity.
func (a *Attachment) QueryItem() *ItemQuery {
return (&AttachmentClient{config: a.config}).QueryItem(a)
return NewAttachmentClient(a.config).QueryItem(a)
}
// QueryDocument queries the "document" edge of the Attachment entity.
func (a *Attachment) QueryDocument() *DocumentQuery {
return (&AttachmentClient{config: a.config}).QueryDocument(a)
return NewAttachmentClient(a.config).QueryDocument(a)
}
// Update returns a builder for updating this Attachment.
// Note that you need to call Attachment.Unwrap() before calling this method if this Attachment
// was returned from a transaction, and the transaction was committed or rolled back.
func (a *Attachment) Update() *AttachmentUpdateOne {
return (&AttachmentClient{config: a.config}).UpdateOne(a)
return NewAttachmentClient(a.config).UpdateOne(a)
}
// Unwrap unwraps the Attachment entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type AttachmentDeleteOne struct {
ad *AttachmentDelete
}
// Where appends a list predicates to the AttachmentDelete builder.
func (ado *AttachmentDeleteOne) Where(ps ...predicate.Attachment) *AttachmentDeleteOne {
ado.ad.mutation.Where(ps...)
return ado
}
// Exec executes the deletion query.
func (ado *AttachmentDeleteOne) Exec(ctx context.Context) error {
n, err := ado.ad.Exec(ctx)
@@ -84,5 +90,7 @@ func (ado *AttachmentDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (ado *AttachmentDeleteOne) ExecX(ctx context.Context) {
ado.ad.ExecX(ctx)
if err := ado.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -20,11 +20,8 @@ import (
// AttachmentQuery is the builder for querying Attachment entities.
type AttachmentQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.Attachment
withItem *ItemQuery
@@ -43,20 +40,20 @@ func (aq *AttachmentQuery) Where(ps ...predicate.Attachment) *AttachmentQuery {
// Limit the number of records to be returned by this query.
func (aq *AttachmentQuery) Limit(limit int) *AttachmentQuery {
aq.limit = &limit
aq.ctx.Limit = &limit
return aq
}
// Offset to start from.
func (aq *AttachmentQuery) Offset(offset int) *AttachmentQuery {
aq.offset = &offset
aq.ctx.Offset = &offset
return aq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (aq *AttachmentQuery) Unique(unique bool) *AttachmentQuery {
aq.unique = &unique
aq.ctx.Unique = &unique
return aq
}
@@ -113,7 +110,7 @@ func (aq *AttachmentQuery) QueryDocument() *DocumentQuery {
// First returns the first Attachment entity from the query.
// Returns a *NotFoundError when no Attachment was found.
func (aq *AttachmentQuery) First(ctx context.Context) (*Attachment, error) {
nodes, err := aq.Limit(1).All(newQueryContext(ctx, TypeAttachment, "First"))
nodes, err := aq.Limit(1).All(setContextOp(ctx, aq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -136,7 +133,7 @@ func (aq *AttachmentQuery) FirstX(ctx context.Context) *Attachment {
// Returns a *NotFoundError when no Attachment ID was found.
func (aq *AttachmentQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = aq.Limit(1).IDs(newQueryContext(ctx, TypeAttachment, "FirstID")); err != nil {
if ids, err = aq.Limit(1).IDs(setContextOp(ctx, aq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -159,7 +156,7 @@ func (aq *AttachmentQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one Attachment entity is found.
// Returns a *NotFoundError when no Attachment entities are found.
func (aq *AttachmentQuery) Only(ctx context.Context) (*Attachment, error) {
nodes, err := aq.Limit(2).All(newQueryContext(ctx, TypeAttachment, "Only"))
nodes, err := aq.Limit(2).All(setContextOp(ctx, aq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -187,7 +184,7 @@ func (aq *AttachmentQuery) OnlyX(ctx context.Context) *Attachment {
// Returns a *NotFoundError when no entities are found.
func (aq *AttachmentQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = aq.Limit(2).IDs(newQueryContext(ctx, TypeAttachment, "OnlyID")); err != nil {
if ids, err = aq.Limit(2).IDs(setContextOp(ctx, aq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -212,7 +209,7 @@ func (aq *AttachmentQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of Attachments.
func (aq *AttachmentQuery) All(ctx context.Context) ([]*Attachment, error) {
ctx = newQueryContext(ctx, TypeAttachment, "All")
ctx = setContextOp(ctx, aq.ctx, "All")
if err := aq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -232,7 +229,7 @@ func (aq *AttachmentQuery) AllX(ctx context.Context) []*Attachment {
// IDs executes the query and returns a list of Attachment IDs.
func (aq *AttachmentQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeAttachment, "IDs")
ctx = setContextOp(ctx, aq.ctx, "IDs")
if err := aq.Select(attachment.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -250,7 +247,7 @@ func (aq *AttachmentQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (aq *AttachmentQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeAttachment, "Count")
ctx = setContextOp(ctx, aq.ctx, "Count")
if err := aq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -268,7 +265,7 @@ func (aq *AttachmentQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (aq *AttachmentQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeAttachment, "Exist")
ctx = setContextOp(ctx, aq.ctx, "Exist")
switch _, err := aq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -296,17 +293,15 @@ func (aq *AttachmentQuery) Clone() *AttachmentQuery {
}
return &AttachmentQuery{
config: aq.config,
limit: aq.limit,
offset: aq.offset,
ctx: aq.ctx.Clone(),
order: append([]OrderFunc{}, aq.order...),
inters: append([]Interceptor{}, aq.inters...),
predicates: append([]predicate.Attachment{}, aq.predicates...),
withItem: aq.withItem.Clone(),
withDocument: aq.withDocument.Clone(),
// clone intermediate query.
sql: aq.sql.Clone(),
path: aq.path,
unique: aq.unique,
sql: aq.sql.Clone(),
path: aq.path,
}
}
@@ -347,9 +342,9 @@ func (aq *AttachmentQuery) WithDocument(opts ...func(*DocumentQuery)) *Attachmen
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (aq *AttachmentQuery) GroupBy(field string, fields ...string) *AttachmentGroupBy {
aq.fields = append([]string{field}, fields...)
aq.ctx.Fields = append([]string{field}, fields...)
grbuild := &AttachmentGroupBy{build: aq}
grbuild.flds = &aq.fields
grbuild.flds = &aq.ctx.Fields
grbuild.label = attachment.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -368,10 +363,10 @@ func (aq *AttachmentQuery) GroupBy(field string, fields ...string) *AttachmentGr
// Select(attachment.FieldCreatedAt).
// Scan(ctx, &v)
func (aq *AttachmentQuery) Select(fields ...string) *AttachmentSelect {
aq.fields = append(aq.fields, fields...)
aq.ctx.Fields = append(aq.ctx.Fields, fields...)
sbuild := &AttachmentSelect{AttachmentQuery: aq}
sbuild.label = attachment.Label
sbuild.flds, sbuild.scan = &aq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &aq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -391,7 +386,7 @@ func (aq *AttachmentQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range aq.fields {
for _, f := range aq.ctx.Fields {
if !attachment.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -468,6 +463,9 @@ func (aq *AttachmentQuery) loadItem(ctx context.Context, query *ItemQuery, nodes
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(item.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -497,6 +495,9 @@ func (aq *AttachmentQuery) loadDocument(ctx context.Context, query *DocumentQuer
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(document.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -516,9 +517,9 @@ func (aq *AttachmentQuery) loadDocument(ctx context.Context, query *DocumentQuer
func (aq *AttachmentQuery) sqlCount(ctx context.Context) (int, error) {
_spec := aq.querySpec()
_spec.Node.Columns = aq.fields
if len(aq.fields) > 0 {
_spec.Unique = aq.unique != nil && *aq.unique
_spec.Node.Columns = aq.ctx.Fields
if len(aq.ctx.Fields) > 0 {
_spec.Unique = aq.ctx.Unique != nil && *aq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, aq.driver, _spec)
}
@@ -536,10 +537,10 @@ func (aq *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
From: aq.sql,
Unique: true,
}
if unique := aq.unique; unique != nil {
if unique := aq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := aq.fields; len(fields) > 0 {
if fields := aq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, attachment.FieldID)
for i := range fields {
@@ -555,10 +556,10 @@ func (aq *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := aq.limit; limit != nil {
if limit := aq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := aq.offset; offset != nil {
if offset := aq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := aq.order; len(ps) > 0 {
@@ -574,7 +575,7 @@ func (aq *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
func (aq *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(aq.driver.Dialect())
t1 := builder.Table(attachment.Table)
columns := aq.fields
columns := aq.ctx.Fields
if len(columns) == 0 {
columns = attachment.Columns
}
@@ -583,7 +584,7 @@ func (aq *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = aq.sql
selector.Select(selector.Columns(columns...)...)
}
if aq.unique != nil && *aq.unique {
if aq.ctx.Unique != nil && *aq.ctx.Unique {
selector.Distinct()
}
for _, p := range aq.predicates {
@@ -592,12 +593,12 @@ func (aq *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range aq.order {
p(selector)
}
if offset := aq.offset; offset != nil {
if offset := aq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := aq.limit; limit != nil {
if limit := aq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -617,7 +618,7 @@ func (agb *AttachmentGroupBy) Aggregate(fns ...AggregateFunc) *AttachmentGroupBy
// Scan applies the selector query and scans the result into the given value.
func (agb *AttachmentGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeAttachment, "GroupBy")
ctx = setContextOp(ctx, agb.build.ctx, "GroupBy")
if err := agb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -665,7 +666,7 @@ func (as *AttachmentSelect) Aggregate(fns ...AggregateFunc) *AttachmentSelect {
// Scan applies the selector query and scans the result into the given value.
func (as *AttachmentSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeAttachment, "Select")
ctx = setContextOp(ctx, as.ctx, "Select")
if err := as.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -99,14 +99,14 @@ func (ar *AuthRoles) assignValues(columns []string, values []any) error {
// QueryToken queries the "token" edge of the AuthRoles entity.
func (ar *AuthRoles) QueryToken() *AuthTokensQuery {
return (&AuthRolesClient{config: ar.config}).QueryToken(ar)
return NewAuthRolesClient(ar.config).QueryToken(ar)
}
// Update returns a builder for updating this AuthRoles.
// Note that you need to call AuthRoles.Unwrap() before calling this method if this AuthRoles
// was returned from a transaction, and the transaction was committed or rolled back.
func (ar *AuthRoles) Update() *AuthRolesUpdateOne {
return (&AuthRolesClient{config: ar.config}).UpdateOne(ar)
return NewAuthRolesClient(ar.config).UpdateOne(ar)
}
// Unwrap unwraps the AuthRoles entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type AuthRolesDeleteOne struct {
ard *AuthRolesDelete
}
// Where appends a list predicates to the AuthRolesDelete builder.
func (ardo *AuthRolesDeleteOne) Where(ps ...predicate.AuthRoles) *AuthRolesDeleteOne {
ardo.ard.mutation.Where(ps...)
return ardo
}
// Exec executes the deletion query.
func (ardo *AuthRolesDeleteOne) Exec(ctx context.Context) error {
n, err := ardo.ard.Exec(ctx)
@@ -84,5 +90,7 @@ func (ardo *AuthRolesDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (ardo *AuthRolesDeleteOne) ExecX(ctx context.Context) {
ardo.ard.ExecX(ctx)
if err := ardo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -19,11 +19,8 @@ import (
// AuthRolesQuery is the builder for querying AuthRoles entities.
type AuthRolesQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.AuthRoles
withToken *AuthTokensQuery
@@ -41,20 +38,20 @@ func (arq *AuthRolesQuery) Where(ps ...predicate.AuthRoles) *AuthRolesQuery {
// Limit the number of records to be returned by this query.
func (arq *AuthRolesQuery) Limit(limit int) *AuthRolesQuery {
arq.limit = &limit
arq.ctx.Limit = &limit
return arq
}
// Offset to start from.
func (arq *AuthRolesQuery) Offset(offset int) *AuthRolesQuery {
arq.offset = &offset
arq.ctx.Offset = &offset
return arq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (arq *AuthRolesQuery) Unique(unique bool) *AuthRolesQuery {
arq.unique = &unique
arq.ctx.Unique = &unique
return arq
}
@@ -89,7 +86,7 @@ func (arq *AuthRolesQuery) QueryToken() *AuthTokensQuery {
// First returns the first AuthRoles entity from the query.
// Returns a *NotFoundError when no AuthRoles was found.
func (arq *AuthRolesQuery) First(ctx context.Context) (*AuthRoles, error) {
nodes, err := arq.Limit(1).All(newQueryContext(ctx, TypeAuthRoles, "First"))
nodes, err := arq.Limit(1).All(setContextOp(ctx, arq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -112,7 +109,7 @@ func (arq *AuthRolesQuery) FirstX(ctx context.Context) *AuthRoles {
// Returns a *NotFoundError when no AuthRoles ID was found.
func (arq *AuthRolesQuery) FirstID(ctx context.Context) (id int, err error) {
var ids []int
if ids, err = arq.Limit(1).IDs(newQueryContext(ctx, TypeAuthRoles, "FirstID")); err != nil {
if ids, err = arq.Limit(1).IDs(setContextOp(ctx, arq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -135,7 +132,7 @@ func (arq *AuthRolesQuery) FirstIDX(ctx context.Context) int {
// Returns a *NotSingularError when more than one AuthRoles entity is found.
// Returns a *NotFoundError when no AuthRoles entities are found.
func (arq *AuthRolesQuery) Only(ctx context.Context) (*AuthRoles, error) {
nodes, err := arq.Limit(2).All(newQueryContext(ctx, TypeAuthRoles, "Only"))
nodes, err := arq.Limit(2).All(setContextOp(ctx, arq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -163,7 +160,7 @@ func (arq *AuthRolesQuery) OnlyX(ctx context.Context) *AuthRoles {
// Returns a *NotFoundError when no entities are found.
func (arq *AuthRolesQuery) OnlyID(ctx context.Context) (id int, err error) {
var ids []int
if ids, err = arq.Limit(2).IDs(newQueryContext(ctx, TypeAuthRoles, "OnlyID")); err != nil {
if ids, err = arq.Limit(2).IDs(setContextOp(ctx, arq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -188,7 +185,7 @@ func (arq *AuthRolesQuery) OnlyIDX(ctx context.Context) int {
// All executes the query and returns a list of AuthRolesSlice.
func (arq *AuthRolesQuery) All(ctx context.Context) ([]*AuthRoles, error) {
ctx = newQueryContext(ctx, TypeAuthRoles, "All")
ctx = setContextOp(ctx, arq.ctx, "All")
if err := arq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -208,7 +205,7 @@ func (arq *AuthRolesQuery) AllX(ctx context.Context) []*AuthRoles {
// IDs executes the query and returns a list of AuthRoles IDs.
func (arq *AuthRolesQuery) IDs(ctx context.Context) ([]int, error) {
var ids []int
ctx = newQueryContext(ctx, TypeAuthRoles, "IDs")
ctx = setContextOp(ctx, arq.ctx, "IDs")
if err := arq.Select(authroles.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -226,7 +223,7 @@ func (arq *AuthRolesQuery) IDsX(ctx context.Context) []int {
// Count returns the count of the given query.
func (arq *AuthRolesQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeAuthRoles, "Count")
ctx = setContextOp(ctx, arq.ctx, "Count")
if err := arq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -244,7 +241,7 @@ func (arq *AuthRolesQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (arq *AuthRolesQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeAuthRoles, "Exist")
ctx = setContextOp(ctx, arq.ctx, "Exist")
switch _, err := arq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -272,16 +269,14 @@ func (arq *AuthRolesQuery) Clone() *AuthRolesQuery {
}
return &AuthRolesQuery{
config: arq.config,
limit: arq.limit,
offset: arq.offset,
ctx: arq.ctx.Clone(),
order: append([]OrderFunc{}, arq.order...),
inters: append([]Interceptor{}, arq.inters...),
predicates: append([]predicate.AuthRoles{}, arq.predicates...),
withToken: arq.withToken.Clone(),
// clone intermediate query.
sql: arq.sql.Clone(),
path: arq.path,
unique: arq.unique,
sql: arq.sql.Clone(),
path: arq.path,
}
}
@@ -311,9 +306,9 @@ func (arq *AuthRolesQuery) WithToken(opts ...func(*AuthTokensQuery)) *AuthRolesQ
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (arq *AuthRolesQuery) GroupBy(field string, fields ...string) *AuthRolesGroupBy {
arq.fields = append([]string{field}, fields...)
arq.ctx.Fields = append([]string{field}, fields...)
grbuild := &AuthRolesGroupBy{build: arq}
grbuild.flds = &arq.fields
grbuild.flds = &arq.ctx.Fields
grbuild.label = authroles.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -332,10 +327,10 @@ func (arq *AuthRolesQuery) GroupBy(field string, fields ...string) *AuthRolesGro
// Select(authroles.FieldRole).
// Scan(ctx, &v)
func (arq *AuthRolesQuery) Select(fields ...string) *AuthRolesSelect {
arq.fields = append(arq.fields, fields...)
arq.ctx.Fields = append(arq.ctx.Fields, fields...)
sbuild := &AuthRolesSelect{AuthRolesQuery: arq}
sbuild.label = authroles.Label
sbuild.flds, sbuild.scan = &arq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &arq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -355,7 +350,7 @@ func (arq *AuthRolesQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range arq.fields {
for _, f := range arq.ctx.Fields {
if !authroles.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -425,6 +420,9 @@ func (arq *AuthRolesQuery) loadToken(ctx context.Context, query *AuthTokensQuery
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(authtokens.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -444,9 +442,9 @@ func (arq *AuthRolesQuery) loadToken(ctx context.Context, query *AuthTokensQuery
func (arq *AuthRolesQuery) sqlCount(ctx context.Context) (int, error) {
_spec := arq.querySpec()
_spec.Node.Columns = arq.fields
if len(arq.fields) > 0 {
_spec.Unique = arq.unique != nil && *arq.unique
_spec.Node.Columns = arq.ctx.Fields
if len(arq.ctx.Fields) > 0 {
_spec.Unique = arq.ctx.Unique != nil && *arq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, arq.driver, _spec)
}
@@ -464,10 +462,10 @@ func (arq *AuthRolesQuery) querySpec() *sqlgraph.QuerySpec {
From: arq.sql,
Unique: true,
}
if unique := arq.unique; unique != nil {
if unique := arq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := arq.fields; len(fields) > 0 {
if fields := arq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, authroles.FieldID)
for i := range fields {
@@ -483,10 +481,10 @@ func (arq *AuthRolesQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := arq.limit; limit != nil {
if limit := arq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := arq.offset; offset != nil {
if offset := arq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := arq.order; len(ps) > 0 {
@@ -502,7 +500,7 @@ func (arq *AuthRolesQuery) querySpec() *sqlgraph.QuerySpec {
func (arq *AuthRolesQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(arq.driver.Dialect())
t1 := builder.Table(authroles.Table)
columns := arq.fields
columns := arq.ctx.Fields
if len(columns) == 0 {
columns = authroles.Columns
}
@@ -511,7 +509,7 @@ func (arq *AuthRolesQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = arq.sql
selector.Select(selector.Columns(columns...)...)
}
if arq.unique != nil && *arq.unique {
if arq.ctx.Unique != nil && *arq.ctx.Unique {
selector.Distinct()
}
for _, p := range arq.predicates {
@@ -520,12 +518,12 @@ func (arq *AuthRolesQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range arq.order {
p(selector)
}
if offset := arq.offset; offset != nil {
if offset := arq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := arq.limit; limit != nil {
if limit := arq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -545,7 +543,7 @@ func (argb *AuthRolesGroupBy) Aggregate(fns ...AggregateFunc) *AuthRolesGroupBy
// Scan applies the selector query and scans the result into the given value.
func (argb *AuthRolesGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeAuthRoles, "GroupBy")
ctx = setContextOp(ctx, argb.build.ctx, "GroupBy")
if err := argb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -593,7 +591,7 @@ func (ars *AuthRolesSelect) Aggregate(fns ...AggregateFunc) *AuthRolesSelect {
// Scan applies the selector query and scans the result into the given value.
func (ars *AuthRolesSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeAuthRoles, "Select")
ctx = setContextOp(ctx, ars.ctx, "Select")
if err := ars.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -142,19 +142,19 @@ func (at *AuthTokens) assignValues(columns []string, values []any) error {
// QueryUser queries the "user" edge of the AuthTokens entity.
func (at *AuthTokens) QueryUser() *UserQuery {
return (&AuthTokensClient{config: at.config}).QueryUser(at)
return NewAuthTokensClient(at.config).QueryUser(at)
}
// QueryRoles queries the "roles" edge of the AuthTokens entity.
func (at *AuthTokens) QueryRoles() *AuthRolesQuery {
return (&AuthTokensClient{config: at.config}).QueryRoles(at)
return NewAuthTokensClient(at.config).QueryRoles(at)
}
// Update returns a builder for updating this AuthTokens.
// Note that you need to call AuthTokens.Unwrap() before calling this method if this AuthTokens
// was returned from a transaction, and the transaction was committed or rolled back.
func (at *AuthTokens) Update() *AuthTokensUpdateOne {
return (&AuthTokensClient{config: at.config}).UpdateOne(at)
return NewAuthTokensClient(at.config).UpdateOne(at)
}
// Unwrap unwraps the AuthTokens entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type AuthTokensDeleteOne struct {
atd *AuthTokensDelete
}
// Where appends a list predicates to the AuthTokensDelete builder.
func (atdo *AuthTokensDeleteOne) Where(ps ...predicate.AuthTokens) *AuthTokensDeleteOne {
atdo.atd.mutation.Where(ps...)
return atdo
}
// Exec executes the deletion query.
func (atdo *AuthTokensDeleteOne) Exec(ctx context.Context) error {
n, err := atdo.atd.Exec(ctx)
@@ -84,5 +90,7 @@ func (atdo *AuthTokensDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (atdo *AuthTokensDeleteOne) ExecX(ctx context.Context) {
atdo.atd.ExecX(ctx)
if err := atdo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -21,11 +21,8 @@ import (
// AuthTokensQuery is the builder for querying AuthTokens entities.
type AuthTokensQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.AuthTokens
withUser *UserQuery
@@ -44,20 +41,20 @@ func (atq *AuthTokensQuery) Where(ps ...predicate.AuthTokens) *AuthTokensQuery {
// Limit the number of records to be returned by this query.
func (atq *AuthTokensQuery) Limit(limit int) *AuthTokensQuery {
atq.limit = &limit
atq.ctx.Limit = &limit
return atq
}
// Offset to start from.
func (atq *AuthTokensQuery) Offset(offset int) *AuthTokensQuery {
atq.offset = &offset
atq.ctx.Offset = &offset
return atq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (atq *AuthTokensQuery) Unique(unique bool) *AuthTokensQuery {
atq.unique = &unique
atq.ctx.Unique = &unique
return atq
}
@@ -114,7 +111,7 @@ func (atq *AuthTokensQuery) QueryRoles() *AuthRolesQuery {
// First returns the first AuthTokens entity from the query.
// Returns a *NotFoundError when no AuthTokens was found.
func (atq *AuthTokensQuery) First(ctx context.Context) (*AuthTokens, error) {
nodes, err := atq.Limit(1).All(newQueryContext(ctx, TypeAuthTokens, "First"))
nodes, err := atq.Limit(1).All(setContextOp(ctx, atq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -137,7 +134,7 @@ func (atq *AuthTokensQuery) FirstX(ctx context.Context) *AuthTokens {
// Returns a *NotFoundError when no AuthTokens ID was found.
func (atq *AuthTokensQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = atq.Limit(1).IDs(newQueryContext(ctx, TypeAuthTokens, "FirstID")); err != nil {
if ids, err = atq.Limit(1).IDs(setContextOp(ctx, atq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -160,7 +157,7 @@ func (atq *AuthTokensQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one AuthTokens entity is found.
// Returns a *NotFoundError when no AuthTokens entities are found.
func (atq *AuthTokensQuery) Only(ctx context.Context) (*AuthTokens, error) {
nodes, err := atq.Limit(2).All(newQueryContext(ctx, TypeAuthTokens, "Only"))
nodes, err := atq.Limit(2).All(setContextOp(ctx, atq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -188,7 +185,7 @@ func (atq *AuthTokensQuery) OnlyX(ctx context.Context) *AuthTokens {
// Returns a *NotFoundError when no entities are found.
func (atq *AuthTokensQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = atq.Limit(2).IDs(newQueryContext(ctx, TypeAuthTokens, "OnlyID")); err != nil {
if ids, err = atq.Limit(2).IDs(setContextOp(ctx, atq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -213,7 +210,7 @@ func (atq *AuthTokensQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of AuthTokensSlice.
func (atq *AuthTokensQuery) All(ctx context.Context) ([]*AuthTokens, error) {
ctx = newQueryContext(ctx, TypeAuthTokens, "All")
ctx = setContextOp(ctx, atq.ctx, "All")
if err := atq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -233,7 +230,7 @@ func (atq *AuthTokensQuery) AllX(ctx context.Context) []*AuthTokens {
// IDs executes the query and returns a list of AuthTokens IDs.
func (atq *AuthTokensQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeAuthTokens, "IDs")
ctx = setContextOp(ctx, atq.ctx, "IDs")
if err := atq.Select(authtokens.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -251,7 +248,7 @@ func (atq *AuthTokensQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (atq *AuthTokensQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeAuthTokens, "Count")
ctx = setContextOp(ctx, atq.ctx, "Count")
if err := atq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -269,7 +266,7 @@ func (atq *AuthTokensQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (atq *AuthTokensQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeAuthTokens, "Exist")
ctx = setContextOp(ctx, atq.ctx, "Exist")
switch _, err := atq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -297,17 +294,15 @@ func (atq *AuthTokensQuery) Clone() *AuthTokensQuery {
}
return &AuthTokensQuery{
config: atq.config,
limit: atq.limit,
offset: atq.offset,
ctx: atq.ctx.Clone(),
order: append([]OrderFunc{}, atq.order...),
inters: append([]Interceptor{}, atq.inters...),
predicates: append([]predicate.AuthTokens{}, atq.predicates...),
withUser: atq.withUser.Clone(),
withRoles: atq.withRoles.Clone(),
// clone intermediate query.
sql: atq.sql.Clone(),
path: atq.path,
unique: atq.unique,
sql: atq.sql.Clone(),
path: atq.path,
}
}
@@ -348,9 +343,9 @@ func (atq *AuthTokensQuery) WithRoles(opts ...func(*AuthRolesQuery)) *AuthTokens
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (atq *AuthTokensQuery) GroupBy(field string, fields ...string) *AuthTokensGroupBy {
atq.fields = append([]string{field}, fields...)
atq.ctx.Fields = append([]string{field}, fields...)
grbuild := &AuthTokensGroupBy{build: atq}
grbuild.flds = &atq.fields
grbuild.flds = &atq.ctx.Fields
grbuild.label = authtokens.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -369,10 +364,10 @@ func (atq *AuthTokensQuery) GroupBy(field string, fields ...string) *AuthTokensG
// Select(authtokens.FieldCreatedAt).
// Scan(ctx, &v)
func (atq *AuthTokensQuery) Select(fields ...string) *AuthTokensSelect {
atq.fields = append(atq.fields, fields...)
atq.ctx.Fields = append(atq.ctx.Fields, fields...)
sbuild := &AuthTokensSelect{AuthTokensQuery: atq}
sbuild.label = authtokens.Label
sbuild.flds, sbuild.scan = &atq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &atq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -392,7 +387,7 @@ func (atq *AuthTokensQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range atq.fields {
for _, f := range atq.ctx.Fields {
if !authtokens.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -469,6 +464,9 @@ func (atq *AuthTokensQuery) loadUser(ctx context.Context, query *UserQuery, node
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(user.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -516,9 +514,9 @@ func (atq *AuthTokensQuery) loadRoles(ctx context.Context, query *AuthRolesQuery
func (atq *AuthTokensQuery) sqlCount(ctx context.Context) (int, error) {
_spec := atq.querySpec()
_spec.Node.Columns = atq.fields
if len(atq.fields) > 0 {
_spec.Unique = atq.unique != nil && *atq.unique
_spec.Node.Columns = atq.ctx.Fields
if len(atq.ctx.Fields) > 0 {
_spec.Unique = atq.ctx.Unique != nil && *atq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, atq.driver, _spec)
}
@@ -536,10 +534,10 @@ func (atq *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
From: atq.sql,
Unique: true,
}
if unique := atq.unique; unique != nil {
if unique := atq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := atq.fields; len(fields) > 0 {
if fields := atq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, authtokens.FieldID)
for i := range fields {
@@ -555,10 +553,10 @@ func (atq *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := atq.limit; limit != nil {
if limit := atq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := atq.offset; offset != nil {
if offset := atq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := atq.order; len(ps) > 0 {
@@ -574,7 +572,7 @@ func (atq *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
func (atq *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(atq.driver.Dialect())
t1 := builder.Table(authtokens.Table)
columns := atq.fields
columns := atq.ctx.Fields
if len(columns) == 0 {
columns = authtokens.Columns
}
@@ -583,7 +581,7 @@ func (atq *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = atq.sql
selector.Select(selector.Columns(columns...)...)
}
if atq.unique != nil && *atq.unique {
if atq.ctx.Unique != nil && *atq.ctx.Unique {
selector.Distinct()
}
for _, p := range atq.predicates {
@@ -592,12 +590,12 @@ func (atq *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range atq.order {
p(selector)
}
if offset := atq.offset; offset != nil {
if offset := atq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := atq.limit; limit != nil {
if limit := atq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -617,7 +615,7 @@ func (atgb *AuthTokensGroupBy) Aggregate(fns ...AggregateFunc) *AuthTokensGroupB
// Scan applies the selector query and scans the result into the given value.
func (atgb *AuthTokensGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeAuthTokens, "GroupBy")
ctx = setContextOp(ctx, atgb.build.ctx, "GroupBy")
if err := atgb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -665,7 +663,7 @@ func (ats *AuthTokensSelect) Aggregate(fns ...AggregateFunc) *AuthTokensSelect {
// Scan applies the selector query and scans the result into the given value.
func (ats *AuthTokensSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeAuthTokens, "Select")
ctx = setContextOp(ctx, ats.ctx, "Select")
if err := ats.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -324,6 +324,7 @@ func (c *AttachmentClient) DeleteOneID(id uuid.UUID) *AttachmentDeleteOne {
func (c *AttachmentClient) Query() *AttachmentQuery {
return &AttachmentQuery{
config: c.config,
ctx: &QueryContext{Type: TypeAttachment},
inters: c.Interceptors(),
}
}
@@ -473,6 +474,7 @@ func (c *AuthRolesClient) DeleteOneID(id int) *AuthRolesDeleteOne {
func (c *AuthRolesClient) Query() *AuthRolesQuery {
return &AuthRolesQuery{
config: c.config,
ctx: &QueryContext{Type: TypeAuthRoles},
inters: c.Interceptors(),
}
}
@@ -606,6 +608,7 @@ func (c *AuthTokensClient) DeleteOneID(id uuid.UUID) *AuthTokensDeleteOne {
func (c *AuthTokensClient) Query() *AuthTokensQuery {
return &AuthTokensQuery{
config: c.config,
ctx: &QueryContext{Type: TypeAuthTokens},
inters: c.Interceptors(),
}
}
@@ -755,6 +758,7 @@ func (c *DocumentClient) DeleteOneID(id uuid.UUID) *DocumentDeleteOne {
func (c *DocumentClient) Query() *DocumentQuery {
return &DocumentQuery{
config: c.config,
ctx: &QueryContext{Type: TypeDocument},
inters: c.Interceptors(),
}
}
@@ -904,6 +908,7 @@ func (c *GroupClient) DeleteOneID(id uuid.UUID) *GroupDeleteOne {
func (c *GroupClient) Query() *GroupQuery {
return &GroupQuery{
config: c.config,
ctx: &QueryContext{Type: TypeGroup},
inters: c.Interceptors(),
}
}
@@ -1117,6 +1122,7 @@ func (c *GroupInvitationTokenClient) DeleteOneID(id uuid.UUID) *GroupInvitationT
func (c *GroupInvitationTokenClient) Query() *GroupInvitationTokenQuery {
return &GroupInvitationTokenQuery{
config: c.config,
ctx: &QueryContext{Type: TypeGroupInvitationToken},
inters: c.Interceptors(),
}
}
@@ -1250,6 +1256,7 @@ func (c *ItemClient) DeleteOneID(id uuid.UUID) *ItemDeleteOne {
func (c *ItemClient) Query() *ItemQuery {
return &ItemQuery{
config: c.config,
ctx: &QueryContext{Type: TypeItem},
inters: c.Interceptors(),
}
}
@@ -1495,6 +1502,7 @@ func (c *ItemFieldClient) DeleteOneID(id uuid.UUID) *ItemFieldDeleteOne {
func (c *ItemFieldClient) Query() *ItemFieldQuery {
return &ItemFieldQuery{
config: c.config,
ctx: &QueryContext{Type: TypeItemField},
inters: c.Interceptors(),
}
}
@@ -1628,6 +1636,7 @@ func (c *LabelClient) DeleteOneID(id uuid.UUID) *LabelDeleteOne {
func (c *LabelClient) Query() *LabelQuery {
return &LabelQuery{
config: c.config,
ctx: &QueryContext{Type: TypeLabel},
inters: c.Interceptors(),
}
}
@@ -1777,6 +1786,7 @@ func (c *LocationClient) DeleteOneID(id uuid.UUID) *LocationDeleteOne {
func (c *LocationClient) Query() *LocationQuery {
return &LocationQuery{
config: c.config,
ctx: &QueryContext{Type: TypeLocation},
inters: c.Interceptors(),
}
}
@@ -1958,6 +1968,7 @@ func (c *MaintenanceEntryClient) DeleteOneID(id uuid.UUID) *MaintenanceEntryDele
func (c *MaintenanceEntryClient) Query() *MaintenanceEntryQuery {
return &MaintenanceEntryQuery{
config: c.config,
ctx: &QueryContext{Type: TypeMaintenanceEntry},
inters: c.Interceptors(),
}
}
@@ -2091,6 +2102,7 @@ func (c *UserClient) DeleteOneID(id uuid.UUID) *UserDeleteOne {
func (c *UserClient) Query() *UserQuery {
return &UserQuery{
config: c.config,
ctx: &QueryContext{Type: TypeUser},
inters: c.Interceptors(),
}
}

View File

@@ -137,19 +137,19 @@ func (d *Document) assignValues(columns []string, values []any) error {
// QueryGroup queries the "group" edge of the Document entity.
func (d *Document) QueryGroup() *GroupQuery {
return (&DocumentClient{config: d.config}).QueryGroup(d)
return NewDocumentClient(d.config).QueryGroup(d)
}
// QueryAttachments queries the "attachments" edge of the Document entity.
func (d *Document) QueryAttachments() *AttachmentQuery {
return (&DocumentClient{config: d.config}).QueryAttachments(d)
return NewDocumentClient(d.config).QueryAttachments(d)
}
// Update returns a builder for updating this Document.
// Note that you need to call Document.Unwrap() before calling this method if this Document
// was returned from a transaction, and the transaction was committed or rolled back.
func (d *Document) Update() *DocumentUpdateOne {
return (&DocumentClient{config: d.config}).UpdateOne(d)
return NewDocumentClient(d.config).UpdateOne(d)
}
// Unwrap unwraps the Document entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type DocumentDeleteOne struct {
dd *DocumentDelete
}
// Where appends a list predicates to the DocumentDelete builder.
func (ddo *DocumentDeleteOne) Where(ps ...predicate.Document) *DocumentDeleteOne {
ddo.dd.mutation.Where(ps...)
return ddo
}
// Exec executes the deletion query.
func (ddo *DocumentDeleteOne) Exec(ctx context.Context) error {
n, err := ddo.dd.Exec(ctx)
@@ -84,5 +90,7 @@ func (ddo *DocumentDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (ddo *DocumentDeleteOne) ExecX(ctx context.Context) {
ddo.dd.ExecX(ctx)
if err := ddo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -21,11 +21,8 @@ import (
// DocumentQuery is the builder for querying Document entities.
type DocumentQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.Document
withGroup *GroupQuery
@@ -44,20 +41,20 @@ func (dq *DocumentQuery) Where(ps ...predicate.Document) *DocumentQuery {
// Limit the number of records to be returned by this query.
func (dq *DocumentQuery) Limit(limit int) *DocumentQuery {
dq.limit = &limit
dq.ctx.Limit = &limit
return dq
}
// Offset to start from.
func (dq *DocumentQuery) Offset(offset int) *DocumentQuery {
dq.offset = &offset
dq.ctx.Offset = &offset
return dq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (dq *DocumentQuery) Unique(unique bool) *DocumentQuery {
dq.unique = &unique
dq.ctx.Unique = &unique
return dq
}
@@ -114,7 +111,7 @@ func (dq *DocumentQuery) QueryAttachments() *AttachmentQuery {
// First returns the first Document entity from the query.
// Returns a *NotFoundError when no Document was found.
func (dq *DocumentQuery) First(ctx context.Context) (*Document, error) {
nodes, err := dq.Limit(1).All(newQueryContext(ctx, TypeDocument, "First"))
nodes, err := dq.Limit(1).All(setContextOp(ctx, dq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -137,7 +134,7 @@ func (dq *DocumentQuery) FirstX(ctx context.Context) *Document {
// Returns a *NotFoundError when no Document ID was found.
func (dq *DocumentQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = dq.Limit(1).IDs(newQueryContext(ctx, TypeDocument, "FirstID")); err != nil {
if ids, err = dq.Limit(1).IDs(setContextOp(ctx, dq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -160,7 +157,7 @@ func (dq *DocumentQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one Document entity is found.
// Returns a *NotFoundError when no Document entities are found.
func (dq *DocumentQuery) Only(ctx context.Context) (*Document, error) {
nodes, err := dq.Limit(2).All(newQueryContext(ctx, TypeDocument, "Only"))
nodes, err := dq.Limit(2).All(setContextOp(ctx, dq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -188,7 +185,7 @@ func (dq *DocumentQuery) OnlyX(ctx context.Context) *Document {
// Returns a *NotFoundError when no entities are found.
func (dq *DocumentQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = dq.Limit(2).IDs(newQueryContext(ctx, TypeDocument, "OnlyID")); err != nil {
if ids, err = dq.Limit(2).IDs(setContextOp(ctx, dq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -213,7 +210,7 @@ func (dq *DocumentQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of Documents.
func (dq *DocumentQuery) All(ctx context.Context) ([]*Document, error) {
ctx = newQueryContext(ctx, TypeDocument, "All")
ctx = setContextOp(ctx, dq.ctx, "All")
if err := dq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -233,7 +230,7 @@ func (dq *DocumentQuery) AllX(ctx context.Context) []*Document {
// IDs executes the query and returns a list of Document IDs.
func (dq *DocumentQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeDocument, "IDs")
ctx = setContextOp(ctx, dq.ctx, "IDs")
if err := dq.Select(document.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -251,7 +248,7 @@ func (dq *DocumentQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (dq *DocumentQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeDocument, "Count")
ctx = setContextOp(ctx, dq.ctx, "Count")
if err := dq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -269,7 +266,7 @@ func (dq *DocumentQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (dq *DocumentQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeDocument, "Exist")
ctx = setContextOp(ctx, dq.ctx, "Exist")
switch _, err := dq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -297,17 +294,15 @@ func (dq *DocumentQuery) Clone() *DocumentQuery {
}
return &DocumentQuery{
config: dq.config,
limit: dq.limit,
offset: dq.offset,
ctx: dq.ctx.Clone(),
order: append([]OrderFunc{}, dq.order...),
inters: append([]Interceptor{}, dq.inters...),
predicates: append([]predicate.Document{}, dq.predicates...),
withGroup: dq.withGroup.Clone(),
withAttachments: dq.withAttachments.Clone(),
// clone intermediate query.
sql: dq.sql.Clone(),
path: dq.path,
unique: dq.unique,
sql: dq.sql.Clone(),
path: dq.path,
}
}
@@ -348,9 +343,9 @@ func (dq *DocumentQuery) WithAttachments(opts ...func(*AttachmentQuery)) *Docume
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (dq *DocumentQuery) GroupBy(field string, fields ...string) *DocumentGroupBy {
dq.fields = append([]string{field}, fields...)
dq.ctx.Fields = append([]string{field}, fields...)
grbuild := &DocumentGroupBy{build: dq}
grbuild.flds = &dq.fields
grbuild.flds = &dq.ctx.Fields
grbuild.label = document.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -369,10 +364,10 @@ func (dq *DocumentQuery) GroupBy(field string, fields ...string) *DocumentGroupB
// Select(document.FieldCreatedAt).
// Scan(ctx, &v)
func (dq *DocumentQuery) Select(fields ...string) *DocumentSelect {
dq.fields = append(dq.fields, fields...)
dq.ctx.Fields = append(dq.ctx.Fields, fields...)
sbuild := &DocumentSelect{DocumentQuery: dq}
sbuild.label = document.Label
sbuild.flds, sbuild.scan = &dq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &dq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -392,7 +387,7 @@ func (dq *DocumentQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range dq.fields {
for _, f := range dq.ctx.Fields {
if !document.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -470,6 +465,9 @@ func (dq *DocumentQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(group.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -520,9 +518,9 @@ func (dq *DocumentQuery) loadAttachments(ctx context.Context, query *AttachmentQ
func (dq *DocumentQuery) sqlCount(ctx context.Context) (int, error) {
_spec := dq.querySpec()
_spec.Node.Columns = dq.fields
if len(dq.fields) > 0 {
_spec.Unique = dq.unique != nil && *dq.unique
_spec.Node.Columns = dq.ctx.Fields
if len(dq.ctx.Fields) > 0 {
_spec.Unique = dq.ctx.Unique != nil && *dq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, dq.driver, _spec)
}
@@ -540,10 +538,10 @@ func (dq *DocumentQuery) querySpec() *sqlgraph.QuerySpec {
From: dq.sql,
Unique: true,
}
if unique := dq.unique; unique != nil {
if unique := dq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := dq.fields; len(fields) > 0 {
if fields := dq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, document.FieldID)
for i := range fields {
@@ -559,10 +557,10 @@ func (dq *DocumentQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := dq.limit; limit != nil {
if limit := dq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := dq.offset; offset != nil {
if offset := dq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := dq.order; len(ps) > 0 {
@@ -578,7 +576,7 @@ func (dq *DocumentQuery) querySpec() *sqlgraph.QuerySpec {
func (dq *DocumentQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(dq.driver.Dialect())
t1 := builder.Table(document.Table)
columns := dq.fields
columns := dq.ctx.Fields
if len(columns) == 0 {
columns = document.Columns
}
@@ -587,7 +585,7 @@ func (dq *DocumentQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = dq.sql
selector.Select(selector.Columns(columns...)...)
}
if dq.unique != nil && *dq.unique {
if dq.ctx.Unique != nil && *dq.ctx.Unique {
selector.Distinct()
}
for _, p := range dq.predicates {
@@ -596,12 +594,12 @@ func (dq *DocumentQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range dq.order {
p(selector)
}
if offset := dq.offset; offset != nil {
if offset := dq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := dq.limit; limit != nil {
if limit := dq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -621,7 +619,7 @@ func (dgb *DocumentGroupBy) Aggregate(fns ...AggregateFunc) *DocumentGroupBy {
// Scan applies the selector query and scans the result into the given value.
func (dgb *DocumentGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeDocument, "GroupBy")
ctx = setContextOp(ctx, dgb.build.ctx, "GroupBy")
if err := dgb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -669,7 +667,7 @@ func (ds *DocumentSelect) Aggregate(fns ...AggregateFunc) *DocumentSelect {
// Scan applies the selector query and scans the result into the given value.
func (ds *DocumentSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeDocument, "Select")
ctx = setContextOp(ctx, ds.ctx, "Select")
if err := ds.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -31,6 +31,7 @@ type (
Hook = ent.Hook
Value = ent.Value
Query = ent.Query
QueryContext = ent.QueryContext
Querier = ent.Querier
QuerierFunc = ent.QuerierFunc
Interceptor = ent.Interceptor
@@ -525,10 +526,11 @@ func withHooks[V Value, M any, PM interface {
return nv, nil
}
// newQueryContext returns a new context with the given QueryContext attached in case it does not exist.
func newQueryContext(ctx context.Context, typ, op string) context.Context {
// setContextOp returns a new context with the given QueryContext attached (including its op) in case it does not exist.
func setContextOp(ctx context.Context, qc *QueryContext, op string) context.Context {
if ent.QueryFromContext(ctx) == nil {
ctx = ent.NewQueryContext(ctx, &ent.QueryContext{Type: typ, Op: op})
qc.Op = op
ctx = ent.NewQueryContext(ctx, qc)
}
return ctx
}

View File

@@ -166,39 +166,39 @@ func (gr *Group) assignValues(columns []string, values []any) error {
// QueryUsers queries the "users" edge of the Group entity.
func (gr *Group) QueryUsers() *UserQuery {
return (&GroupClient{config: gr.config}).QueryUsers(gr)
return NewGroupClient(gr.config).QueryUsers(gr)
}
// QueryLocations queries the "locations" edge of the Group entity.
func (gr *Group) QueryLocations() *LocationQuery {
return (&GroupClient{config: gr.config}).QueryLocations(gr)
return NewGroupClient(gr.config).QueryLocations(gr)
}
// QueryItems queries the "items" edge of the Group entity.
func (gr *Group) QueryItems() *ItemQuery {
return (&GroupClient{config: gr.config}).QueryItems(gr)
return NewGroupClient(gr.config).QueryItems(gr)
}
// QueryLabels queries the "labels" edge of the Group entity.
func (gr *Group) QueryLabels() *LabelQuery {
return (&GroupClient{config: gr.config}).QueryLabels(gr)
return NewGroupClient(gr.config).QueryLabels(gr)
}
// QueryDocuments queries the "documents" edge of the Group entity.
func (gr *Group) QueryDocuments() *DocumentQuery {
return (&GroupClient{config: gr.config}).QueryDocuments(gr)
return NewGroupClient(gr.config).QueryDocuments(gr)
}
// QueryInvitationTokens queries the "invitation_tokens" edge of the Group entity.
func (gr *Group) QueryInvitationTokens() *GroupInvitationTokenQuery {
return (&GroupClient{config: gr.config}).QueryInvitationTokens(gr)
return NewGroupClient(gr.config).QueryInvitationTokens(gr)
}
// Update returns a builder for updating this Group.
// Note that you need to call Group.Unwrap() before calling this method if this Group
// was returned from a transaction, and the transaction was committed or rolled back.
func (gr *Group) Update() *GroupUpdateOne {
return (&GroupClient{config: gr.config}).UpdateOne(gr)
return NewGroupClient(gr.config).UpdateOne(gr)
}
// Unwrap unwraps the Group entity that was returned from a transaction after it was closed,

View File

@@ -131,6 +131,7 @@ const (
CurrencyDkk Currency = "dkk"
CurrencyInr Currency = "inr"
CurrencyRmb Currency = "rmb"
CurrencyBgn Currency = "bgn"
)
func (c Currency) String() string {
@@ -140,7 +141,7 @@ func (c Currency) String() string {
// CurrencyValidator is a validator for the "currency" field enum values. It is called by the builders before save.
func CurrencyValidator(c Currency) error {
switch c {
case CurrencyUsd, CurrencyEur, CurrencyGbp, CurrencyJpy, CurrencyZar, CurrencyAud, CurrencyNok, CurrencySek, CurrencyDkk, CurrencyInr, CurrencyRmb:
case CurrencyUsd, CurrencyEur, CurrencyGbp, CurrencyJpy, CurrencyZar, CurrencyAud, CurrencyNok, CurrencySek, CurrencyDkk, CurrencyInr, CurrencyRmb, CurrencyBgn:
return nil
default:
return fmt.Errorf("group: invalid enum value for currency field: %q", c)

View File

@@ -69,6 +69,12 @@ type GroupDeleteOne struct {
gd *GroupDelete
}
// Where appends a list predicates to the GroupDelete builder.
func (gdo *GroupDeleteOne) Where(ps ...predicate.Group) *GroupDeleteOne {
gdo.gd.mutation.Where(ps...)
return gdo
}
// Exec executes the deletion query.
func (gdo *GroupDeleteOne) Exec(ctx context.Context) error {
n, err := gdo.gd.Exec(ctx)
@@ -84,5 +90,7 @@ func (gdo *GroupDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (gdo *GroupDeleteOne) ExecX(ctx context.Context) {
gdo.gd.ExecX(ctx)
if err := gdo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -25,11 +25,8 @@ import (
// GroupQuery is the builder for querying Group entities.
type GroupQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.Group
withUsers *UserQuery
@@ -51,20 +48,20 @@ func (gq *GroupQuery) Where(ps ...predicate.Group) *GroupQuery {
// Limit the number of records to be returned by this query.
func (gq *GroupQuery) Limit(limit int) *GroupQuery {
gq.limit = &limit
gq.ctx.Limit = &limit
return gq
}
// Offset to start from.
func (gq *GroupQuery) Offset(offset int) *GroupQuery {
gq.offset = &offset
gq.ctx.Offset = &offset
return gq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (gq *GroupQuery) Unique(unique bool) *GroupQuery {
gq.unique = &unique
gq.ctx.Unique = &unique
return gq
}
@@ -209,7 +206,7 @@ func (gq *GroupQuery) QueryInvitationTokens() *GroupInvitationTokenQuery {
// First returns the first Group entity from the query.
// Returns a *NotFoundError when no Group was found.
func (gq *GroupQuery) First(ctx context.Context) (*Group, error) {
nodes, err := gq.Limit(1).All(newQueryContext(ctx, TypeGroup, "First"))
nodes, err := gq.Limit(1).All(setContextOp(ctx, gq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -232,7 +229,7 @@ func (gq *GroupQuery) FirstX(ctx context.Context) *Group {
// Returns a *NotFoundError when no Group ID was found.
func (gq *GroupQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = gq.Limit(1).IDs(newQueryContext(ctx, TypeGroup, "FirstID")); err != nil {
if ids, err = gq.Limit(1).IDs(setContextOp(ctx, gq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -255,7 +252,7 @@ func (gq *GroupQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one Group entity is found.
// Returns a *NotFoundError when no Group entities are found.
func (gq *GroupQuery) Only(ctx context.Context) (*Group, error) {
nodes, err := gq.Limit(2).All(newQueryContext(ctx, TypeGroup, "Only"))
nodes, err := gq.Limit(2).All(setContextOp(ctx, gq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -283,7 +280,7 @@ func (gq *GroupQuery) OnlyX(ctx context.Context) *Group {
// Returns a *NotFoundError when no entities are found.
func (gq *GroupQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = gq.Limit(2).IDs(newQueryContext(ctx, TypeGroup, "OnlyID")); err != nil {
if ids, err = gq.Limit(2).IDs(setContextOp(ctx, gq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -308,7 +305,7 @@ func (gq *GroupQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of Groups.
func (gq *GroupQuery) All(ctx context.Context) ([]*Group, error) {
ctx = newQueryContext(ctx, TypeGroup, "All")
ctx = setContextOp(ctx, gq.ctx, "All")
if err := gq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -328,7 +325,7 @@ func (gq *GroupQuery) AllX(ctx context.Context) []*Group {
// IDs executes the query and returns a list of Group IDs.
func (gq *GroupQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeGroup, "IDs")
ctx = setContextOp(ctx, gq.ctx, "IDs")
if err := gq.Select(group.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -346,7 +343,7 @@ func (gq *GroupQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (gq *GroupQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeGroup, "Count")
ctx = setContextOp(ctx, gq.ctx, "Count")
if err := gq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -364,7 +361,7 @@ func (gq *GroupQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (gq *GroupQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeGroup, "Exist")
ctx = setContextOp(ctx, gq.ctx, "Exist")
switch _, err := gq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -392,8 +389,7 @@ func (gq *GroupQuery) Clone() *GroupQuery {
}
return &GroupQuery{
config: gq.config,
limit: gq.limit,
offset: gq.offset,
ctx: gq.ctx.Clone(),
order: append([]OrderFunc{}, gq.order...),
inters: append([]Interceptor{}, gq.inters...),
predicates: append([]predicate.Group{}, gq.predicates...),
@@ -404,9 +400,8 @@ func (gq *GroupQuery) Clone() *GroupQuery {
withDocuments: gq.withDocuments.Clone(),
withInvitationTokens: gq.withInvitationTokens.Clone(),
// clone intermediate query.
sql: gq.sql.Clone(),
path: gq.path,
unique: gq.unique,
sql: gq.sql.Clone(),
path: gq.path,
}
}
@@ -491,9 +486,9 @@ func (gq *GroupQuery) WithInvitationTokens(opts ...func(*GroupInvitationTokenQue
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (gq *GroupQuery) GroupBy(field string, fields ...string) *GroupGroupBy {
gq.fields = append([]string{field}, fields...)
gq.ctx.Fields = append([]string{field}, fields...)
grbuild := &GroupGroupBy{build: gq}
grbuild.flds = &gq.fields
grbuild.flds = &gq.ctx.Fields
grbuild.label = group.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -512,10 +507,10 @@ func (gq *GroupQuery) GroupBy(field string, fields ...string) *GroupGroupBy {
// Select(group.FieldCreatedAt).
// Scan(ctx, &v)
func (gq *GroupQuery) Select(fields ...string) *GroupSelect {
gq.fields = append(gq.fields, fields...)
gq.ctx.Fields = append(gq.ctx.Fields, fields...)
sbuild := &GroupSelect{GroupQuery: gq}
sbuild.label = group.Label
sbuild.flds, sbuild.scan = &gq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &gq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -535,7 +530,7 @@ func (gq *GroupQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range gq.fields {
for _, f := range gq.ctx.Fields {
if !group.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -817,9 +812,9 @@ func (gq *GroupQuery) loadInvitationTokens(ctx context.Context, query *GroupInvi
func (gq *GroupQuery) sqlCount(ctx context.Context) (int, error) {
_spec := gq.querySpec()
_spec.Node.Columns = gq.fields
if len(gq.fields) > 0 {
_spec.Unique = gq.unique != nil && *gq.unique
_spec.Node.Columns = gq.ctx.Fields
if len(gq.ctx.Fields) > 0 {
_spec.Unique = gq.ctx.Unique != nil && *gq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, gq.driver, _spec)
}
@@ -837,10 +832,10 @@ func (gq *GroupQuery) querySpec() *sqlgraph.QuerySpec {
From: gq.sql,
Unique: true,
}
if unique := gq.unique; unique != nil {
if unique := gq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := gq.fields; len(fields) > 0 {
if fields := gq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, group.FieldID)
for i := range fields {
@@ -856,10 +851,10 @@ func (gq *GroupQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := gq.limit; limit != nil {
if limit := gq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := gq.offset; offset != nil {
if offset := gq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := gq.order; len(ps) > 0 {
@@ -875,7 +870,7 @@ func (gq *GroupQuery) querySpec() *sqlgraph.QuerySpec {
func (gq *GroupQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(gq.driver.Dialect())
t1 := builder.Table(group.Table)
columns := gq.fields
columns := gq.ctx.Fields
if len(columns) == 0 {
columns = group.Columns
}
@@ -884,7 +879,7 @@ func (gq *GroupQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = gq.sql
selector.Select(selector.Columns(columns...)...)
}
if gq.unique != nil && *gq.unique {
if gq.ctx.Unique != nil && *gq.ctx.Unique {
selector.Distinct()
}
for _, p := range gq.predicates {
@@ -893,12 +888,12 @@ func (gq *GroupQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range gq.order {
p(selector)
}
if offset := gq.offset; offset != nil {
if offset := gq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := gq.limit; limit != nil {
if limit := gq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -918,7 +913,7 @@ func (ggb *GroupGroupBy) Aggregate(fns ...AggregateFunc) *GroupGroupBy {
// Scan applies the selector query and scans the result into the given value.
func (ggb *GroupGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeGroup, "GroupBy")
ctx = setContextOp(ctx, ggb.build.ctx, "GroupBy")
if err := ggb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -966,7 +961,7 @@ func (gs *GroupSelect) Aggregate(fns ...AggregateFunc) *GroupSelect {
// Scan applies the selector query and scans the result into the given value.
func (gs *GroupSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeGroup, "Select")
ctx = setContextOp(ctx, gs.ctx, "Select")
if err := gs.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -136,14 +136,14 @@ func (git *GroupInvitationToken) assignValues(columns []string, values []any) er
// QueryGroup queries the "group" edge of the GroupInvitationToken entity.
func (git *GroupInvitationToken) QueryGroup() *GroupQuery {
return (&GroupInvitationTokenClient{config: git.config}).QueryGroup(git)
return NewGroupInvitationTokenClient(git.config).QueryGroup(git)
}
// Update returns a builder for updating this GroupInvitationToken.
// Note that you need to call GroupInvitationToken.Unwrap() before calling this method if this GroupInvitationToken
// was returned from a transaction, and the transaction was committed or rolled back.
func (git *GroupInvitationToken) Update() *GroupInvitationTokenUpdateOne {
return (&GroupInvitationTokenClient{config: git.config}).UpdateOne(git)
return NewGroupInvitationTokenClient(git.config).UpdateOne(git)
}
// Unwrap unwraps the GroupInvitationToken entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type GroupInvitationTokenDeleteOne struct {
gitd *GroupInvitationTokenDelete
}
// Where appends a list predicates to the GroupInvitationTokenDelete builder.
func (gitdo *GroupInvitationTokenDeleteOne) Where(ps ...predicate.GroupInvitationToken) *GroupInvitationTokenDeleteOne {
gitdo.gitd.mutation.Where(ps...)
return gitdo
}
// Exec executes the deletion query.
func (gitdo *GroupInvitationTokenDeleteOne) Exec(ctx context.Context) error {
n, err := gitdo.gitd.Exec(ctx)
@@ -84,5 +90,7 @@ func (gitdo *GroupInvitationTokenDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (gitdo *GroupInvitationTokenDeleteOne) ExecX(ctx context.Context) {
gitdo.gitd.ExecX(ctx)
if err := gitdo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -19,11 +19,8 @@ import (
// GroupInvitationTokenQuery is the builder for querying GroupInvitationToken entities.
type GroupInvitationTokenQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.GroupInvitationToken
withGroup *GroupQuery
@@ -41,20 +38,20 @@ func (gitq *GroupInvitationTokenQuery) Where(ps ...predicate.GroupInvitationToke
// Limit the number of records to be returned by this query.
func (gitq *GroupInvitationTokenQuery) Limit(limit int) *GroupInvitationTokenQuery {
gitq.limit = &limit
gitq.ctx.Limit = &limit
return gitq
}
// Offset to start from.
func (gitq *GroupInvitationTokenQuery) Offset(offset int) *GroupInvitationTokenQuery {
gitq.offset = &offset
gitq.ctx.Offset = &offset
return gitq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (gitq *GroupInvitationTokenQuery) Unique(unique bool) *GroupInvitationTokenQuery {
gitq.unique = &unique
gitq.ctx.Unique = &unique
return gitq
}
@@ -89,7 +86,7 @@ func (gitq *GroupInvitationTokenQuery) QueryGroup() *GroupQuery {
// First returns the first GroupInvitationToken entity from the query.
// Returns a *NotFoundError when no GroupInvitationToken was found.
func (gitq *GroupInvitationTokenQuery) First(ctx context.Context) (*GroupInvitationToken, error) {
nodes, err := gitq.Limit(1).All(newQueryContext(ctx, TypeGroupInvitationToken, "First"))
nodes, err := gitq.Limit(1).All(setContextOp(ctx, gitq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -112,7 +109,7 @@ func (gitq *GroupInvitationTokenQuery) FirstX(ctx context.Context) *GroupInvitat
// Returns a *NotFoundError when no GroupInvitationToken ID was found.
func (gitq *GroupInvitationTokenQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = gitq.Limit(1).IDs(newQueryContext(ctx, TypeGroupInvitationToken, "FirstID")); err != nil {
if ids, err = gitq.Limit(1).IDs(setContextOp(ctx, gitq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -135,7 +132,7 @@ func (gitq *GroupInvitationTokenQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one GroupInvitationToken entity is found.
// Returns a *NotFoundError when no GroupInvitationToken entities are found.
func (gitq *GroupInvitationTokenQuery) Only(ctx context.Context) (*GroupInvitationToken, error) {
nodes, err := gitq.Limit(2).All(newQueryContext(ctx, TypeGroupInvitationToken, "Only"))
nodes, err := gitq.Limit(2).All(setContextOp(ctx, gitq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -163,7 +160,7 @@ func (gitq *GroupInvitationTokenQuery) OnlyX(ctx context.Context) *GroupInvitati
// Returns a *NotFoundError when no entities are found.
func (gitq *GroupInvitationTokenQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = gitq.Limit(2).IDs(newQueryContext(ctx, TypeGroupInvitationToken, "OnlyID")); err != nil {
if ids, err = gitq.Limit(2).IDs(setContextOp(ctx, gitq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -188,7 +185,7 @@ func (gitq *GroupInvitationTokenQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of GroupInvitationTokens.
func (gitq *GroupInvitationTokenQuery) All(ctx context.Context) ([]*GroupInvitationToken, error) {
ctx = newQueryContext(ctx, TypeGroupInvitationToken, "All")
ctx = setContextOp(ctx, gitq.ctx, "All")
if err := gitq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -208,7 +205,7 @@ func (gitq *GroupInvitationTokenQuery) AllX(ctx context.Context) []*GroupInvitat
// IDs executes the query and returns a list of GroupInvitationToken IDs.
func (gitq *GroupInvitationTokenQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeGroupInvitationToken, "IDs")
ctx = setContextOp(ctx, gitq.ctx, "IDs")
if err := gitq.Select(groupinvitationtoken.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -226,7 +223,7 @@ func (gitq *GroupInvitationTokenQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (gitq *GroupInvitationTokenQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeGroupInvitationToken, "Count")
ctx = setContextOp(ctx, gitq.ctx, "Count")
if err := gitq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -244,7 +241,7 @@ func (gitq *GroupInvitationTokenQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (gitq *GroupInvitationTokenQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeGroupInvitationToken, "Exist")
ctx = setContextOp(ctx, gitq.ctx, "Exist")
switch _, err := gitq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -272,16 +269,14 @@ func (gitq *GroupInvitationTokenQuery) Clone() *GroupInvitationTokenQuery {
}
return &GroupInvitationTokenQuery{
config: gitq.config,
limit: gitq.limit,
offset: gitq.offset,
ctx: gitq.ctx.Clone(),
order: append([]OrderFunc{}, gitq.order...),
inters: append([]Interceptor{}, gitq.inters...),
predicates: append([]predicate.GroupInvitationToken{}, gitq.predicates...),
withGroup: gitq.withGroup.Clone(),
// clone intermediate query.
sql: gitq.sql.Clone(),
path: gitq.path,
unique: gitq.unique,
sql: gitq.sql.Clone(),
path: gitq.path,
}
}
@@ -311,9 +306,9 @@ func (gitq *GroupInvitationTokenQuery) WithGroup(opts ...func(*GroupQuery)) *Gro
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (gitq *GroupInvitationTokenQuery) GroupBy(field string, fields ...string) *GroupInvitationTokenGroupBy {
gitq.fields = append([]string{field}, fields...)
gitq.ctx.Fields = append([]string{field}, fields...)
grbuild := &GroupInvitationTokenGroupBy{build: gitq}
grbuild.flds = &gitq.fields
grbuild.flds = &gitq.ctx.Fields
grbuild.label = groupinvitationtoken.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -332,10 +327,10 @@ func (gitq *GroupInvitationTokenQuery) GroupBy(field string, fields ...string) *
// Select(groupinvitationtoken.FieldCreatedAt).
// Scan(ctx, &v)
func (gitq *GroupInvitationTokenQuery) Select(fields ...string) *GroupInvitationTokenSelect {
gitq.fields = append(gitq.fields, fields...)
gitq.ctx.Fields = append(gitq.ctx.Fields, fields...)
sbuild := &GroupInvitationTokenSelect{GroupInvitationTokenQuery: gitq}
sbuild.label = groupinvitationtoken.Label
sbuild.flds, sbuild.scan = &gitq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &gitq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -355,7 +350,7 @@ func (gitq *GroupInvitationTokenQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range gitq.fields {
for _, f := range gitq.ctx.Fields {
if !groupinvitationtoken.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -425,6 +420,9 @@ func (gitq *GroupInvitationTokenQuery) loadGroup(ctx context.Context, query *Gro
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(group.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -444,9 +442,9 @@ func (gitq *GroupInvitationTokenQuery) loadGroup(ctx context.Context, query *Gro
func (gitq *GroupInvitationTokenQuery) sqlCount(ctx context.Context) (int, error) {
_spec := gitq.querySpec()
_spec.Node.Columns = gitq.fields
if len(gitq.fields) > 0 {
_spec.Unique = gitq.unique != nil && *gitq.unique
_spec.Node.Columns = gitq.ctx.Fields
if len(gitq.ctx.Fields) > 0 {
_spec.Unique = gitq.ctx.Unique != nil && *gitq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, gitq.driver, _spec)
}
@@ -464,10 +462,10 @@ func (gitq *GroupInvitationTokenQuery) querySpec() *sqlgraph.QuerySpec {
From: gitq.sql,
Unique: true,
}
if unique := gitq.unique; unique != nil {
if unique := gitq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := gitq.fields; len(fields) > 0 {
if fields := gitq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, groupinvitationtoken.FieldID)
for i := range fields {
@@ -483,10 +481,10 @@ func (gitq *GroupInvitationTokenQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := gitq.limit; limit != nil {
if limit := gitq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := gitq.offset; offset != nil {
if offset := gitq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := gitq.order; len(ps) > 0 {
@@ -502,7 +500,7 @@ func (gitq *GroupInvitationTokenQuery) querySpec() *sqlgraph.QuerySpec {
func (gitq *GroupInvitationTokenQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(gitq.driver.Dialect())
t1 := builder.Table(groupinvitationtoken.Table)
columns := gitq.fields
columns := gitq.ctx.Fields
if len(columns) == 0 {
columns = groupinvitationtoken.Columns
}
@@ -511,7 +509,7 @@ func (gitq *GroupInvitationTokenQuery) sqlQuery(ctx context.Context) *sql.Select
selector = gitq.sql
selector.Select(selector.Columns(columns...)...)
}
if gitq.unique != nil && *gitq.unique {
if gitq.ctx.Unique != nil && *gitq.ctx.Unique {
selector.Distinct()
}
for _, p := range gitq.predicates {
@@ -520,12 +518,12 @@ func (gitq *GroupInvitationTokenQuery) sqlQuery(ctx context.Context) *sql.Select
for _, p := range gitq.order {
p(selector)
}
if offset := gitq.offset; offset != nil {
if offset := gitq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := gitq.limit; limit != nil {
if limit := gitq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -545,7 +543,7 @@ func (gitgb *GroupInvitationTokenGroupBy) Aggregate(fns ...AggregateFunc) *Group
// Scan applies the selector query and scans the result into the given value.
func (gitgb *GroupInvitationTokenGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeGroupInvitationToken, "GroupBy")
ctx = setContextOp(ctx, gitgb.build.ctx, "GroupBy")
if err := gitgb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -593,7 +591,7 @@ func (gits *GroupInvitationTokenSelect) Aggregate(fns ...AggregateFunc) *GroupIn
// Scan applies the selector query and scans the result into the given value.
func (gits *GroupInvitationTokenSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeGroupInvitationToken, "Select")
ctx = setContextOp(ctx, gits.ctx, "Select")
if err := gits.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -390,49 +390,49 @@ func (i *Item) assignValues(columns []string, values []any) error {
// QueryParent queries the "parent" edge of the Item entity.
func (i *Item) QueryParent() *ItemQuery {
return (&ItemClient{config: i.config}).QueryParent(i)
return NewItemClient(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)
return NewItemClient(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)
return NewItemClient(i.config).QueryGroup(i)
}
// QueryLabel queries the "label" edge of the Item entity.
func (i *Item) QueryLabel() *LabelQuery {
return (&ItemClient{config: i.config}).QueryLabel(i)
return NewItemClient(i.config).QueryLabel(i)
}
// QueryLocation queries the "location" edge of the Item entity.
func (i *Item) QueryLocation() *LocationQuery {
return (&ItemClient{config: i.config}).QueryLocation(i)
return NewItemClient(i.config).QueryLocation(i)
}
// QueryFields queries the "fields" edge of the Item entity.
func (i *Item) QueryFields() *ItemFieldQuery {
return (&ItemClient{config: i.config}).QueryFields(i)
return NewItemClient(i.config).QueryFields(i)
}
// QueryMaintenanceEntries queries the "maintenance_entries" edge of the Item entity.
func (i *Item) QueryMaintenanceEntries() *MaintenanceEntryQuery {
return (&ItemClient{config: i.config}).QueryMaintenanceEntries(i)
return NewItemClient(i.config).QueryMaintenanceEntries(i)
}
// QueryAttachments queries the "attachments" edge of the Item entity.
func (i *Item) QueryAttachments() *AttachmentQuery {
return (&ItemClient{config: i.config}).QueryAttachments(i)
return NewItemClient(i.config).QueryAttachments(i)
}
// Update returns a builder for updating this Item.
// Note that you need to call Item.Unwrap() before calling this method if this Item
// was returned from a transaction, and the transaction was committed or rolled back.
func (i *Item) Update() *ItemUpdateOne {
return (&ItemClient{config: i.config}).UpdateOne(i)
return NewItemClient(i.config).UpdateOne(i)
}
// Unwrap unwraps the Item entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type ItemDeleteOne struct {
id *ItemDelete
}
// Where appends a list predicates to the ItemDelete builder.
func (ido *ItemDeleteOne) Where(ps ...predicate.Item) *ItemDeleteOne {
ido.id.mutation.Where(ps...)
return ido
}
// Exec executes the deletion query.
func (ido *ItemDeleteOne) Exec(ctx context.Context) error {
n, err := ido.id.Exec(ctx)
@@ -84,5 +90,7 @@ func (ido *ItemDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (ido *ItemDeleteOne) ExecX(ctx context.Context) {
ido.id.ExecX(ctx)
if err := ido.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -25,11 +25,8 @@ import (
// ItemQuery is the builder for querying Item entities.
type ItemQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.Item
withParent *ItemQuery
@@ -54,20 +51,20 @@ func (iq *ItemQuery) Where(ps ...predicate.Item) *ItemQuery {
// Limit the number of records to be returned by this query.
func (iq *ItemQuery) Limit(limit int) *ItemQuery {
iq.limit = &limit
iq.ctx.Limit = &limit
return iq
}
// Offset to start from.
func (iq *ItemQuery) Offset(offset int) *ItemQuery {
iq.offset = &offset
iq.ctx.Offset = &offset
return iq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (iq *ItemQuery) Unique(unique bool) *ItemQuery {
iq.unique = &unique
iq.ctx.Unique = &unique
return iq
}
@@ -256,7 +253,7 @@ func (iq *ItemQuery) QueryAttachments() *AttachmentQuery {
// First returns the first Item entity from the query.
// Returns a *NotFoundError when no Item was found.
func (iq *ItemQuery) First(ctx context.Context) (*Item, error) {
nodes, err := iq.Limit(1).All(newQueryContext(ctx, TypeItem, "First"))
nodes, err := iq.Limit(1).All(setContextOp(ctx, iq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -279,7 +276,7 @@ func (iq *ItemQuery) FirstX(ctx context.Context) *Item {
// Returns a *NotFoundError when no Item ID was found.
func (iq *ItemQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = iq.Limit(1).IDs(newQueryContext(ctx, TypeItem, "FirstID")); err != nil {
if ids, err = iq.Limit(1).IDs(setContextOp(ctx, iq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -302,7 +299,7 @@ func (iq *ItemQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one Item entity is found.
// Returns a *NotFoundError when no Item entities are found.
func (iq *ItemQuery) Only(ctx context.Context) (*Item, error) {
nodes, err := iq.Limit(2).All(newQueryContext(ctx, TypeItem, "Only"))
nodes, err := iq.Limit(2).All(setContextOp(ctx, iq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -330,7 +327,7 @@ func (iq *ItemQuery) OnlyX(ctx context.Context) *Item {
// Returns a *NotFoundError when no entities are found.
func (iq *ItemQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = iq.Limit(2).IDs(newQueryContext(ctx, TypeItem, "OnlyID")); err != nil {
if ids, err = iq.Limit(2).IDs(setContextOp(ctx, iq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -355,7 +352,7 @@ func (iq *ItemQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of Items.
func (iq *ItemQuery) All(ctx context.Context) ([]*Item, error) {
ctx = newQueryContext(ctx, TypeItem, "All")
ctx = setContextOp(ctx, iq.ctx, "All")
if err := iq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -375,7 +372,7 @@ func (iq *ItemQuery) AllX(ctx context.Context) []*Item {
// IDs executes the query and returns a list of Item IDs.
func (iq *ItemQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeItem, "IDs")
ctx = setContextOp(ctx, iq.ctx, "IDs")
if err := iq.Select(item.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -393,7 +390,7 @@ func (iq *ItemQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (iq *ItemQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeItem, "Count")
ctx = setContextOp(ctx, iq.ctx, "Count")
if err := iq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -411,7 +408,7 @@ func (iq *ItemQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (iq *ItemQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeItem, "Exist")
ctx = setContextOp(ctx, iq.ctx, "Exist")
switch _, err := iq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -439,8 +436,7 @@ func (iq *ItemQuery) Clone() *ItemQuery {
}
return &ItemQuery{
config: iq.config,
limit: iq.limit,
offset: iq.offset,
ctx: iq.ctx.Clone(),
order: append([]OrderFunc{}, iq.order...),
inters: append([]Interceptor{}, iq.inters...),
predicates: append([]predicate.Item{}, iq.predicates...),
@@ -453,9 +449,8 @@ func (iq *ItemQuery) Clone() *ItemQuery {
withMaintenanceEntries: iq.withMaintenanceEntries.Clone(),
withAttachments: iq.withAttachments.Clone(),
// clone intermediate query.
sql: iq.sql.Clone(),
path: iq.path,
unique: iq.unique,
sql: iq.sql.Clone(),
path: iq.path,
}
}
@@ -562,9 +557,9 @@ func (iq *ItemQuery) WithAttachments(opts ...func(*AttachmentQuery)) *ItemQuery
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (iq *ItemQuery) GroupBy(field string, fields ...string) *ItemGroupBy {
iq.fields = append([]string{field}, fields...)
iq.ctx.Fields = append([]string{field}, fields...)
grbuild := &ItemGroupBy{build: iq}
grbuild.flds = &iq.fields
grbuild.flds = &iq.ctx.Fields
grbuild.label = item.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -583,10 +578,10 @@ func (iq *ItemQuery) GroupBy(field string, fields ...string) *ItemGroupBy {
// Select(item.FieldCreatedAt).
// Scan(ctx, &v)
func (iq *ItemQuery) Select(fields ...string) *ItemSelect {
iq.fields = append(iq.fields, fields...)
iq.ctx.Fields = append(iq.ctx.Fields, fields...)
sbuild := &ItemSelect{ItemQuery: iq}
sbuild.label = item.Label
sbuild.flds, sbuild.scan = &iq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &iq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -606,7 +601,7 @@ func (iq *ItemQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range iq.fields {
for _, f := range iq.ctx.Fields {
if !item.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -730,6 +725,9 @@ func (iq *ItemQuery) loadParent(ctx context.Context, query *ItemQuery, nodes []*
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(item.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -790,6 +788,9 @@ func (iq *ItemQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(group.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -829,27 +830,30 @@ func (iq *ItemQuery) loadLabel(ctx context.Context, query *LabelQuery, nodes []*
if err := query.prepareQuery(ctx); err != nil {
return err
}
neighbors, err := query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) {
assign := spec.Assign
values := spec.ScanValues
spec.ScanValues = func(columns []string) ([]any, error) {
values, err := values(columns[1:])
if err != nil {
return nil, err
qr := QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
return query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) {
assign := spec.Assign
values := spec.ScanValues
spec.ScanValues = func(columns []string) ([]any, error) {
values, err := values(columns[1:])
if err != nil {
return nil, err
}
return append([]any{new(uuid.UUID)}, values...), nil
}
return append([]any{new(uuid.UUID)}, values...), nil
}
spec.Assign = func(columns []string, values []any) error {
outValue := *values[0].(*uuid.UUID)
inValue := *values[1].(*uuid.UUID)
if nids[inValue] == nil {
nids[inValue] = map[*Item]struct{}{byID[outValue]: {}}
return assign(columns[1:], values[1:])
spec.Assign = func(columns []string, values []any) error {
outValue := *values[0].(*uuid.UUID)
inValue := *values[1].(*uuid.UUID)
if nids[inValue] == nil {
nids[inValue] = map[*Item]struct{}{byID[outValue]: {}}
return assign(columns[1:], values[1:])
}
nids[inValue][byID[outValue]] = struct{}{}
return nil
}
nids[inValue][byID[outValue]] = struct{}{}
return nil
}
})
})
neighbors, err := withInterceptors[[]*Label](ctx, query, qr, query.inters)
if err != nil {
return err
}
@@ -877,6 +881,9 @@ func (iq *ItemQuery) loadLocation(ctx context.Context, query *LocationQuery, nod
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(location.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -985,9 +992,9 @@ func (iq *ItemQuery) loadAttachments(ctx context.Context, query *AttachmentQuery
func (iq *ItemQuery) sqlCount(ctx context.Context) (int, error) {
_spec := iq.querySpec()
_spec.Node.Columns = iq.fields
if len(iq.fields) > 0 {
_spec.Unique = iq.unique != nil && *iq.unique
_spec.Node.Columns = iq.ctx.Fields
if len(iq.ctx.Fields) > 0 {
_spec.Unique = iq.ctx.Unique != nil && *iq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, iq.driver, _spec)
}
@@ -1005,10 +1012,10 @@ func (iq *ItemQuery) querySpec() *sqlgraph.QuerySpec {
From: iq.sql,
Unique: true,
}
if unique := iq.unique; unique != nil {
if unique := iq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := iq.fields; len(fields) > 0 {
if fields := iq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, item.FieldID)
for i := range fields {
@@ -1024,10 +1031,10 @@ func (iq *ItemQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := iq.limit; limit != nil {
if limit := iq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := iq.offset; offset != nil {
if offset := iq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := iq.order; len(ps) > 0 {
@@ -1043,7 +1050,7 @@ func (iq *ItemQuery) querySpec() *sqlgraph.QuerySpec {
func (iq *ItemQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(iq.driver.Dialect())
t1 := builder.Table(item.Table)
columns := iq.fields
columns := iq.ctx.Fields
if len(columns) == 0 {
columns = item.Columns
}
@@ -1052,7 +1059,7 @@ func (iq *ItemQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = iq.sql
selector.Select(selector.Columns(columns...)...)
}
if iq.unique != nil && *iq.unique {
if iq.ctx.Unique != nil && *iq.ctx.Unique {
selector.Distinct()
}
for _, p := range iq.predicates {
@@ -1061,12 +1068,12 @@ func (iq *ItemQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range iq.order {
p(selector)
}
if offset := iq.offset; offset != nil {
if offset := iq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := iq.limit; limit != nil {
if limit := iq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -1086,7 +1093,7 @@ func (igb *ItemGroupBy) Aggregate(fns ...AggregateFunc) *ItemGroupBy {
// Scan applies the selector query and scans the result into the given value.
func (igb *ItemGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeItem, "GroupBy")
ctx = setContextOp(ctx, igb.build.ctx, "GroupBy")
if err := igb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -1134,7 +1141,7 @@ func (is *ItemSelect) Aggregate(fns ...AggregateFunc) *ItemSelect {
// Scan applies the selector query and scans the result into the given value.
func (is *ItemSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeItem, "Select")
ctx = setContextOp(ctx, is.ctx, "Select")
if err := is.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -170,14 +170,14 @@ func (_if *ItemField) assignValues(columns []string, values []any) error {
// QueryItem queries the "item" edge of the ItemField entity.
func (_if *ItemField) QueryItem() *ItemQuery {
return (&ItemFieldClient{config: _if.config}).QueryItem(_if)
return NewItemFieldClient(_if.config).QueryItem(_if)
}
// Update returns a builder for updating this ItemField.
// Note that you need to call ItemField.Unwrap() before calling this method if this ItemField
// was returned from a transaction, and the transaction was committed or rolled back.
func (_if *ItemField) Update() *ItemFieldUpdateOne {
return (&ItemFieldClient{config: _if.config}).UpdateOne(_if)
return NewItemFieldClient(_if.config).UpdateOne(_if)
}
// Unwrap unwraps the ItemField entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type ItemFieldDeleteOne struct {
ifd *ItemFieldDelete
}
// Where appends a list predicates to the ItemFieldDelete builder.
func (ifdo *ItemFieldDeleteOne) Where(ps ...predicate.ItemField) *ItemFieldDeleteOne {
ifdo.ifd.mutation.Where(ps...)
return ifdo
}
// Exec executes the deletion query.
func (ifdo *ItemFieldDeleteOne) Exec(ctx context.Context) error {
n, err := ifdo.ifd.Exec(ctx)
@@ -84,5 +90,7 @@ func (ifdo *ItemFieldDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (ifdo *ItemFieldDeleteOne) ExecX(ctx context.Context) {
ifdo.ifd.ExecX(ctx)
if err := ifdo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -19,11 +19,8 @@ import (
// ItemFieldQuery is the builder for querying ItemField entities.
type ItemFieldQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.ItemField
withItem *ItemQuery
@@ -41,20 +38,20 @@ func (ifq *ItemFieldQuery) Where(ps ...predicate.ItemField) *ItemFieldQuery {
// Limit the number of records to be returned by this query.
func (ifq *ItemFieldQuery) Limit(limit int) *ItemFieldQuery {
ifq.limit = &limit
ifq.ctx.Limit = &limit
return ifq
}
// Offset to start from.
func (ifq *ItemFieldQuery) Offset(offset int) *ItemFieldQuery {
ifq.offset = &offset
ifq.ctx.Offset = &offset
return ifq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (ifq *ItemFieldQuery) Unique(unique bool) *ItemFieldQuery {
ifq.unique = &unique
ifq.ctx.Unique = &unique
return ifq
}
@@ -89,7 +86,7 @@ func (ifq *ItemFieldQuery) QueryItem() *ItemQuery {
// First returns the first ItemField entity from the query.
// Returns a *NotFoundError when no ItemField was found.
func (ifq *ItemFieldQuery) First(ctx context.Context) (*ItemField, error) {
nodes, err := ifq.Limit(1).All(newQueryContext(ctx, TypeItemField, "First"))
nodes, err := ifq.Limit(1).All(setContextOp(ctx, ifq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -112,7 +109,7 @@ func (ifq *ItemFieldQuery) FirstX(ctx context.Context) *ItemField {
// Returns a *NotFoundError when no ItemField ID was found.
func (ifq *ItemFieldQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = ifq.Limit(1).IDs(newQueryContext(ctx, TypeItemField, "FirstID")); err != nil {
if ids, err = ifq.Limit(1).IDs(setContextOp(ctx, ifq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -135,7 +132,7 @@ func (ifq *ItemFieldQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one ItemField entity is found.
// Returns a *NotFoundError when no ItemField entities are found.
func (ifq *ItemFieldQuery) Only(ctx context.Context) (*ItemField, error) {
nodes, err := ifq.Limit(2).All(newQueryContext(ctx, TypeItemField, "Only"))
nodes, err := ifq.Limit(2).All(setContextOp(ctx, ifq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -163,7 +160,7 @@ func (ifq *ItemFieldQuery) OnlyX(ctx context.Context) *ItemField {
// Returns a *NotFoundError when no entities are found.
func (ifq *ItemFieldQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = ifq.Limit(2).IDs(newQueryContext(ctx, TypeItemField, "OnlyID")); err != nil {
if ids, err = ifq.Limit(2).IDs(setContextOp(ctx, ifq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -188,7 +185,7 @@ func (ifq *ItemFieldQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of ItemFields.
func (ifq *ItemFieldQuery) All(ctx context.Context) ([]*ItemField, error) {
ctx = newQueryContext(ctx, TypeItemField, "All")
ctx = setContextOp(ctx, ifq.ctx, "All")
if err := ifq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -208,7 +205,7 @@ func (ifq *ItemFieldQuery) AllX(ctx context.Context) []*ItemField {
// IDs executes the query and returns a list of ItemField IDs.
func (ifq *ItemFieldQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeItemField, "IDs")
ctx = setContextOp(ctx, ifq.ctx, "IDs")
if err := ifq.Select(itemfield.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -226,7 +223,7 @@ func (ifq *ItemFieldQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (ifq *ItemFieldQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeItemField, "Count")
ctx = setContextOp(ctx, ifq.ctx, "Count")
if err := ifq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -244,7 +241,7 @@ func (ifq *ItemFieldQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (ifq *ItemFieldQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeItemField, "Exist")
ctx = setContextOp(ctx, ifq.ctx, "Exist")
switch _, err := ifq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -272,16 +269,14 @@ func (ifq *ItemFieldQuery) Clone() *ItemFieldQuery {
}
return &ItemFieldQuery{
config: ifq.config,
limit: ifq.limit,
offset: ifq.offset,
ctx: ifq.ctx.Clone(),
order: append([]OrderFunc{}, ifq.order...),
inters: append([]Interceptor{}, ifq.inters...),
predicates: append([]predicate.ItemField{}, ifq.predicates...),
withItem: ifq.withItem.Clone(),
// clone intermediate query.
sql: ifq.sql.Clone(),
path: ifq.path,
unique: ifq.unique,
sql: ifq.sql.Clone(),
path: ifq.path,
}
}
@@ -311,9 +306,9 @@ func (ifq *ItemFieldQuery) WithItem(opts ...func(*ItemQuery)) *ItemFieldQuery {
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (ifq *ItemFieldQuery) GroupBy(field string, fields ...string) *ItemFieldGroupBy {
ifq.fields = append([]string{field}, fields...)
ifq.ctx.Fields = append([]string{field}, fields...)
grbuild := &ItemFieldGroupBy{build: ifq}
grbuild.flds = &ifq.fields
grbuild.flds = &ifq.ctx.Fields
grbuild.label = itemfield.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -332,10 +327,10 @@ func (ifq *ItemFieldQuery) GroupBy(field string, fields ...string) *ItemFieldGro
// Select(itemfield.FieldCreatedAt).
// Scan(ctx, &v)
func (ifq *ItemFieldQuery) Select(fields ...string) *ItemFieldSelect {
ifq.fields = append(ifq.fields, fields...)
ifq.ctx.Fields = append(ifq.ctx.Fields, fields...)
sbuild := &ItemFieldSelect{ItemFieldQuery: ifq}
sbuild.label = itemfield.Label
sbuild.flds, sbuild.scan = &ifq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &ifq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -355,7 +350,7 @@ func (ifq *ItemFieldQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range ifq.fields {
for _, f := range ifq.ctx.Fields {
if !itemfield.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -425,6 +420,9 @@ func (ifq *ItemFieldQuery) loadItem(ctx context.Context, query *ItemQuery, nodes
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(item.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -444,9 +442,9 @@ func (ifq *ItemFieldQuery) loadItem(ctx context.Context, query *ItemQuery, nodes
func (ifq *ItemFieldQuery) sqlCount(ctx context.Context) (int, error) {
_spec := ifq.querySpec()
_spec.Node.Columns = ifq.fields
if len(ifq.fields) > 0 {
_spec.Unique = ifq.unique != nil && *ifq.unique
_spec.Node.Columns = ifq.ctx.Fields
if len(ifq.ctx.Fields) > 0 {
_spec.Unique = ifq.ctx.Unique != nil && *ifq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, ifq.driver, _spec)
}
@@ -464,10 +462,10 @@ func (ifq *ItemFieldQuery) querySpec() *sqlgraph.QuerySpec {
From: ifq.sql,
Unique: true,
}
if unique := ifq.unique; unique != nil {
if unique := ifq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := ifq.fields; len(fields) > 0 {
if fields := ifq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, itemfield.FieldID)
for i := range fields {
@@ -483,10 +481,10 @@ func (ifq *ItemFieldQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := ifq.limit; limit != nil {
if limit := ifq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := ifq.offset; offset != nil {
if offset := ifq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := ifq.order; len(ps) > 0 {
@@ -502,7 +500,7 @@ func (ifq *ItemFieldQuery) querySpec() *sqlgraph.QuerySpec {
func (ifq *ItemFieldQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(ifq.driver.Dialect())
t1 := builder.Table(itemfield.Table)
columns := ifq.fields
columns := ifq.ctx.Fields
if len(columns) == 0 {
columns = itemfield.Columns
}
@@ -511,7 +509,7 @@ func (ifq *ItemFieldQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = ifq.sql
selector.Select(selector.Columns(columns...)...)
}
if ifq.unique != nil && *ifq.unique {
if ifq.ctx.Unique != nil && *ifq.ctx.Unique {
selector.Distinct()
}
for _, p := range ifq.predicates {
@@ -520,12 +518,12 @@ func (ifq *ItemFieldQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range ifq.order {
p(selector)
}
if offset := ifq.offset; offset != nil {
if offset := ifq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := ifq.limit; limit != nil {
if limit := ifq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -545,7 +543,7 @@ func (ifgb *ItemFieldGroupBy) Aggregate(fns ...AggregateFunc) *ItemFieldGroupBy
// Scan applies the selector query and scans the result into the given value.
func (ifgb *ItemFieldGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeItemField, "GroupBy")
ctx = setContextOp(ctx, ifgb.build.ctx, "GroupBy")
if err := ifgb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -593,7 +591,7 @@ func (ifs *ItemFieldSelect) Aggregate(fns ...AggregateFunc) *ItemFieldSelect {
// Scan applies the selector query and scans the result into the given value.
func (ifs *ItemFieldSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeItemField, "Select")
ctx = setContextOp(ctx, ifs.ctx, "Select")
if err := ifs.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -145,19 +145,19 @@ func (l *Label) assignValues(columns []string, values []any) error {
// QueryGroup queries the "group" edge of the Label entity.
func (l *Label) QueryGroup() *GroupQuery {
return (&LabelClient{config: l.config}).QueryGroup(l)
return NewLabelClient(l.config).QueryGroup(l)
}
// QueryItems queries the "items" edge of the Label entity.
func (l *Label) QueryItems() *ItemQuery {
return (&LabelClient{config: l.config}).QueryItems(l)
return NewLabelClient(l.config).QueryItems(l)
}
// Update returns a builder for updating this Label.
// Note that you need to call Label.Unwrap() before calling this method if this Label
// was returned from a transaction, and the transaction was committed or rolled back.
func (l *Label) Update() *LabelUpdateOne {
return (&LabelClient{config: l.config}).UpdateOne(l)
return NewLabelClient(l.config).UpdateOne(l)
}
// Unwrap unwraps the Label entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type LabelDeleteOne struct {
ld *LabelDelete
}
// Where appends a list predicates to the LabelDelete builder.
func (ldo *LabelDeleteOne) Where(ps ...predicate.Label) *LabelDeleteOne {
ldo.ld.mutation.Where(ps...)
return ldo
}
// Exec executes the deletion query.
func (ldo *LabelDeleteOne) Exec(ctx context.Context) error {
n, err := ldo.ld.Exec(ctx)
@@ -84,5 +90,7 @@ func (ldo *LabelDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (ldo *LabelDeleteOne) ExecX(ctx context.Context) {
ldo.ld.ExecX(ctx)
if err := ldo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -21,11 +21,8 @@ import (
// LabelQuery is the builder for querying Label entities.
type LabelQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.Label
withGroup *GroupQuery
@@ -44,20 +41,20 @@ func (lq *LabelQuery) Where(ps ...predicate.Label) *LabelQuery {
// Limit the number of records to be returned by this query.
func (lq *LabelQuery) Limit(limit int) *LabelQuery {
lq.limit = &limit
lq.ctx.Limit = &limit
return lq
}
// Offset to start from.
func (lq *LabelQuery) Offset(offset int) *LabelQuery {
lq.offset = &offset
lq.ctx.Offset = &offset
return lq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (lq *LabelQuery) Unique(unique bool) *LabelQuery {
lq.unique = &unique
lq.ctx.Unique = &unique
return lq
}
@@ -114,7 +111,7 @@ func (lq *LabelQuery) QueryItems() *ItemQuery {
// First returns the first Label entity from the query.
// Returns a *NotFoundError when no Label was found.
func (lq *LabelQuery) First(ctx context.Context) (*Label, error) {
nodes, err := lq.Limit(1).All(newQueryContext(ctx, TypeLabel, "First"))
nodes, err := lq.Limit(1).All(setContextOp(ctx, lq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -137,7 +134,7 @@ func (lq *LabelQuery) FirstX(ctx context.Context) *Label {
// Returns a *NotFoundError when no Label ID was found.
func (lq *LabelQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = lq.Limit(1).IDs(newQueryContext(ctx, TypeLabel, "FirstID")); err != nil {
if ids, err = lq.Limit(1).IDs(setContextOp(ctx, lq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -160,7 +157,7 @@ func (lq *LabelQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one Label entity is found.
// Returns a *NotFoundError when no Label entities are found.
func (lq *LabelQuery) Only(ctx context.Context) (*Label, error) {
nodes, err := lq.Limit(2).All(newQueryContext(ctx, TypeLabel, "Only"))
nodes, err := lq.Limit(2).All(setContextOp(ctx, lq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -188,7 +185,7 @@ func (lq *LabelQuery) OnlyX(ctx context.Context) *Label {
// Returns a *NotFoundError when no entities are found.
func (lq *LabelQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = lq.Limit(2).IDs(newQueryContext(ctx, TypeLabel, "OnlyID")); err != nil {
if ids, err = lq.Limit(2).IDs(setContextOp(ctx, lq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -213,7 +210,7 @@ func (lq *LabelQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of Labels.
func (lq *LabelQuery) All(ctx context.Context) ([]*Label, error) {
ctx = newQueryContext(ctx, TypeLabel, "All")
ctx = setContextOp(ctx, lq.ctx, "All")
if err := lq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -233,7 +230,7 @@ func (lq *LabelQuery) AllX(ctx context.Context) []*Label {
// IDs executes the query and returns a list of Label IDs.
func (lq *LabelQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeLabel, "IDs")
ctx = setContextOp(ctx, lq.ctx, "IDs")
if err := lq.Select(label.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -251,7 +248,7 @@ func (lq *LabelQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (lq *LabelQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeLabel, "Count")
ctx = setContextOp(ctx, lq.ctx, "Count")
if err := lq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -269,7 +266,7 @@ func (lq *LabelQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (lq *LabelQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeLabel, "Exist")
ctx = setContextOp(ctx, lq.ctx, "Exist")
switch _, err := lq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -297,17 +294,15 @@ func (lq *LabelQuery) Clone() *LabelQuery {
}
return &LabelQuery{
config: lq.config,
limit: lq.limit,
offset: lq.offset,
ctx: lq.ctx.Clone(),
order: append([]OrderFunc{}, lq.order...),
inters: append([]Interceptor{}, lq.inters...),
predicates: append([]predicate.Label{}, lq.predicates...),
withGroup: lq.withGroup.Clone(),
withItems: lq.withItems.Clone(),
// clone intermediate query.
sql: lq.sql.Clone(),
path: lq.path,
unique: lq.unique,
sql: lq.sql.Clone(),
path: lq.path,
}
}
@@ -348,9 +343,9 @@ func (lq *LabelQuery) WithItems(opts ...func(*ItemQuery)) *LabelQuery {
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (lq *LabelQuery) GroupBy(field string, fields ...string) *LabelGroupBy {
lq.fields = append([]string{field}, fields...)
lq.ctx.Fields = append([]string{field}, fields...)
grbuild := &LabelGroupBy{build: lq}
grbuild.flds = &lq.fields
grbuild.flds = &lq.ctx.Fields
grbuild.label = label.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -369,10 +364,10 @@ func (lq *LabelQuery) GroupBy(field string, fields ...string) *LabelGroupBy {
// Select(label.FieldCreatedAt).
// Scan(ctx, &v)
func (lq *LabelQuery) Select(fields ...string) *LabelSelect {
lq.fields = append(lq.fields, fields...)
lq.ctx.Fields = append(lq.ctx.Fields, fields...)
sbuild := &LabelSelect{LabelQuery: lq}
sbuild.label = label.Label
sbuild.flds, sbuild.scan = &lq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &lq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -392,7 +387,7 @@ func (lq *LabelQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range lq.fields {
for _, f := range lq.ctx.Fields {
if !label.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -470,6 +465,9 @@ func (lq *LabelQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(group.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -509,27 +507,30 @@ func (lq *LabelQuery) loadItems(ctx context.Context, query *ItemQuery, nodes []*
if err := query.prepareQuery(ctx); err != nil {
return err
}
neighbors, err := query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) {
assign := spec.Assign
values := spec.ScanValues
spec.ScanValues = func(columns []string) ([]any, error) {
values, err := values(columns[1:])
if err != nil {
return nil, err
qr := QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
return query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) {
assign := spec.Assign
values := spec.ScanValues
spec.ScanValues = func(columns []string) ([]any, error) {
values, err := values(columns[1:])
if err != nil {
return nil, err
}
return append([]any{new(uuid.UUID)}, values...), nil
}
return append([]any{new(uuid.UUID)}, values...), nil
}
spec.Assign = func(columns []string, values []any) error {
outValue := *values[0].(*uuid.UUID)
inValue := *values[1].(*uuid.UUID)
if nids[inValue] == nil {
nids[inValue] = map[*Label]struct{}{byID[outValue]: {}}
return assign(columns[1:], values[1:])
spec.Assign = func(columns []string, values []any) error {
outValue := *values[0].(*uuid.UUID)
inValue := *values[1].(*uuid.UUID)
if nids[inValue] == nil {
nids[inValue] = map[*Label]struct{}{byID[outValue]: {}}
return assign(columns[1:], values[1:])
}
nids[inValue][byID[outValue]] = struct{}{}
return nil
}
nids[inValue][byID[outValue]] = struct{}{}
return nil
}
})
})
neighbors, err := withInterceptors[[]*Item](ctx, query, qr, query.inters)
if err != nil {
return err
}
@@ -547,9 +548,9 @@ func (lq *LabelQuery) loadItems(ctx context.Context, query *ItemQuery, nodes []*
func (lq *LabelQuery) sqlCount(ctx context.Context) (int, error) {
_spec := lq.querySpec()
_spec.Node.Columns = lq.fields
if len(lq.fields) > 0 {
_spec.Unique = lq.unique != nil && *lq.unique
_spec.Node.Columns = lq.ctx.Fields
if len(lq.ctx.Fields) > 0 {
_spec.Unique = lq.ctx.Unique != nil && *lq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, lq.driver, _spec)
}
@@ -567,10 +568,10 @@ func (lq *LabelQuery) querySpec() *sqlgraph.QuerySpec {
From: lq.sql,
Unique: true,
}
if unique := lq.unique; unique != nil {
if unique := lq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := lq.fields; len(fields) > 0 {
if fields := lq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, label.FieldID)
for i := range fields {
@@ -586,10 +587,10 @@ func (lq *LabelQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := lq.limit; limit != nil {
if limit := lq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := lq.offset; offset != nil {
if offset := lq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := lq.order; len(ps) > 0 {
@@ -605,7 +606,7 @@ func (lq *LabelQuery) querySpec() *sqlgraph.QuerySpec {
func (lq *LabelQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(lq.driver.Dialect())
t1 := builder.Table(label.Table)
columns := lq.fields
columns := lq.ctx.Fields
if len(columns) == 0 {
columns = label.Columns
}
@@ -614,7 +615,7 @@ func (lq *LabelQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = lq.sql
selector.Select(selector.Columns(columns...)...)
}
if lq.unique != nil && *lq.unique {
if lq.ctx.Unique != nil && *lq.ctx.Unique {
selector.Distinct()
}
for _, p := range lq.predicates {
@@ -623,12 +624,12 @@ func (lq *LabelQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range lq.order {
p(selector)
}
if offset := lq.offset; offset != nil {
if offset := lq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := lq.limit; limit != nil {
if limit := lq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -648,7 +649,7 @@ func (lgb *LabelGroupBy) Aggregate(fns ...AggregateFunc) *LabelGroupBy {
// Scan applies the selector query and scans the result into the given value.
func (lgb *LabelGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeLabel, "GroupBy")
ctx = setContextOp(ctx, lgb.build.ctx, "GroupBy")
if err := lgb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -696,7 +697,7 @@ func (ls *LabelSelect) Aggregate(fns ...AggregateFunc) *LabelSelect {
// Scan applies the selector query and scans the result into the given value.
func (ls *LabelSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeLabel, "Select")
ctx = setContextOp(ctx, ls.ctx, "Select")
if err := ls.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -173,29 +173,29 @@ func (l *Location) assignValues(columns []string, values []any) error {
// QueryParent queries the "parent" edge of the Location entity.
func (l *Location) QueryParent() *LocationQuery {
return (&LocationClient{config: l.config}).QueryParent(l)
return NewLocationClient(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)
return NewLocationClient(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)
return NewLocationClient(l.config).QueryGroup(l)
}
// QueryItems queries the "items" edge of the Location entity.
func (l *Location) QueryItems() *ItemQuery {
return (&LocationClient{config: l.config}).QueryItems(l)
return NewLocationClient(l.config).QueryItems(l)
}
// Update returns a builder for updating this Location.
// Note that you need to call Location.Unwrap() before calling this method if this Location
// was returned from a transaction, and the transaction was committed or rolled back.
func (l *Location) Update() *LocationUpdateOne {
return (&LocationClient{config: l.config}).UpdateOne(l)
return NewLocationClient(l.config).UpdateOne(l)
}
// Unwrap unwraps the Location entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type LocationDeleteOne struct {
ld *LocationDelete
}
// Where appends a list predicates to the LocationDelete builder.
func (ldo *LocationDeleteOne) Where(ps ...predicate.Location) *LocationDeleteOne {
ldo.ld.mutation.Where(ps...)
return ldo
}
// Exec executes the deletion query.
func (ldo *LocationDeleteOne) Exec(ctx context.Context) error {
n, err := ldo.ld.Exec(ctx)
@@ -84,5 +90,7 @@ func (ldo *LocationDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (ldo *LocationDeleteOne) ExecX(ctx context.Context) {
ldo.ld.ExecX(ctx)
if err := ldo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -21,11 +21,8 @@ import (
// LocationQuery is the builder for querying Location entities.
type LocationQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.Location
withParent *LocationQuery
@@ -46,20 +43,20 @@ func (lq *LocationQuery) Where(ps ...predicate.Location) *LocationQuery {
// Limit the number of records to be returned by this query.
func (lq *LocationQuery) Limit(limit int) *LocationQuery {
lq.limit = &limit
lq.ctx.Limit = &limit
return lq
}
// Offset to start from.
func (lq *LocationQuery) Offset(offset int) *LocationQuery {
lq.offset = &offset
lq.ctx.Offset = &offset
return lq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (lq *LocationQuery) Unique(unique bool) *LocationQuery {
lq.unique = &unique
lq.ctx.Unique = &unique
return lq
}
@@ -160,7 +157,7 @@ func (lq *LocationQuery) QueryItems() *ItemQuery {
// First returns the first Location entity from the query.
// Returns a *NotFoundError when no Location was found.
func (lq *LocationQuery) First(ctx context.Context) (*Location, error) {
nodes, err := lq.Limit(1).All(newQueryContext(ctx, TypeLocation, "First"))
nodes, err := lq.Limit(1).All(setContextOp(ctx, lq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -183,7 +180,7 @@ func (lq *LocationQuery) FirstX(ctx context.Context) *Location {
// Returns a *NotFoundError when no Location ID was found.
func (lq *LocationQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = lq.Limit(1).IDs(newQueryContext(ctx, TypeLocation, "FirstID")); err != nil {
if ids, err = lq.Limit(1).IDs(setContextOp(ctx, lq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -206,7 +203,7 @@ func (lq *LocationQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one Location entity is found.
// Returns a *NotFoundError when no Location entities are found.
func (lq *LocationQuery) Only(ctx context.Context) (*Location, error) {
nodes, err := lq.Limit(2).All(newQueryContext(ctx, TypeLocation, "Only"))
nodes, err := lq.Limit(2).All(setContextOp(ctx, lq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -234,7 +231,7 @@ func (lq *LocationQuery) OnlyX(ctx context.Context) *Location {
// Returns a *NotFoundError when no entities are found.
func (lq *LocationQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = lq.Limit(2).IDs(newQueryContext(ctx, TypeLocation, "OnlyID")); err != nil {
if ids, err = lq.Limit(2).IDs(setContextOp(ctx, lq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -259,7 +256,7 @@ func (lq *LocationQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of Locations.
func (lq *LocationQuery) All(ctx context.Context) ([]*Location, error) {
ctx = newQueryContext(ctx, TypeLocation, "All")
ctx = setContextOp(ctx, lq.ctx, "All")
if err := lq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -279,7 +276,7 @@ func (lq *LocationQuery) AllX(ctx context.Context) []*Location {
// IDs executes the query and returns a list of Location IDs.
func (lq *LocationQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeLocation, "IDs")
ctx = setContextOp(ctx, lq.ctx, "IDs")
if err := lq.Select(location.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -297,7 +294,7 @@ func (lq *LocationQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (lq *LocationQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeLocation, "Count")
ctx = setContextOp(ctx, lq.ctx, "Count")
if err := lq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -315,7 +312,7 @@ func (lq *LocationQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (lq *LocationQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeLocation, "Exist")
ctx = setContextOp(ctx, lq.ctx, "Exist")
switch _, err := lq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -343,8 +340,7 @@ func (lq *LocationQuery) Clone() *LocationQuery {
}
return &LocationQuery{
config: lq.config,
limit: lq.limit,
offset: lq.offset,
ctx: lq.ctx.Clone(),
order: append([]OrderFunc{}, lq.order...),
inters: append([]Interceptor{}, lq.inters...),
predicates: append([]predicate.Location{}, lq.predicates...),
@@ -353,9 +349,8 @@ func (lq *LocationQuery) Clone() *LocationQuery {
withGroup: lq.withGroup.Clone(),
withItems: lq.withItems.Clone(),
// clone intermediate query.
sql: lq.sql.Clone(),
path: lq.path,
unique: lq.unique,
sql: lq.sql.Clone(),
path: lq.path,
}
}
@@ -418,9 +413,9 @@ func (lq *LocationQuery) WithItems(opts ...func(*ItemQuery)) *LocationQuery {
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (lq *LocationQuery) GroupBy(field string, fields ...string) *LocationGroupBy {
lq.fields = append([]string{field}, fields...)
lq.ctx.Fields = append([]string{field}, fields...)
grbuild := &LocationGroupBy{build: lq}
grbuild.flds = &lq.fields
grbuild.flds = &lq.ctx.Fields
grbuild.label = location.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -439,10 +434,10 @@ func (lq *LocationQuery) GroupBy(field string, fields ...string) *LocationGroupB
// Select(location.FieldCreatedAt).
// Scan(ctx, &v)
func (lq *LocationQuery) Select(fields ...string) *LocationSelect {
lq.fields = append(lq.fields, fields...)
lq.ctx.Fields = append(lq.ctx.Fields, fields...)
sbuild := &LocationSelect{LocationQuery: lq}
sbuild.label = location.Label
sbuild.flds, sbuild.scan = &lq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &lq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -462,7 +457,7 @@ func (lq *LocationQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range lq.fields {
for _, f := range lq.ctx.Fields {
if !location.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -555,6 +550,9 @@ func (lq *LocationQuery) loadParent(ctx context.Context, query *LocationQuery, n
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(location.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -615,6 +613,9 @@ func (lq *LocationQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(group.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -665,9 +666,9 @@ func (lq *LocationQuery) loadItems(ctx context.Context, query *ItemQuery, nodes
func (lq *LocationQuery) sqlCount(ctx context.Context) (int, error) {
_spec := lq.querySpec()
_spec.Node.Columns = lq.fields
if len(lq.fields) > 0 {
_spec.Unique = lq.unique != nil && *lq.unique
_spec.Node.Columns = lq.ctx.Fields
if len(lq.ctx.Fields) > 0 {
_spec.Unique = lq.ctx.Unique != nil && *lq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, lq.driver, _spec)
}
@@ -685,10 +686,10 @@ func (lq *LocationQuery) querySpec() *sqlgraph.QuerySpec {
From: lq.sql,
Unique: true,
}
if unique := lq.unique; unique != nil {
if unique := lq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := lq.fields; len(fields) > 0 {
if fields := lq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, location.FieldID)
for i := range fields {
@@ -704,10 +705,10 @@ func (lq *LocationQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := lq.limit; limit != nil {
if limit := lq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := lq.offset; offset != nil {
if offset := lq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := lq.order; len(ps) > 0 {
@@ -723,7 +724,7 @@ func (lq *LocationQuery) querySpec() *sqlgraph.QuerySpec {
func (lq *LocationQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(lq.driver.Dialect())
t1 := builder.Table(location.Table)
columns := lq.fields
columns := lq.ctx.Fields
if len(columns) == 0 {
columns = location.Columns
}
@@ -732,7 +733,7 @@ func (lq *LocationQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = lq.sql
selector.Select(selector.Columns(columns...)...)
}
if lq.unique != nil && *lq.unique {
if lq.ctx.Unique != nil && *lq.ctx.Unique {
selector.Distinct()
}
for _, p := range lq.predicates {
@@ -741,12 +742,12 @@ func (lq *LocationQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range lq.order {
p(selector)
}
if offset := lq.offset; offset != nil {
if offset := lq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := lq.limit; limit != nil {
if limit := lq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -766,7 +767,7 @@ func (lgb *LocationGroupBy) Aggregate(fns ...AggregateFunc) *LocationGroupBy {
// Scan applies the selector query and scans the result into the given value.
func (lgb *LocationGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeLocation, "GroupBy")
ctx = setContextOp(ctx, lgb.build.ctx, "GroupBy")
if err := lgb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -814,7 +815,7 @@ func (ls *LocationSelect) Aggregate(fns ...AggregateFunc) *LocationSelect {
// Scan applies the selector query and scans the result into the given value.
func (ls *LocationSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeLocation, "Select")
ctx = setContextOp(ctx, ls.ctx, "Select")
if err := ls.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -142,14 +142,14 @@ func (me *MaintenanceEntry) assignValues(columns []string, values []any) error {
// QueryItem queries the "item" edge of the MaintenanceEntry entity.
func (me *MaintenanceEntry) QueryItem() *ItemQuery {
return (&MaintenanceEntryClient{config: me.config}).QueryItem(me)
return NewMaintenanceEntryClient(me.config).QueryItem(me)
}
// Update returns a builder for updating this MaintenanceEntry.
// Note that you need to call MaintenanceEntry.Unwrap() before calling this method if this MaintenanceEntry
// was returned from a transaction, and the transaction was committed or rolled back.
func (me *MaintenanceEntry) Update() *MaintenanceEntryUpdateOne {
return (&MaintenanceEntryClient{config: me.config}).UpdateOne(me)
return NewMaintenanceEntryClient(me.config).UpdateOne(me)
}
// Unwrap unwraps the MaintenanceEntry entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type MaintenanceEntryDeleteOne struct {
med *MaintenanceEntryDelete
}
// Where appends a list predicates to the MaintenanceEntryDelete builder.
func (medo *MaintenanceEntryDeleteOne) Where(ps ...predicate.MaintenanceEntry) *MaintenanceEntryDeleteOne {
medo.med.mutation.Where(ps...)
return medo
}
// Exec executes the deletion query.
func (medo *MaintenanceEntryDeleteOne) Exec(ctx context.Context) error {
n, err := medo.med.Exec(ctx)
@@ -84,5 +90,7 @@ func (medo *MaintenanceEntryDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (medo *MaintenanceEntryDeleteOne) ExecX(ctx context.Context) {
medo.med.ExecX(ctx)
if err := medo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -19,11 +19,8 @@ import (
// MaintenanceEntryQuery is the builder for querying MaintenanceEntry entities.
type MaintenanceEntryQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.MaintenanceEntry
withItem *ItemQuery
@@ -40,20 +37,20 @@ func (meq *MaintenanceEntryQuery) Where(ps ...predicate.MaintenanceEntry) *Maint
// Limit the number of records to be returned by this query.
func (meq *MaintenanceEntryQuery) Limit(limit int) *MaintenanceEntryQuery {
meq.limit = &limit
meq.ctx.Limit = &limit
return meq
}
// Offset to start from.
func (meq *MaintenanceEntryQuery) Offset(offset int) *MaintenanceEntryQuery {
meq.offset = &offset
meq.ctx.Offset = &offset
return meq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (meq *MaintenanceEntryQuery) Unique(unique bool) *MaintenanceEntryQuery {
meq.unique = &unique
meq.ctx.Unique = &unique
return meq
}
@@ -88,7 +85,7 @@ func (meq *MaintenanceEntryQuery) QueryItem() *ItemQuery {
// First returns the first MaintenanceEntry entity from the query.
// Returns a *NotFoundError when no MaintenanceEntry was found.
func (meq *MaintenanceEntryQuery) First(ctx context.Context) (*MaintenanceEntry, error) {
nodes, err := meq.Limit(1).All(newQueryContext(ctx, TypeMaintenanceEntry, "First"))
nodes, err := meq.Limit(1).All(setContextOp(ctx, meq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -111,7 +108,7 @@ func (meq *MaintenanceEntryQuery) FirstX(ctx context.Context) *MaintenanceEntry
// Returns a *NotFoundError when no MaintenanceEntry ID was found.
func (meq *MaintenanceEntryQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = meq.Limit(1).IDs(newQueryContext(ctx, TypeMaintenanceEntry, "FirstID")); err != nil {
if ids, err = meq.Limit(1).IDs(setContextOp(ctx, meq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -134,7 +131,7 @@ func (meq *MaintenanceEntryQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one MaintenanceEntry entity is found.
// Returns a *NotFoundError when no MaintenanceEntry entities are found.
func (meq *MaintenanceEntryQuery) Only(ctx context.Context) (*MaintenanceEntry, error) {
nodes, err := meq.Limit(2).All(newQueryContext(ctx, TypeMaintenanceEntry, "Only"))
nodes, err := meq.Limit(2).All(setContextOp(ctx, meq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -162,7 +159,7 @@ func (meq *MaintenanceEntryQuery) OnlyX(ctx context.Context) *MaintenanceEntry {
// Returns a *NotFoundError when no entities are found.
func (meq *MaintenanceEntryQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = meq.Limit(2).IDs(newQueryContext(ctx, TypeMaintenanceEntry, "OnlyID")); err != nil {
if ids, err = meq.Limit(2).IDs(setContextOp(ctx, meq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -187,7 +184,7 @@ func (meq *MaintenanceEntryQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of MaintenanceEntries.
func (meq *MaintenanceEntryQuery) All(ctx context.Context) ([]*MaintenanceEntry, error) {
ctx = newQueryContext(ctx, TypeMaintenanceEntry, "All")
ctx = setContextOp(ctx, meq.ctx, "All")
if err := meq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -207,7 +204,7 @@ func (meq *MaintenanceEntryQuery) AllX(ctx context.Context) []*MaintenanceEntry
// IDs executes the query and returns a list of MaintenanceEntry IDs.
func (meq *MaintenanceEntryQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeMaintenanceEntry, "IDs")
ctx = setContextOp(ctx, meq.ctx, "IDs")
if err := meq.Select(maintenanceentry.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -225,7 +222,7 @@ func (meq *MaintenanceEntryQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (meq *MaintenanceEntryQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeMaintenanceEntry, "Count")
ctx = setContextOp(ctx, meq.ctx, "Count")
if err := meq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -243,7 +240,7 @@ func (meq *MaintenanceEntryQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (meq *MaintenanceEntryQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeMaintenanceEntry, "Exist")
ctx = setContextOp(ctx, meq.ctx, "Exist")
switch _, err := meq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -271,16 +268,14 @@ func (meq *MaintenanceEntryQuery) Clone() *MaintenanceEntryQuery {
}
return &MaintenanceEntryQuery{
config: meq.config,
limit: meq.limit,
offset: meq.offset,
ctx: meq.ctx.Clone(),
order: append([]OrderFunc{}, meq.order...),
inters: append([]Interceptor{}, meq.inters...),
predicates: append([]predicate.MaintenanceEntry{}, meq.predicates...),
withItem: meq.withItem.Clone(),
// clone intermediate query.
sql: meq.sql.Clone(),
path: meq.path,
unique: meq.unique,
sql: meq.sql.Clone(),
path: meq.path,
}
}
@@ -310,9 +305,9 @@ func (meq *MaintenanceEntryQuery) WithItem(opts ...func(*ItemQuery)) *Maintenanc
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (meq *MaintenanceEntryQuery) GroupBy(field string, fields ...string) *MaintenanceEntryGroupBy {
meq.fields = append([]string{field}, fields...)
meq.ctx.Fields = append([]string{field}, fields...)
grbuild := &MaintenanceEntryGroupBy{build: meq}
grbuild.flds = &meq.fields
grbuild.flds = &meq.ctx.Fields
grbuild.label = maintenanceentry.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -331,10 +326,10 @@ func (meq *MaintenanceEntryQuery) GroupBy(field string, fields ...string) *Maint
// Select(maintenanceentry.FieldCreatedAt).
// Scan(ctx, &v)
func (meq *MaintenanceEntryQuery) Select(fields ...string) *MaintenanceEntrySelect {
meq.fields = append(meq.fields, fields...)
meq.ctx.Fields = append(meq.ctx.Fields, fields...)
sbuild := &MaintenanceEntrySelect{MaintenanceEntryQuery: meq}
sbuild.label = maintenanceentry.Label
sbuild.flds, sbuild.scan = &meq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &meq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -354,7 +349,7 @@ func (meq *MaintenanceEntryQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range meq.fields {
for _, f := range meq.ctx.Fields {
if !maintenanceentry.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -414,6 +409,9 @@ func (meq *MaintenanceEntryQuery) loadItem(ctx context.Context, query *ItemQuery
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(item.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -433,9 +431,9 @@ func (meq *MaintenanceEntryQuery) loadItem(ctx context.Context, query *ItemQuery
func (meq *MaintenanceEntryQuery) sqlCount(ctx context.Context) (int, error) {
_spec := meq.querySpec()
_spec.Node.Columns = meq.fields
if len(meq.fields) > 0 {
_spec.Unique = meq.unique != nil && *meq.unique
_spec.Node.Columns = meq.ctx.Fields
if len(meq.ctx.Fields) > 0 {
_spec.Unique = meq.ctx.Unique != nil && *meq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, meq.driver, _spec)
}
@@ -453,10 +451,10 @@ func (meq *MaintenanceEntryQuery) querySpec() *sqlgraph.QuerySpec {
From: meq.sql,
Unique: true,
}
if unique := meq.unique; unique != nil {
if unique := meq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := meq.fields; len(fields) > 0 {
if fields := meq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, maintenanceentry.FieldID)
for i := range fields {
@@ -472,10 +470,10 @@ func (meq *MaintenanceEntryQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := meq.limit; limit != nil {
if limit := meq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := meq.offset; offset != nil {
if offset := meq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := meq.order; len(ps) > 0 {
@@ -491,7 +489,7 @@ func (meq *MaintenanceEntryQuery) querySpec() *sqlgraph.QuerySpec {
func (meq *MaintenanceEntryQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(meq.driver.Dialect())
t1 := builder.Table(maintenanceentry.Table)
columns := meq.fields
columns := meq.ctx.Fields
if len(columns) == 0 {
columns = maintenanceentry.Columns
}
@@ -500,7 +498,7 @@ func (meq *MaintenanceEntryQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = meq.sql
selector.Select(selector.Columns(columns...)...)
}
if meq.unique != nil && *meq.unique {
if meq.ctx.Unique != nil && *meq.ctx.Unique {
selector.Distinct()
}
for _, p := range meq.predicates {
@@ -509,12 +507,12 @@ func (meq *MaintenanceEntryQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range meq.order {
p(selector)
}
if offset := meq.offset; offset != nil {
if offset := meq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := meq.limit; limit != nil {
if limit := meq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -534,7 +532,7 @@ func (megb *MaintenanceEntryGroupBy) Aggregate(fns ...AggregateFunc) *Maintenanc
// Scan applies the selector query and scans the result into the given value.
func (megb *MaintenanceEntryGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeMaintenanceEntry, "GroupBy")
ctx = setContextOp(ctx, megb.build.ctx, "GroupBy")
if err := megb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -582,7 +580,7 @@ func (mes *MaintenanceEntrySelect) Aggregate(fns ...AggregateFunc) *MaintenanceE
// Scan applies the selector query and scans the result into the given value.
func (mes *MaintenanceEntrySelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeMaintenanceEntry, "Select")
ctx = setContextOp(ctx, mes.ctx, "Select")
if err := mes.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -116,7 +116,7 @@ var (
{Name: "created_at", Type: field.TypeTime},
{Name: "updated_at", Type: field.TypeTime},
{Name: "name", Type: field.TypeString, Size: 255},
{Name: "currency", Type: field.TypeEnum, Enums: []string{"usd", "eur", "gbp", "jpy", "zar", "aud", "nok", "sek", "dkk", "inr", "rmb"}, Default: "usd"},
{Name: "currency", Type: field.TypeEnum, Enums: []string{"usd", "eur", "gbp", "jpy", "zar", "aud", "nok", "sek", "dkk", "inr", "rmb", "bgn"}, Default: "usd"},
}
// GroupsTable holds the schema information for the "groups" table.
GroupsTable = &schema.Table{

View File

@@ -5,6 +5,6 @@ package runtime
// The schema-stitching logic is generated in github.com/hay-kot/homebox/backend/internal/data/ent/runtime.go
const (
Version = "v0.11.5" // Version of ent codegen.
Sum = "h1:V2qhG91C4PMQTa82Q4StoESMQ4dzkMNeStCzszxi0jQ=" // Sum of ent codegen.
Version = "v0.11.7" // Version of ent codegen.
Sum = "h1:V+wKFh0jhAbY/FoU+PPbdMOf2Ma5vh07R/IdF+N/nFg=" // Sum of ent codegen.
)

View File

@@ -27,7 +27,7 @@ func (Group) Fields() []ent.Field {
NotEmpty(),
field.Enum("currency").
Default("usd").
Values("usd", "eur", "gbp", "jpy", "zar", "aud", "nok", "sek", "dkk", "inr", "rmb"),
Values("usd", "eur", "gbp", "jpy", "zar", "aud", "nok", "sek", "dkk", "inr", "rmb", "bgn"),
}
}

View File

@@ -179,19 +179,19 @@ func (u *User) assignValues(columns []string, values []any) error {
// QueryGroup queries the "group" edge of the User entity.
func (u *User) QueryGroup() *GroupQuery {
return (&UserClient{config: u.config}).QueryGroup(u)
return NewUserClient(u.config).QueryGroup(u)
}
// QueryAuthTokens queries the "auth_tokens" edge of the User entity.
func (u *User) QueryAuthTokens() *AuthTokensQuery {
return (&UserClient{config: u.config}).QueryAuthTokens(u)
return NewUserClient(u.config).QueryAuthTokens(u)
}
// Update returns a builder for updating this User.
// Note that you need to call User.Unwrap() before calling this method if this User
// was returned from a transaction, and the transaction was committed or rolled back.
func (u *User) Update() *UserUpdateOne {
return (&UserClient{config: u.config}).UpdateOne(u)
return NewUserClient(u.config).UpdateOne(u)
}
// Unwrap unwraps the User entity that was returned from a transaction after it was closed,

View File

@@ -69,6 +69,12 @@ type UserDeleteOne struct {
ud *UserDelete
}
// Where appends a list predicates to the UserDelete builder.
func (udo *UserDeleteOne) Where(ps ...predicate.User) *UserDeleteOne {
udo.ud.mutation.Where(ps...)
return udo
}
// Exec executes the deletion query.
func (udo *UserDeleteOne) Exec(ctx context.Context) error {
n, err := udo.ud.Exec(ctx)
@@ -84,5 +90,7 @@ func (udo *UserDeleteOne) Exec(ctx context.Context) error {
// ExecX is like Exec, but panics if an error occurs.
func (udo *UserDeleteOne) ExecX(ctx context.Context) {
udo.ud.ExecX(ctx)
if err := udo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -21,11 +21,8 @@ import (
// UserQuery is the builder for querying User entities.
type UserQuery struct {
config
limit *int
offset *int
unique *bool
ctx *QueryContext
order []OrderFunc
fields []string
inters []Interceptor
predicates []predicate.User
withGroup *GroupQuery
@@ -44,20 +41,20 @@ func (uq *UserQuery) Where(ps ...predicate.User) *UserQuery {
// Limit the number of records to be returned by this query.
func (uq *UserQuery) Limit(limit int) *UserQuery {
uq.limit = &limit
uq.ctx.Limit = &limit
return uq
}
// Offset to start from.
func (uq *UserQuery) Offset(offset int) *UserQuery {
uq.offset = &offset
uq.ctx.Offset = &offset
return uq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (uq *UserQuery) Unique(unique bool) *UserQuery {
uq.unique = &unique
uq.ctx.Unique = &unique
return uq
}
@@ -114,7 +111,7 @@ func (uq *UserQuery) QueryAuthTokens() *AuthTokensQuery {
// First returns the first User entity from the query.
// Returns a *NotFoundError when no User was found.
func (uq *UserQuery) First(ctx context.Context) (*User, error) {
nodes, err := uq.Limit(1).All(newQueryContext(ctx, TypeUser, "First"))
nodes, err := uq.Limit(1).All(setContextOp(ctx, uq.ctx, "First"))
if err != nil {
return nil, err
}
@@ -137,7 +134,7 @@ func (uq *UserQuery) FirstX(ctx context.Context) *User {
// Returns a *NotFoundError when no User ID was found.
func (uq *UserQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = uq.Limit(1).IDs(newQueryContext(ctx, TypeUser, "FirstID")); err != nil {
if ids, err = uq.Limit(1).IDs(setContextOp(ctx, uq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
@@ -160,7 +157,7 @@ func (uq *UserQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Returns a *NotSingularError when more than one User entity is found.
// Returns a *NotFoundError when no User entities are found.
func (uq *UserQuery) Only(ctx context.Context) (*User, error) {
nodes, err := uq.Limit(2).All(newQueryContext(ctx, TypeUser, "Only"))
nodes, err := uq.Limit(2).All(setContextOp(ctx, uq.ctx, "Only"))
if err != nil {
return nil, err
}
@@ -188,7 +185,7 @@ func (uq *UserQuery) OnlyX(ctx context.Context) *User {
// Returns a *NotFoundError when no entities are found.
func (uq *UserQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = uq.Limit(2).IDs(newQueryContext(ctx, TypeUser, "OnlyID")); err != nil {
if ids, err = uq.Limit(2).IDs(setContextOp(ctx, uq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
@@ -213,7 +210,7 @@ func (uq *UserQuery) OnlyIDX(ctx context.Context) uuid.UUID {
// All executes the query and returns a list of Users.
func (uq *UserQuery) All(ctx context.Context) ([]*User, error) {
ctx = newQueryContext(ctx, TypeUser, "All")
ctx = setContextOp(ctx, uq.ctx, "All")
if err := uq.prepareQuery(ctx); err != nil {
return nil, err
}
@@ -233,7 +230,7 @@ func (uq *UserQuery) AllX(ctx context.Context) []*User {
// IDs executes the query and returns a list of User IDs.
func (uq *UserQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
var ids []uuid.UUID
ctx = newQueryContext(ctx, TypeUser, "IDs")
ctx = setContextOp(ctx, uq.ctx, "IDs")
if err := uq.Select(user.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
@@ -251,7 +248,7 @@ func (uq *UserQuery) IDsX(ctx context.Context) []uuid.UUID {
// Count returns the count of the given query.
func (uq *UserQuery) Count(ctx context.Context) (int, error) {
ctx = newQueryContext(ctx, TypeUser, "Count")
ctx = setContextOp(ctx, uq.ctx, "Count")
if err := uq.prepareQuery(ctx); err != nil {
return 0, err
}
@@ -269,7 +266,7 @@ func (uq *UserQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph.
func (uq *UserQuery) Exist(ctx context.Context) (bool, error) {
ctx = newQueryContext(ctx, TypeUser, "Exist")
ctx = setContextOp(ctx, uq.ctx, "Exist")
switch _, err := uq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
@@ -297,17 +294,15 @@ func (uq *UserQuery) Clone() *UserQuery {
}
return &UserQuery{
config: uq.config,
limit: uq.limit,
offset: uq.offset,
ctx: uq.ctx.Clone(),
order: append([]OrderFunc{}, uq.order...),
inters: append([]Interceptor{}, uq.inters...),
predicates: append([]predicate.User{}, uq.predicates...),
withGroup: uq.withGroup.Clone(),
withAuthTokens: uq.withAuthTokens.Clone(),
// clone intermediate query.
sql: uq.sql.Clone(),
path: uq.path,
unique: uq.unique,
sql: uq.sql.Clone(),
path: uq.path,
}
}
@@ -348,9 +343,9 @@ func (uq *UserQuery) WithAuthTokens(opts ...func(*AuthTokensQuery)) *UserQuery {
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (uq *UserQuery) GroupBy(field string, fields ...string) *UserGroupBy {
uq.fields = append([]string{field}, fields...)
uq.ctx.Fields = append([]string{field}, fields...)
grbuild := &UserGroupBy{build: uq}
grbuild.flds = &uq.fields
grbuild.flds = &uq.ctx.Fields
grbuild.label = user.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -369,10 +364,10 @@ func (uq *UserQuery) GroupBy(field string, fields ...string) *UserGroupBy {
// Select(user.FieldCreatedAt).
// Scan(ctx, &v)
func (uq *UserQuery) Select(fields ...string) *UserSelect {
uq.fields = append(uq.fields, fields...)
uq.ctx.Fields = append(uq.ctx.Fields, fields...)
sbuild := &UserSelect{UserQuery: uq}
sbuild.label = user.Label
sbuild.flds, sbuild.scan = &uq.fields, sbuild.Scan
sbuild.flds, sbuild.scan = &uq.ctx.Fields, sbuild.Scan
return sbuild
}
@@ -392,7 +387,7 @@ func (uq *UserQuery) prepareQuery(ctx context.Context) error {
}
}
}
for _, f := range uq.fields {
for _, f := range uq.ctx.Fields {
if !user.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
@@ -470,6 +465,9 @@ func (uq *UserQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(group.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
@@ -520,9 +518,9 @@ func (uq *UserQuery) loadAuthTokens(ctx context.Context, query *AuthTokensQuery,
func (uq *UserQuery) sqlCount(ctx context.Context) (int, error) {
_spec := uq.querySpec()
_spec.Node.Columns = uq.fields
if len(uq.fields) > 0 {
_spec.Unique = uq.unique != nil && *uq.unique
_spec.Node.Columns = uq.ctx.Fields
if len(uq.ctx.Fields) > 0 {
_spec.Unique = uq.ctx.Unique != nil && *uq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, uq.driver, _spec)
}
@@ -540,10 +538,10 @@ func (uq *UserQuery) querySpec() *sqlgraph.QuerySpec {
From: uq.sql,
Unique: true,
}
if unique := uq.unique; unique != nil {
if unique := uq.ctx.Unique; unique != nil {
_spec.Unique = *unique
}
if fields := uq.fields; len(fields) > 0 {
if fields := uq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, user.FieldID)
for i := range fields {
@@ -559,10 +557,10 @@ func (uq *UserQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if limit := uq.limit; limit != nil {
if limit := uq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := uq.offset; offset != nil {
if offset := uq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := uq.order; len(ps) > 0 {
@@ -578,7 +576,7 @@ func (uq *UserQuery) querySpec() *sqlgraph.QuerySpec {
func (uq *UserQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(uq.driver.Dialect())
t1 := builder.Table(user.Table)
columns := uq.fields
columns := uq.ctx.Fields
if len(columns) == 0 {
columns = user.Columns
}
@@ -587,7 +585,7 @@ func (uq *UserQuery) sqlQuery(ctx context.Context) *sql.Selector {
selector = uq.sql
selector.Select(selector.Columns(columns...)...)
}
if uq.unique != nil && *uq.unique {
if uq.ctx.Unique != nil && *uq.ctx.Unique {
selector.Distinct()
}
for _, p := range uq.predicates {
@@ -596,12 +594,12 @@ func (uq *UserQuery) sqlQuery(ctx context.Context) *sql.Selector {
for _, p := range uq.order {
p(selector)
}
if offset := uq.offset; offset != nil {
if offset := uq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := uq.limit; limit != nil {
if limit := uq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -621,7 +619,7 @@ func (ugb *UserGroupBy) Aggregate(fns ...AggregateFunc) *UserGroupBy {
// Scan applies the selector query and scans the result into the given value.
func (ugb *UserGroupBy) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeUser, "GroupBy")
ctx = setContextOp(ctx, ugb.build.ctx, "GroupBy")
if err := ugb.build.prepareQuery(ctx); err != nil {
return err
}
@@ -669,7 +667,7 @@ func (us *UserSelect) Aggregate(fns ...AggregateFunc) *UserSelect {
// Scan applies the selector query and scans the result into the given value.
func (us *UserSelect) Scan(ctx context.Context, v any) error {
ctx = newQueryContext(ctx, TypeUser, "Select")
ctx = setContextOp(ctx, us.ctx, "Select")
if err := us.prepareQuery(ctx); err != nil {
return err
}

View File

@@ -8,11 +8,34 @@ import (
type AssetID int
func (aid AssetID) Nil() bool {
return aid.Int() <= 0
}
func (aid AssetID) Int() int {
return int(aid)
}
func ParseAssetIDBytes(d []byte) (AID AssetID, ok bool) {
d = bytes.Replace(d, []byte(`"`), []byte(``), -1)
d = bytes.Replace(d, []byte(`-`), []byte(``), -1)
aidInt, err := strconv.Atoi(string(d))
if err != nil {
return AssetID(-1), false
}
return AssetID(aidInt), true
}
func ParseAssetID(s string) (AID AssetID, ok bool) {
return ParseAssetIDBytes([]byte(s))
}
func (aid AssetID) MarshalJSON() ([]byte, error) {
aidStr := fmt.Sprintf("%06d", aid)
aidStr = fmt.Sprintf("%s-%s", aidStr[:3], aidStr[3:])
return []byte(fmt.Sprintf(`"%s"`, aidStr)), nil
}
func (aid *AssetID) UnmarshalJSON(d []byte) error {
@@ -26,5 +49,4 @@ func (aid *AssetID) UnmarshalJSON(d []byte) error {
*aid = AssetID(aidInt)
return nil
}

View File

@@ -2,6 +2,7 @@ package repo
import (
"context"
"fmt"
"time"
"github.com/google/uuid"
@@ -19,14 +20,21 @@ type ItemsRepository struct {
}
type (
FieldQuery struct {
Name string
Value string
}
ItemQuery struct {
Page int
PageSize int
Search string `json:"search"`
AssetID AssetID `json:"assetId"`
LocationIDs []uuid.UUID `json:"locationIds"`
LabelIDs []uuid.UUID `json:"labelIds"`
SortBy string `json:"sortBy"`
IncludeArchived bool `json:"includeArchived"`
Fields []FieldQuery
}
ItemField struct {
@@ -177,7 +185,8 @@ func mapItemSummary(item *ent.Item) ItemSummary {
}
var (
mapItemOutErr = mapTErrFunc(mapItemOut)
mapItemOutErr = mapTErrFunc(mapItemOut)
mapItemsOutErr = mapTEachErrFunc(mapItemOut)
)
func mapFields(fields []*ent.ItemField) []ItemField {
@@ -300,22 +309,6 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite
qb = qb.Where(item.Archived(false))
}
if len(q.LabelIDs) > 0 {
labels := make([]predicate.Item, 0, len(q.LabelIDs))
for _, l := range q.LabelIDs {
labels = append(labels, item.HasLabelWith(label.ID(l)))
}
qb = qb.Where(item.Or(labels...))
}
if len(q.LocationIDs) > 0 {
locations := make([]predicate.Item, 0, len(q.LocationIDs))
for _, l := range q.LocationIDs {
locations = append(locations, item.HasLocationWith(location.ID(l)))
}
qb = qb.Where(item.Or(locations...))
}
if q.Search != "" {
qb.Where(
item.Or(
@@ -326,7 +319,58 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite
)
}
if !q.AssetID.Nil() {
qb = qb.Where(item.AssetID(q.AssetID.Int()))
}
// Filters within this block define a AND relationship where each subset
// of filters is OR'd together.
//
// The goal is to allow matches like where the item has
// - one of the selected labels AND
// - one of the selected locations AND
// - one of the selected fields key/value matches
var andPredicates []predicate.Item
{
if len(q.LabelIDs) > 0 {
labelPredicates := make([]predicate.Item, 0, len(q.LabelIDs))
for _, l := range q.LabelIDs {
labelPredicates = append(labelPredicates, item.HasLabelWith(label.ID(l)))
}
andPredicates = append(andPredicates, item.Or(labelPredicates...))
}
if len(q.LocationIDs) > 0 {
locationPredicates := make([]predicate.Item, 0, len(q.LocationIDs))
for _, l := range q.LocationIDs {
locationPredicates = append(locationPredicates, item.HasLocationWith(location.ID(l)))
}
andPredicates = append(andPredicates, item.Or(locationPredicates...))
}
if len(q.Fields) > 0 {
fieldPredicates := make([]predicate.Item, 0, len(q.Fields))
for _, f := range q.Fields {
fieldPredicates = append(fieldPredicates, item.HasFieldsWith(
itemfield.And(
itemfield.Name(f.Name),
itemfield.TextValue(f.Value),
),
))
}
andPredicates = append(andPredicates, item.Or(fieldPredicates...))
}
}
if len(andPredicates) > 0 {
qb = qb.Where(item.And(andPredicates...))
}
count, err := qb.Count(ctx)
if err != nil {
return PaginationResult[ItemSummary]{}, err
}
@@ -356,7 +400,6 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite
}
// QueryByAssetID returns items by asset ID. If the item does not exist, an error is returned.
func (e *ItemsRepository) QueryByAssetID(ctx context.Context, gid uuid.UUID, assetID AssetID, page int, pageSize int) (PaginationResult[ItemSummary], error) {
qb := e.db.Item.Query().Where(
@@ -372,7 +415,7 @@ func (e *ItemsRepository) QueryByAssetID(ctx context.Context, gid uuid.UUID, ass
pageSize = -1
}
items, err := mapItemsSummaryErr(
items, err := mapItemsSummaryErr(
qb.Order(ent.Asc(item.FieldName)).
WithLabel().
WithLocation().
@@ -392,8 +435,8 @@ func (e *ItemsRepository) QueryByAssetID(ctx context.Context, gid uuid.UUID, ass
}
// GetAll returns all the items in the database with the Labels and Locations eager loaded.
func (e *ItemsRepository) GetAll(ctx context.Context, gid uuid.UUID) ([]ItemSummary, error) {
return mapItemsSummaryErr(e.db.Item.Query().
func (e *ItemsRepository) GetAll(ctx context.Context, gid uuid.UUID) ([]ItemOut, error) {
return mapItemsOutErr(e.db.Item.Query().
Where(item.HasGroupWith(group.ID(gid))).
WithLabel().
WithLocation().
@@ -474,8 +517,8 @@ func (e *ItemsRepository) DeleteByGroup(ctx context.Context, gid, id uuid.UUID)
return err
}
func (e *ItemsRepository) UpdateByGroup(ctx context.Context, gid uuid.UUID, data ItemUpdate) (ItemOut, error) {
q := e.db.Item.Update().Where(item.ID(data.ID), item.HasGroupWith(group.ID(gid))).
func (e *ItemsRepository) UpdateByGroup(ctx context.Context, GID uuid.UUID, data ItemUpdate) (ItemOut, error) {
q := e.db.Item.Update().Where(item.ID(data.ID), item.HasGroupWith(group.ID(GID))).
SetName(data.Name).
SetDescription(data.Description).
SetLocationID(data.LocationID).
@@ -588,3 +631,115 @@ func (e *ItemsRepository) UpdateByGroup(ctx context.Context, gid uuid.UUID, data
return e.GetOne(ctx, data.ID)
}
func (e *ItemsRepository) GetAllCustomFieldValues(ctx context.Context, GID uuid.UUID, name string) ([]string, error) {
type st struct {
Value string `json:"text_value"`
}
var values []st
err := e.db.Item.Query().
Where(
item.HasGroupWith(group.ID(GID)),
).
QueryFields().
Where(
itemfield.Name(name),
).
Unique(true).
Select(itemfield.FieldTextValue).
Scan(ctx, &values)
if err != nil {
return nil, fmt.Errorf("failed to get field values: %w", err)
}
valueStrings := make([]string, len(values))
for i, f := range values {
valueStrings[i] = f.Value
}
return valueStrings, nil
}
func (e *ItemsRepository) GetAllCustomFieldNames(ctx context.Context, GID uuid.UUID) ([]string, error) {
type st struct {
Name string `json:"name"`
}
var fields []st
err := e.db.Item.Query().
Where(
item.HasGroupWith(group.ID(GID)),
).
QueryFields().
Unique(true).
Select(itemfield.FieldName).
Scan(ctx, &fields)
if err != nil {
return nil, fmt.Errorf("failed to get custom fields: %w", err)
}
fieldNames := make([]string, len(fields))
for i, f := range fields {
fieldNames[i] = f.Name
}
return fieldNames, nil
}
// ZeroOutTimeFields is a helper function that can be invoked via the UI by a group member which will
// set all date fields to the beginning of the day.
//
// This is designed to resolve a long-time bug that has since been fixed with the time selector on the
// frontend. This function is intended to be used as a one-time fix for existing databases and may be
// removed in the future.
func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, GID uuid.UUID) (int, error) {
q := e.db.Item.Query().Where(
item.HasGroupWith(group.ID(GID)),
item.Or(
item.PurchaseTimeNotNil(),
item.SoldTimeNotNil(),
item.WarrantyExpiresNotNil(),
),
)
items, err := q.All(ctx)
if err != nil {
return -1, fmt.Errorf("ZeroOutTimeFields() -> failed to get items: %w", err)
}
toDateOnly := func(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
updated := 0
for _, i := range items {
updateQ := e.db.Item.Update().Where(item.ID(i.ID))
if !i.PurchaseTime.IsZero() {
updateQ.SetPurchaseTime(toDateOnly(i.PurchaseTime))
}
if !i.SoldTime.IsZero() {
updateQ.SetSoldTime(toDateOnly(i.SoldTime))
}
if !i.WarrantyExpires.IsZero() {
updateQ.SetWarrantyExpires(toDateOnly(i.WarrantyExpires))
}
_, err = updateQ.Save(ctx)
if err != nil {
return updated, fmt.Errorf("ZeroOutTimeFields() -> failed to update item: %w", err)
}
updated++
}
return updated, nil
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func itemFactory() ItemCreate {
@@ -36,6 +37,8 @@ func useItems(t *testing.T, len int) []ItemOut {
for _, item := range items {
_ = tRepos.Items.Delete(context.Background(), item.ID)
}
_ = tRepos.Locations.Delete(context.Background(), location.ID)
})
return items
@@ -271,3 +274,48 @@ func TestItemsRepository_Update(t *testing.T) {
assert.Equal(t, updateData.WarrantyDetails, got.WarrantyDetails)
assert.Equal(t, updateData.LifetimeWarranty, got.LifetimeWarranty)
}
func TestItemRepository_GetAllCustomFields(t *testing.T) {
const FIELDS_COUNT = 5
entity := useItems(t, 1)[0]
fields := make([]ItemField, FIELDS_COUNT)
names := make([]string, FIELDS_COUNT)
values := make([]string, FIELDS_COUNT)
for i := 0; i < FIELDS_COUNT; i++ {
name := fk.Str(10)
fields[i] = ItemField{
Name: name,
Type: "text",
TextValue: fk.Str(10),
}
names[i] = name
values[i] = fields[i].TextValue
}
_, err := tRepos.Items.UpdateByGroup(context.Background(), tGroup.ID, ItemUpdate{
ID: entity.ID,
Name: entity.Name,
LocationID: entity.Location.ID,
Fields: fields,
})
require.NoError(t, err)
// Test getting all fields
{
results, err := tRepos.Items.GetAllCustomFieldNames(context.Background(), tGroup.ID)
assert.NoError(t, err)
assert.ElementsMatch(t, names, results)
}
// Test getting all values from field
{
results, err := tRepos.Items.GetAllCustomFieldValues(context.Background(), tUser.GroupID, names[0])
assert.NoError(t, err)
assert.ElementsMatch(t, values[:1], results)
}
}

View File

@@ -19,8 +19,9 @@ type LocationRepository struct {
type (
LocationCreate struct {
Name string `json:"name"`
Description string `json:"description"`
Name string `json:"name"`
ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"`
Description string `json:"description"`
}
LocationUpdate struct {
@@ -152,7 +153,9 @@ func (r *LocationRepository) getOne(ctx context.Context, where ...predicate.Loca
Where(where...).
WithGroup().
WithItems(func(iq *ent.ItemQuery) {
iq.Where(item.Archived(false)).WithLabel()
iq.Where(item.Archived(false)).
Order(ent.Asc(item.FieldName)).
WithLabel()
}).
WithParent().
WithChildren().
@@ -168,11 +171,16 @@ func (r *LocationRepository) GetOneByGroup(ctx context.Context, GID, ID uuid.UUI
}
func (r *LocationRepository) Create(ctx context.Context, GID uuid.UUID, data LocationCreate) (LocationOut, error) {
location, err := r.db.Location.Create().
q := r.db.Location.Create().
SetName(data.Name).
SetDescription(data.Description).
SetGroupID(GID).
Save(ctx)
SetGroupID(GID)
if data.ParentID != uuid.Nil {
q.SetParentID(data.ParentID)
}
location, err := q.Save(ctx)
if err != nil {
return LocationOut{}, err
@@ -218,3 +226,129 @@ func (r *LocationRepository) DeleteByGroup(ctx context.Context, GID, ID uuid.UUI
_, err := r.db.Location.Delete().Where(location.ID(ID), location.HasGroupWith(group.ID(GID))).Exec(ctx)
return err
}
type TreeItem struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Children []*TreeItem `json:"children"`
}
type FlatTreeItem struct {
ID uuid.UUID
Name string
Type string
ParentID uuid.UUID
Level int
}
type TreeQuery struct {
WithItems bool `json:"withItems"`
}
func (lr *LocationRepository) Tree(ctx context.Context, GID uuid.UUID, tq TreeQuery) ([]TreeItem, error) {
query := `
WITH recursive location_tree(id, NAME, location_children, level, node_type) AS
(
SELECT id,
NAME,
location_children,
0 AS level,
'location' AS node_type
FROM locations
WHERE location_children IS NULL
AND group_locations = ?
UNION ALL
SELECT c.id,
c.NAME,
c.location_children,
level + 1,
'location' AS node_type
FROM locations c
JOIN location_tree p
ON c.location_children = p.id
WHERE level < 10 -- prevent infinite loop & excessive recursion
{{ WITH_ITEMS }}
)
SELECT id,
NAME,
level,
location_children,
node_type
FROM location_tree
ORDER BY level,
node_type DESC, -- sort locations before items
lower(NAME)`
if tq.WithItems {
itemQuery := `
UNION ALL
SELECT i.id,
i.name,
location_items as location_children,
level + 1,
'item' AS node_type
FROM items i
JOIN location_tree p
ON i.location_items = p.id
WHERE level < 10 -- prevent infinite loop & excessive recursion`
query = strings.ReplaceAll(query, "{{ WITH_ITEMS }}", itemQuery)
} else {
query = strings.ReplaceAll(query, "{{ WITH_ITEMS }}", "")
}
rows, err := lr.db.Sql().QueryContext(ctx, query, GID)
if err != nil {
return nil, err
}
defer rows.Close()
var locations []FlatTreeItem
for rows.Next() {
var location FlatTreeItem
if err := rows.Scan(&location.ID, &location.Name, &location.Level, &location.ParentID, &location.Type); err != nil {
return nil, err
}
locations = append(locations, location)
}
if err := rows.Err(); err != nil {
return nil, err
}
return ConvertLocationsToTree(locations), nil
}
func ConvertLocationsToTree(locations []FlatTreeItem) []TreeItem {
var locationMap = make(map[uuid.UUID]*TreeItem, len(locations))
var rootIds []uuid.UUID
for _, location := range locations {
loc := &TreeItem{
ID: location.ID,
Name: location.Name,
Type: location.Type,
Children: []*TreeItem{},
}
locationMap[location.ID] = loc
if location.ParentID != uuid.Nil {
parent, ok := locationMap[location.ParentID]
if ok {
parent.Children = append(parent.Children, loc)
}
} else {
rootIds = append(rootIds, location.ID)
}
}
roots := make([]TreeItem, 0, len(rootIds))
for _, id := range rootIds {
roots = append(roots, *locationMap[id])
}
return roots
}

View File

@@ -2,8 +2,11 @@ package repo
import (
"context"
"encoding/json"
"testing"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent"
"github.com/stretchr/testify/assert"
)
@@ -14,6 +17,30 @@ func locationFactory() LocationCreate {
}
}
func useLocations(t *testing.T, len int) []LocationOut {
t.Helper()
out := make([]LocationOut, len)
for i := 0; i < len; i++ {
loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory())
assert.NoError(t, err)
out[i] = loc
}
t.Cleanup(func() {
for _, loc := range out {
err := tRepos.Locations.Delete(context.Background(), loc.ID)
if err != nil {
assert.True(t, ent.IsNotFound(err))
}
}
})
return out
}
func TestLocationRepository_Get(t *testing.T) {
loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory())
assert.NoError(t, err)
@@ -29,13 +56,9 @@ func TestLocationRepository_Get(t *testing.T) {
func TestLocationRepositoryGetAllWithCount(t *testing.T) {
ctx := context.Background()
result, err := tRepos.Locations.Create(ctx, tGroup.ID, LocationCreate{
Name: fk.Str(10),
Description: fk.Str(100),
})
assert.NoError(t, err)
result := useLocations(t, 1)[0]
_, err = tRepos.Items.Create(ctx, tGroup.ID, ItemCreate{
_, err := tRepos.Items.Create(ctx, tGroup.ID, ItemCreate{
Name: fk.Str(10),
Description: fk.Str(100),
LocationID: result.ID,
@@ -55,8 +78,7 @@ func TestLocationRepositoryGetAllWithCount(t *testing.T) {
}
func TestLocationRepository_Create(t *testing.T) {
loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory())
assert.NoError(t, err)
loc := useLocations(t, 1)[0]
// Get by ID
foundLoc, err := tRepos.Locations.Get(context.Background(), loc.ID)
@@ -68,8 +90,7 @@ func TestLocationRepository_Create(t *testing.T) {
}
func TestLocationRepository_Update(t *testing.T) {
loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory())
assert.NoError(t, err)
loc := useLocations(t, 1)[0]
updateData := LocationUpdate{
ID: loc.ID,
@@ -92,12 +113,154 @@ func TestLocationRepository_Update(t *testing.T) {
}
func TestLocationRepository_Delete(t *testing.T) {
loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory())
assert.NoError(t, err)
loc := useLocations(t, 1)[0]
err = tRepos.Locations.Delete(context.Background(), loc.ID)
err := tRepos.Locations.Delete(context.Background(), loc.ID)
assert.NoError(t, err)
_, err = tRepos.Locations.Get(context.Background(), loc.ID)
assert.Error(t, err)
}
func TestItemRepository_TreeQuery(t *testing.T) {
locs := useLocations(t, 3)
// Set relations
_, err := tRepos.Locations.UpdateOneByGroup(context.Background(), tGroup.ID, locs[0].ID, LocationUpdate{
ID: locs[0].ID,
ParentID: locs[1].ID,
Name: locs[0].Name,
Description: locs[0].Description,
})
assert.NoError(t, err)
locations, err := tRepos.Locations.Tree(context.Background(), tGroup.ID, TreeQuery{WithItems: true})
assert.NoError(t, err)
assert.Equal(t, 2, len(locations))
// Check roots
for _, loc := range locations {
if loc.ID == locs[1].ID {
assert.Equal(t, 1, len(loc.Children))
}
}
}
func TestConvertLocationsToTree(t *testing.T) {
uuid1, uuid2, uuid3, uuid4 := uuid.New(), uuid.New(), uuid.New(), uuid.New()
testCases := []struct {
name string
locations []FlatTreeItem
expected []TreeItem
}{
{
name: "Convert locations to tree",
locations: []FlatTreeItem{
{
ID: uuid1,
Name: "Root1",
ParentID: uuid.Nil,
Level: 0,
},
{
ID: uuid2,
Name: "Child1",
ParentID: uuid1,
Level: 1,
},
{
ID: uuid3,
Name: "Child2",
ParentID: uuid1,
Level: 1,
},
},
expected: []TreeItem{
{
ID: uuid1,
Name: "Root1",
Children: []*TreeItem{
{
ID: uuid2,
Name: "Child1",
Children: []*TreeItem{},
},
{
ID: uuid3,
Name: "Child2",
Children: []*TreeItem{},
},
},
},
},
},
{
name: "Convert locations to tree with deeply nested children",
locations: []FlatTreeItem{
{
ID: uuid1,
Name: "Root1",
ParentID: uuid.Nil,
Level: 0,
},
{
ID: uuid2,
Name: "Child1",
ParentID: uuid1,
Level: 1,
},
{
ID: uuid3,
Name: "Child2",
ParentID: uuid2,
Level: 2,
},
{
ID: uuid4,
Name: "Child3",
ParentID: uuid3,
Level: 3,
},
},
expected: []TreeItem{
{
ID: uuid1,
Name: "Root1",
Children: []*TreeItem{
{
ID: uuid2,
Name: "Child1",
Children: []*TreeItem{
{
ID: uuid3,
Name: "Child2",
Children: []*TreeItem{
{
ID: uuid4,
Name: "Child3",
Children: []*TreeItem{},
},
},
},
},
},
},
},
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := ConvertLocationsToTree(tc.locations)
// Compare JSON strings
expected, _ := json.Marshal(tc.expected)
got, _ := json.Marshal(result)
assert.Equal(t, string(expected), string(got))
})
}
}

View File

@@ -69,7 +69,7 @@ func (e *UserRepository) GetOneId(ctx context.Context, id uuid.UUID) (UserOut, e
func (e *UserRepository) GetOneEmail(ctx context.Context, email string) (UserOut, error) {
return mapUserOutErr(e.db.User.Query().
Where(user.Email(email)).
Where(user.EmailEqualFold(email)).
WithGroup().
Only(ctx),
)

View File

@@ -5,7 +5,7 @@ import (
"errors"
"fmt"
"github.com/ardanlabs/conf/v2"
"github.com/ardanlabs/conf/v3"
"os"
)

View File

@@ -34,8 +34,11 @@ Homebox is currently in early-active development and is currently in **beta** st
- Purchased From Information
- Item Identifications (Serial, Model, etc)
- Categorized Attachments (Images, Manuals, General)
- Arbitrary/Custom Fields - _Coming Soon!_
- Csv Import for quickly creating and managing items - _Export Coming Soon!_
- Arbitrary/Custom Fields
- Csv Import for quickly creating and managing items
- Custom Reporting
- Bill of Materials Export
- QR Code Label Generator
- Organize _Items_ by creating _Labels_ and _Locations_ and assigning them to items.
- Multi-Tenant Support - All users are placed inside of a group and can only see items that are apart of their group. Invite family members to your group, or share an instance among friends!

View File

@@ -41,3 +41,8 @@ Homebox has a built-in QR code generator that can be used to generate QR codes f
However, the API endpoint is available for generating QR codes on the fly for any item (or any other data) if you provide a valid API key in the query parameters. An example url would look like `/api/v1/qrcode?data=https://homebox.fly.dev/item/{uuid}&access_token={api_key}`. Currently the easiest way to get an API token is to use one from an existing URL of the QR Code in the API key, but this will be improved in the future.
:octicons-tag-24: 0.8.0
In version 0.8.0 We've added a custom label generation. On the tools page, there is now a link to the label-generator page where you can generate labels based on Asset ID for your inventory. These are still in early development, so please provide feedback. There's also more information on the implementation on the label generator page.
[Demo](https://homebox.fly.dev/reports/label-generator)

View File

@@ -1,6 +1,7 @@
<template>
<NuxtLayout>
<Html lang="en" :data-theme="theme || 'homebox'" />
<Link rel="icon" type="image/svg" href="/favicon.svg"></Link>
<NuxtPage />
</NuxtLayout>
</template>

View File

@@ -4,4 +4,23 @@
.btn {
text-transform: none !important;
}
/* transparent subtle scrollbar */
::-webkit-scrollbar {
width: 0.2em;
background-color: #F5F5F5;
}
::-webkit-scrollbar-thumb {
background-color: rgba(0,0,0,.2);
}
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
background-color: #F5F5F5;
}
::-webkit-scrollbar-thumb:hover {
background-color: #9B9B9B;
}

View File

@@ -53,11 +53,16 @@
);
function setFile(e: Event) {
importCsv.value = e.target.files[0];
const result = e.target as HTMLInputElement;
if (!result.files || result.files.length === 0) {
return;
}
importCsv.value = result.files[0];
}
function uploadCsv() {
importRef.value.click();
importRef.value?.click();
}
const eventBus = useEventBus();
@@ -85,6 +90,8 @@
importRef.value.value = "";
}
eventBus.emit(EventTypes.ClearStores);
eventBus.emit(EventTypes.InvalidStores);
toast.success("Import successful!");
}
</script>

View File

@@ -0,0 +1,17 @@
<template>
<div class="grid grid-cols-1 md:grid-cols-4 gap-10 py-6">
<div class="col-span-3">
<h4 class="mb-1 text-lg font-semibold">
<slot name="title"></slot>
</h4>
<p class="text-sm">
<slot></slot>
</p>
</div>
<BaseButton class="btn-primary mt-auto" @click="$emit('action')">
<slot name="button">
<slot name="title"></slot>
</slot>
</BaseButton>
</div>
</template>

View File

@@ -6,7 +6,7 @@
<div class="dropdown dropdown-top sm:dropdown-end">
<div class="relative">
<input
v-model="isearch"
v-model="internalSearch"
tabindex="0"
class="input w-full items-center flex flex-wrap border border-gray-400 rounded-lg"
@keyup.enter="selectFirst"
@@ -26,9 +26,11 @@
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>
<div type="button" @click="select(obj)">
<slot name="display" v-bind="{ item: obj }">
{{ usingObjects ? obj[itemText] : obj }}
</slot>
</div>
</li>
<li class="hidden first:flex">
<button disabled>
@@ -49,9 +51,10 @@
interface Props {
label: string;
modelValue: string | ItemsObject;
modelValue: string | ItemsObject | null | undefined;
items: ItemsObject[] | string[];
itemText?: keyof ItemsObject;
itemSearch?: keyof ItemsObject | null;
itemValue?: keyof ItemsObject;
search?: string;
noResultsText?: string;
@@ -63,21 +66,34 @@
modelValue: "",
items: () => [],
itemText: "text",
itemValue: "value",
search: "",
itemSearch: null,
itemValue: "value",
noResultsText: "No Results Found",
});
const searchKey = computed(() => props.itemSearch || props.itemText);
function clear() {
select(value.value);
}
const isearch = ref("");
watch(isearch, () => {
internalSearch.value = isearch.value;
});
const internalSearch = ref("");
watch(
() => props.search,
val => {
internalSearch.value = val;
}
);
watch(
() => internalSearch.value,
val => {
emit("update:search", val);
}
);
const internalSearch = useVModel(props, "search", emit);
const value = useVModel(props, "modelValue", emit);
const usingObjects = computed(() => {
@@ -102,9 +118,9 @@
() => {
if (value.value) {
if (typeof value.value === "string") {
isearch.value = value.value;
internalSearch.value = value.value;
} else {
isearch.value = value.value[props.itemText] as string;
internalSearch.value = value.value[searchKey.value] as string;
}
}
},
@@ -113,7 +129,7 @@
}
);
function select(obj: string | ItemsObject) {
function select(obj: Props["modelValue"]) {
if (isStrings(props.items)) {
if (obj === value.value) {
value.value = "";
@@ -131,16 +147,16 @@
}
const filtered = computed(() => {
if (!isearch.value || isearch.value === "") {
if (!internalSearch.value || internalSearch.value === "") {
return props.items;
}
if (isStrings(props.items)) {
return props.items.filter(item => item.toLowerCase().includes(isearch.value.toLowerCase()));
return props.items.filter(item => item.toLowerCase().includes(internalSearch.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());
if (searchKey.value && searchKey.value in item) {
return (item[searchKey.value] as string).toLowerCase().includes(internalSearch.value.toLowerCase());
}
return false;
});

View File

@@ -0,0 +1,157 @@
<template>
<div>
<Combobox v-model="value">
<ComboboxLabel class="label">
<span class="label-text">{{ label }}</span>
</ComboboxLabel>
<div class="relative">
<ComboboxInput
:display-value="i => extractDisplay(i as SupportValues)"
class="w-full input input-bordered"
@change="search = $event.target.value"
/>
<ComboboxButton class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
<Icon name="mdi-chevron-down" class="w-5 h-5" />
</ComboboxButton>
<ComboboxOptions
v-if="computedItems.length > 0"
class="absolute dropdown-content z-10 mt-2 max-h-60 w-full overflow-auto rounded-md card bg-base-100 border border-gray-400"
>
<ComboboxOption
v-for="item in computedItems"
:key="item.id"
v-slot="{ active, selected }"
:value="item.value"
as="template"
>
<li
:class="[
'relative cursor-default select-none py-2 pl-3 pr-9 duration-75 ease-in-out transition-colors',
active ? 'bg-primary text-white' : 'text-gray-900',
]"
>
<slot name="display" v-bind="{ item: item, selected, active }">
<span :class="['block truncate', selected && 'font-semibold']">
{{ item.display }}
</span>
<span
v-if="selected"
:class="[
'absolute inset-y-0 right-0 flex text-primary items-center pr-4',
active ? 'text-primary-content' : 'bg-primary',
]"
>
<Icon name="mdi-check" class="h-5 w-5" aria-hidden="true" />
</span>
</slot>
</li>
</ComboboxOption>
</ComboboxOptions>
</div>
</Combobox>
</div>
</template>
<script setup lang="ts">
import {
Combobox,
ComboboxInput,
ComboboxOptions,
ComboboxOption,
ComboboxButton,
ComboboxLabel,
} from "@headlessui/vue";
type SupportValues = string | { [key: string]: any };
type ComboItem = {
display: string;
value: SupportValues;
id: number;
};
type Props = {
label: string;
modelValue: SupportValues | null | undefined;
items: string[] | object[];
display?: string;
multiple?: boolean;
};
const emit = defineEmits(["update:modelValue", "update:search"]);
const props = withDefaults(defineProps<Props>(), {
label: "",
modelValue: "",
display: "text",
multiple: false,
});
const search = ref("");
const value = useVModel(props, "modelValue", emit);
function extractDisplay(item?: SupportValues): string {
if (!item) {
return "";
}
if (typeof item === "string") {
return item;
}
if (props.display in item) {
return item[props.display] as string;
}
// Try these options as well
const fallback = ["name", "title", "display", "value"];
for (let i = 0; i < fallback.length; i++) {
const key = fallback[i];
if (key in item) {
return item[key] as string;
}
}
return "";
}
const computedItems = computed<ComboItem[]>(() => {
const list: ComboItem[] = [];
for (let i = 0; i < props.items.length; i++) {
const item = props.items[i];
const out: Partial<ComboItem> = {
id: i,
value: item,
};
switch (typeof item) {
case "string":
out.display = item;
break;
case "object":
// @ts-ignore - up to the user to provide a valid display key
out.display = item[props.display] as string;
break;
default:
out.display = "";
break;
}
if (search.value && out.display) {
const foldSearch = search.value.toLowerCase();
const foldDisplay = out.display.toLowerCase();
if (foldDisplay.startsWith(foldSearch)) {
list.push(out as ComboItem);
}
continue;
}
list.push(out as ComboItem);
}
return list;
});
</script>

View File

@@ -1,38 +1,15 @@
<template>
<div ref="label" class="dropdown dropdown-end dropdown-top w-full">
<FormTextField v-model="dateText" tabindex="0" label="Date" :inline="inline" readonly />
<div tabindex="0" class="card compact dropdown-content shadow bg-base-100 rounded-box w-64" @blur="resetTime">
<div class="card-body">
<div class="grid grid-cols-7 gap-2">
<div v-for="d in daysIdx" :key="d">
<p class="text-center">
{{ d }}
</p>
</div>
<template v-for="day in days">
<button
v-if="day.number != ''"
:key="day.number"
type="button"
class="text-center btn-xs btn btn-outline"
@click="select($event, day.date)"
>
{{ day.number }}
</button>
<div v-else :key="`${day.number}-empty`"></div>
</template>
</div>
<div class="flex justify-between mt-1 items-center">
<button type="button" class="btn btn-xs" @click="prevMonth">
<Icon class="h-5 w-5" name="mdi-arrow-left"></Icon>
</button>
<p class="text-center">{{ month }} {{ year }}</p>
<button type="button" class="btn btn-xs" @click="nextMonth">
<Icon class="h-5 w-5" name="mdi-arrow-right"></Icon>
</button>
</div>
</div>
</div>
<div v-if="!inline" class="form-control w-full">
<label class="label">
<span class="label-text"> Date </span>
</label>
<input ref="input" v-model="selected" type="date" class="input input-bordered w-full" />
</div>
<div v-else class="sm:grid sm:grid-cols-4 sm:items-start sm:gap-4">
<label class="label">
<span class="label-text"> Date </span>
</label>
<input v-model="selected" type="date" class="input input-bordered col-span-3 w-full mt-2" />
</div>
</template>
@@ -41,7 +18,7 @@
const props = defineProps({
modelValue: {
type: Date,
type: Date as () => Date | string,
required: false,
default: null,
},
@@ -51,88 +28,28 @@
},
});
const selected = useVModel(props, "modelValue", emit);
const dateText = computed(() => {
if (!validDate(selected.value)) {
return "";
}
const selected = computed({
get() {
// return modelValue as string as YYYY-MM-DD or null
if (validDate(props.modelValue)) {
if (typeof props.modelValue === "string") {
return props.modelValue;
}
if (selected.value) {
return selected.value.toLocaleDateString();
}
return props.modelValue ? props.modelValue.toISOString().split("T")[0] : null;
}
return "";
});
const time = ref(new Date());
function resetTime() {
time.value = new Date();
}
const label = ref<HTMLElement>();
onClickOutside(label, () => {
resetTime();
});
const month = computed(() => {
return time.value.toLocaleString("default", { month: "long" });
});
const year = computed(() => {
return time.value.getFullYear();
});
function nextMonth() {
time.value.setMonth(time.value.getMonth() + 1);
time.value = new Date(time.value);
}
function prevMonth() {
time.value.setMonth(time.value.getMonth() - 1);
time.value = new Date(time.value);
}
const daysIdx = computed(() => {
return ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
});
function select(e: MouseEvent, day: Date) {
selected.value = day;
// @ts-ignore - this is a vue3 bug
e.target.blur();
resetTime();
}
type DayEntry = {
number: number | string;
date: Date;
};
function daysInMonth(month: number, year: number) {
return new Date(year, month, 0).getDate();
}
const days = computed<DayEntry[]>(() => {
const days = [];
const totalDays = daysInMonth(time.value.getMonth() + 1, time.value.getFullYear());
const firstDay = new Date(time.value.getFullYear(), time.value.getMonth(), 1).getDay();
for (let i = 0; i < firstDay; i++) {
days.push({
number: "",
date: new Date(),
});
}
for (let i = 1; i <= totalDays; i++) {
days.push({
number: i,
date: new Date(time.value.getFullYear(), time.value.getMonth(), i),
});
}
return days;
return null;
},
set(value: string | null) {
// emit update:modelValue with a Date object or null
emit("update:modelValue", value ? new Date(value) : null);
},
});
</script>
<style class="scoped">
::-webkit-calendar-picker-indicator {
filter: invert(1);
}
</style>

View File

@@ -0,0 +1,34 @@
<template>
<div class="flex">
<FormTextField v-model="value" placeholder="Password" label="Password" :type="inputType"> </FormTextField>
<button
type="button"
class="inline-flex p-1 ml-1 justify-center mt-auto mb-3 tooltip"
data-tip="Toggle Password Show"
@click="toggle()"
>
<Icon name="mdi-eye" class="h-5 w-5" />
</button>
</div>
</template>
<script setup lang="ts">
type Props = {
modelValue: string;
placeholder: string;
label: string;
};
const props = withDefaults(defineProps<Props>(), {
placeholder: "Password",
label: "Password",
});
const [hide, toggle] = useToggle(true);
const inputType = computed(() => {
return hide.value ? "password" : "text";
});
const value = useVModel(props, "modelValue");
</script>

View File

@@ -2,7 +2,7 @@
<BaseModal v-model="modal">
<template #title> Create Item </template>
<form @submit.prevent="create(true)">
<FormSelect v-model="form.location" label="Location" :items="locations ?? []" />
<LocationSelector v-model="form.location" />
<FormTextField
ref="locationNameRef"
v-model="form.name"

View File

@@ -0,0 +1,65 @@
<script setup lang="ts">
import { ViewType } from "~~/composables/use-preferences";
import { ItemSummary } from "~~/lib/api/types/data-contracts";
type Props = {
view?: ViewType;
items: ItemSummary[];
};
const preferences = useViewPreferences();
const props = defineProps<Props>();
const viewSet = computed(() => {
return !!props.view;
});
const itemView = computed(() => {
return props.view ?? preferences.value.itemDisplayView;
});
function setViewPreference(view: ViewType) {
preferences.value.itemDisplayView = view;
}
</script>
<template>
<section>
<BaseSectionHeader class="mb-5 flex justify-between items-center">
Items
<template #description>
<div v-if="!viewSet" class="dropdown dropdown-hover dropdown-left">
<label tabindex="0" class="btn btn-ghost m-1">
<Icon name="mdi-dots-vertical" class="h-7 w-7" />
</label>
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-32">
<li>
<button @click="setViewPreference('card')">
<Icon name="mdi-card-text-outline" class="h-5 w-5" />
Card
</button>
</li>
<li>
<button @click="setViewPreference('table')">
<Icon name="mdi-table" class="h-5 w-5" />
Table
</button>
</li>
</ul>
</div>
</template>
</BaseSectionHeader>
<template v-if="itemView === 'table'">
<ItemViewTable :items="items" />
</template>
<template v-else>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
<ItemCard v-for="item in items" :key="item.id" :item="item" />
</div>
</template>
</section>
</template>
<style scoped></style>

View File

@@ -0,0 +1,10 @@
import { ItemSummary } from "~~/lib/api/types/data-contracts";
export type TableHeader = {
text: string;
value: keyof ItemSummary;
sortable?: boolean;
align?: "left" | "center" | "right";
};
export type TableData = Record<string, any>;

View File

@@ -0,0 +1,181 @@
<template>
<BaseCard>
<table class="table w-full">
<thead>
<tr class="bg-primary">
<th
v-for="h in headers"
:key="h.value"
class="text-no-transform text-sm bg-neutral text-neutral-content cursor-pointer"
@click="sortBy(h.value)"
>
<div
class="flex items-center gap-1"
:class="{
'justify-center': h.align === 'center',
'justify-start': h.align === 'right',
'justify-end': h.align === 'left',
}"
>
<template v-if="typeof h === 'string'">{{ h }}</template>
<template v-else>{{ h.text }}</template>
<div :class="`inline-flex ${sortByProperty === h.value ? '' : 'opacity-0'}`">
<span class="swap swap-rotate" :class="{ 'swap-active': pagination.descending }">
<Icon name="mdi-arrow-down" class="swap-on h-5 w-5" />
<Icon name="mdi-arrow-up" class="swap-off h-5 w-5" />
</span>
</div>
</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(d, i) in data" :key="d.id" class="hover cursor-pointer" @click="navigateTo(`/item/${d.id}`)">
<td
v-for="h in headers"
:key="`${h.value}-${i}`"
class="bg-base-100"
:class="{
'text-center': h.align === 'center',
'text-right': h.align === 'right',
'text-left': h.align === 'left',
}"
>
<template v-if="cell(h) === 'cell-name'">
<NuxtLink class="hover" :to="`/item/${d.id}`">
{{ d.name }}
</NuxtLink>
</template>
<template v-else-if="cell(h) === 'cell-purchasePrice'">
<Currency :amount="d.purchasePrice" />
</template>
<template v-else-if="cell(h) === 'cell-insured'">
<Icon v-if="d.insured" name="mdi-check" class="text-green-500 h-5 w-5" />
<Icon v-else name="mdi-close" class="text-red-500 h-5 w-5" />
</template>
<slot v-else :name="cell(h)" v-bind="{ item: d }">
{{ extractValue(d, h.value) }}
</slot>
</td>
</tr>
</tbody>
</table>
<div v-if="hasPrev || hasNext" class="border-t p-3 justify-end flex">
<div class="btn-group">
<button :disabled="!hasPrev" class="btn btn-sm" @click="prev()">«</button>
<button class="btn btn-sm">Page {{ pagination.page }}</button>
<button :disabled="!hasNext" class="btn btn-sm" @click="next()">»</button>
</div>
</div>
</BaseCard>
</template>
<script setup lang="ts">
import { TableData, TableHeader } from "./Table.types";
import { ItemSummary } from "~~/lib/api/types/data-contracts";
type Props = {
items: ItemSummary[];
};
const props = defineProps<Props>();
const sortByProperty = ref<keyof ItemSummary>("name");
const headers = computed<TableHeader[]>(() => {
return [
{ text: "Name", value: "name" },
{ text: "Quantity", value: "quantity", align: "center" },
{ text: "Insured", value: "insured", align: "center" },
{ text: "Price", value: "purchasePrice" },
] as TableHeader[];
});
const pagination = reactive({
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 0,
});
const next = () => pagination.page++;
const hasNext = computed<boolean>(() => {
return pagination.page * pagination.rowsPerPage < props.items.length;
});
const prev = () => pagination.page--;
const hasPrev = computed<boolean>(() => {
return pagination.page > 1;
});
function sortBy(property: keyof ItemSummary) {
if (sortByProperty.value === property) {
pagination.descending = !pagination.descending;
} else {
pagination.descending = false;
}
sortByProperty.value = property;
}
function extractSortable(item: ItemSummary, property: keyof ItemSummary): string | number | boolean {
const value = item[property];
if (typeof value === "string") {
// Try parse float
const parsed = parseFloat(value);
if (!isNaN(parsed)) {
return parsed;
}
return value.toLowerCase();
}
if (typeof value !== "number" && typeof value !== "boolean") {
return "";
}
return value;
}
function itemSort(a: ItemSummary, b: ItemSummary) {
const aLower = extractSortable(a, sortByProperty.value);
const bLower = extractSortable(b, sortByProperty.value);
if (aLower < bLower) {
return -1;
}
if (aLower > bLower) {
return 1;
}
return 0;
}
const data = computed<TableData[]>(() => {
// sort by property
let data = [...props.items].sort(itemSort);
// sort descending
if (pagination.descending) {
data.reverse();
}
// paginate
const start = (pagination.page - 1) * pagination.rowsPerPage;
const end = start + pagination.rowsPerPage;
data = data.slice(start, end);
return data;
});
function extractValue(data: TableData, value: string) {
const parts = value.split(".");
let current = data;
for (const part of parts) {
current = current[part];
}
return current;
}
function cell(h: TableHeader) {
return `cell-${h.value.replace(".", "_")}`;
}
</script>
<style scoped></style>

View File

@@ -10,6 +10,7 @@
label="Location Name"
/>
<FormTextArea v-model="form.description" label="Location Description" />
<LocationSelector v-model="form.parent" />
<div class="modal-action">
<BaseButton type="submit" :loading="loading"> Create </BaseButton>
</div>
@@ -18,6 +19,7 @@
</template>
<script setup lang="ts">
import { LocationSummary } from "~~/lib/api/types/data-contracts";
const props = defineProps({
modelValue: {
type: Boolean,
@@ -31,6 +33,7 @@
const form = reactive({
name: "",
description: "",
parent: null as LocationSummary | null,
});
whenever(
@@ -43,6 +46,7 @@
function reset() {
form.name = "";
form.description = "";
form.parent = null;
focused.value = false;
modal.value = false;
loading.value = false;
@@ -54,7 +58,11 @@
async function create() {
loading.value = true;
const { data, error } = await api.locations.create(form);
const { data, error } = await api.locations.create({
name: form.name,
description: form.description,
parentId: form.parent ? form.parent.id : null,
});
if (error) {
toast.error("Couldn't create location");

View File

@@ -0,0 +1,55 @@
<template>
<FormAutocomplete2 v-if="locations" v-model="value" :items="locations" display="name" label="Parent Location">
<template #display="{ item, selected, active }">
<div>
<div class="flex w-full">
{{ cast(item.value).name }}
<span
v-if="selected"
:class="['absolute inset-y-0 right-0 flex items-center pr-4', active ? 'text-white' : 'text-primary']"
>
<Icon name="mdi-check" class="h-5 w-5" aria-hidden="true" />
</span>
</div>
<div v-if="cast(item.value).name != cast(item.value).treeString" class="text-xs mt-1">
{{ cast(item.value).treeString }}
</div>
</div>
</template>
</FormAutocomplete2>
</template>
<script lang="ts" setup>
import { FlatTreeItem, useFlatLocations } from "~~/composables/use-location-helpers";
import { LocationSummary } from "~~/lib/api/types/data-contracts";
type Props = {
modelValue?: LocationSummary | null;
};
// Cast the type of the item to a FlatTreeItem so we can get type "safety" in the template
// Note that this does not actually change the type of the item, it just tells the compiler
// that the type is FlatTreeItem. We must keep this in sync with the type of the items
function cast(value: any): FlatTreeItem {
return value as FlatTreeItem;
}
const props = defineProps<Props>();
const value = useVModel(props, "modelValue");
const locations = await useFlatLocations();
const form = ref({
parent: null as LocationSummary | null,
search: "",
});
// Whenever parent goes from value to null reset search
watch(
() => value.value,
() => {
if (!value.value) {
form.value.search = "";
}
}
);
</script>

View File

@@ -0,0 +1,73 @@
<script setup lang="ts">
import { useTreeState } from "./tree-state";
import { TreeItem } from "~~/lib/api/types/data-contracts";
type Props = {
treeId: string;
item: TreeItem;
};
const props = withDefaults(defineProps<Props>(), {});
const link = computed(() => {
return props.item.type === "location" ? `/location/${props.item.id}` : `/item/${props.item.id}`;
});
const hasChildren = computed(() => {
return props.item.children.length > 0;
});
const state = useTreeState(props.treeId);
const openRef = computed({
get() {
return state.value[nodeHash.value] ?? false;
},
set(value) {
state.value[nodeHash.value] = value;
},
});
const nodeHash = computed(() => {
// converts a UUID to a short hash
return props.item.id.replace(/-/g, "").substring(0, 8);
});
</script>
<template>
<div>
<div
class="node flex items-center gap-1 rounded p-1"
:class="{
'cursor-pointer hover:bg-base-200': hasChildren,
}"
@click="openRef = !openRef"
>
<div
class="p-1/2 rounded mr-1 flex items-center justify-center"
:class="{
'hover:bg-base-200': hasChildren,
}"
>
<div v-if="!hasChildren" class="h-6 w-6"></div>
<label
v-else
class="swap swap-rotate"
:class="{
'swap-active': openRef,
}"
>
<Icon name="mdi-chevron-right" class="h-6 w-6 swap-off" />
<Icon name="mdi-chevron-down" class="h-6 w-6 swap-on" />
</label>
</div>
<Icon v-if="item.type === 'location'" name="mdi-map-marker" class="h-4 w-4" />
<Icon v-else name="mdi-package-variant" class="h-4 w-4" />
<NuxtLink class="hover:link text-lg" :to="link" @click.stop>{{ item.name }} </NuxtLink>
</div>
<div v-if="openRef" class="ml-4">
<LocationTreeNode v-for="child in item.children" :key="child.id" :item="child" :tree-id="treeId" />
</div>
</div>
</template>
<style scoped></style>

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import { TreeItem } from "~~/lib/api/types/data-contracts";
type Props = {
locs: TreeItem[];
treeId: string;
};
defineProps<Props>();
</script>
<template>
<div class="p-4 border-2 root">
<LocationTreeNode v-for="item in locs" :key="item.id" :item="item" :tree-id="treeId" />
</div>
</template>
<style></style>

View File

@@ -0,0 +1,17 @@
import type { Ref } from "vue";
type TreeState = Record<string, boolean>;
const store: Record<string, Ref<TreeState>> = {};
export function newTreeKey(): string {
return Math.random().toString(36).substring(2);
}
export function useTreeState(key: string): Ref<TreeState> {
if (!store[key]) {
store[key] = ref({});
}
return store[key];
}

View File

@@ -0,0 +1,104 @@
<template>
<div ref="el" class="dropdown" :class="{ 'dropdown-open': dropdownOpen }">
<button ref="btn" tabindex="0" class="btn btn-xs" @click="toggle">
{{ label }} {{ len }} <Icon name="mdi-chevron-down" class="h-4 w-4" />
</button>
<div tabindex="0" class="dropdown-content mt-1 w-64 shadow bg-base-100 rounded-md">
<div class="pt-4 px-4 shadow-sm mb-1">
<input v-model="search" type="text" placeholder="Search…" class="input input-sm input-bordered w-full mb-2" />
</div>
<div class="overflow-y-auto max-h-72 divide-y">
<label
v-for="v in selectedView"
:key="v"
class="cursor-pointer px-4 label flex justify-between hover:bg-base-200"
>
<span class="label-text mr-2">
<slot name="display" v-bind="{ item: v }">
{{ v[display] }}
</slot>
</span>
<input v-model="selected" type="checkbox" :value="v" class="checkbox checkbox-sm checkbox-primary" />
</label>
<hr v-if="selected.length > 0" />
<label
v-for="v in unselected"
:key="v"
class="cursor-pointer px-4 label flex justify-between hover:bg-base-200"
>
<span class="label-text mr-2">
<slot name="display" v-bind="{ item: v }">
{{ v[display] }}
</slot>
</span>
<input v-model="selected" type="checkbox" :value="v" class="checkbox checkbox-sm checkbox-primary" />
</label>
</div>
</div>
</div>
</template>
<script setup lang="ts">
type Props = {
label: string;
options: any[];
display?: string;
modelValue: any[];
};
const btn = ref<HTMLButtonElement>();
const search = ref("");
const searchFold = computed(() => search.value.toLowerCase());
const dropdownOpen = ref(false);
const el = ref();
function toggle() {
dropdownOpen.value = !dropdownOpen.value;
if (!dropdownOpen.value) {
btn.value?.blur();
}
}
onClickOutside(el, () => {
dropdownOpen.value = false;
});
watch(dropdownOpen, val => {
console.log(val);
});
const emit = defineEmits(["update:modelValue"]);
const props = withDefaults(defineProps<Props>(), {
label: "",
display: "name",
modelValue: () => [],
});
const len = computed(() => {
return selected.value.length > 0 ? `(${selected.value.length})` : "";
});
const selectedView = computed(() => {
return selected.value.filter(o => {
if (searchFold.value.length > 0) {
return o[props.display].toLowerCase().includes(searchFold.value);
}
return true;
});
});
const selected = useVModel(props, "modelValue", emit);
const unselected = computed(() => {
return props.options.filter(o => {
if (searchFold.value.length > 0) {
return o[props.display].toLowerCase().includes(searchFold.value) && !selected.value.includes(o);
}
return !selected.value.includes(o);
});
});
</script>
<style scoped></style>

View File

@@ -4,7 +4,7 @@ import { Requests } from "~~/lib/requests";
import { useAuthStore } from "~~/stores/auth";
export type Observer = {
handler: (r: Response) => void;
handler: (r: Response, req?: RequestInit) => void;
};
export type RemoveObserver = () => void;

View File

@@ -2,7 +2,7 @@ export enum EventTypes {
// ClearStores event is used to inform the stores that _all_ the data they are using
// is now out of date and they should refresh - This is used when the user makes large
// changes to the data such as bulk actions or importing a CSV file
ClearStores,
InvalidStores,
}
export type EventFn = () => void;
@@ -15,7 +15,7 @@ export interface IEventBus {
class EventBus implements IEventBus {
private listeners: Record<EventTypes, Record<string, EventFn>> = {
[EventTypes.ClearStores]: {},
[EventTypes.InvalidStores]: {},
};
on(event: EventTypes, fn: EventFn, key: string): void {

View File

@@ -63,11 +63,11 @@ export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human"): st
switch (fmt) {
case "relative":
return useTimeAgo(dt).value + useDateFormat(dt, " (MM-DD-YYYY)").value;
return useTimeAgo(dt).value + useDateFormat(dt, " (YYYY-MM-DD)").value;
case "long":
return useDateFormat(dt, "MM-DD-YYYY (dddd)").value;
return useDateFormat(dt, "YYYY-MM-DD (dddd)").value;
case "short":
return useDateFormat(dt, "MM-DD-YYYY").value;
return useDateFormat(dt, "YYYY-MM-DD").value;
case "human":
// January 1st, 2021
return `${months[dt.getMonth()]} ${dt.getDate()}${ordinalIndicator(dt.getDate())}, ${dt.getFullYear()}`;

View File

@@ -0,0 +1,44 @@
import { Ref } from "vue";
import { TreeItem } from "~~/lib/api/types/data-contracts";
export interface FlatTreeItem {
id: string;
name: string;
treeString: string;
}
export function flatTree(tree: TreeItem[]): Ref<FlatTreeItem[]> {
const v = ref<FlatTreeItem[]>([]);
// turns the nested items into a flat items array where
// the display is a string of the tree hierarchy separated by breadcrumbs
function flatten(items: TreeItem[], display: string) {
for (const item of items) {
v.value.push({
id: item.id,
name: item.name,
treeString: display + item.name,
});
if (item.children) {
flatten(item.children, display + item.name + " > ");
}
}
}
flatten(tree, "");
return v;
}
export async function useFlatLocations(): Promise<Ref<FlatTreeItem[]>> {
const api = useUserApi();
const locations = await api.locations.getTree();
if (!locations) {
return ref([]);
}
return flatTree(locations.data.items);
}

View File

@@ -1,10 +1,13 @@
import { Ref } from "vue";
import { DaisyTheme } from "~~/lib/data/themes";
export type ViewType = "table" | "card" | "tree";
export type LocationViewPreferences = {
showDetails: boolean;
showEmpty: boolean;
editorAdvancedView: boolean;
itemDisplayView: ViewType;
theme: DaisyTheme;
};
@@ -19,6 +22,7 @@ export function useViewPreferences(): Ref<LocationViewPreferences> {
showDetails: true,
showEmpty: true,
editorAdvancedView: false,
itemDisplayView: "card",
theme: "homebox",
},
{ mergeDefaults: true }

View File

@@ -6,7 +6,6 @@
up the tree
-->
<ModalConfirm />
<AppImportDialog v-model="modals.import" />
<ItemCreateModal v-model="modals.item" />
<LabelCreateModal v-model="modals.label" />
<LocationCreateModal v-model="modals.location" />
@@ -78,10 +77,6 @@
<Icon :name="n.icon" class="h-6 w-6 mr-4" />
{{ n.name }}
</NuxtLink>
<button v-else class="rounded-btn" @click="n.action">
<Icon :name="n.icon" class="h-6 w-6 mr-4" />
{{ n.name }}
</button>
</li>
</ul>
</div>
@@ -158,35 +153,40 @@
to: "/profile",
},
{
icon: "mdi-document",
icon: "mdi-magnify",
id: 3,
active: computed(() => route.path === "/items"),
name: "Items",
name: "Search",
to: "/items",
},
{
icon: "mdi-database",
id: 2,
name: "Import",
action: () => {
modals.import = true;
},
icon: "mdi-map-marker",
id: 4,
active: computed(() => route.path === "/locations"),
name: "Locations",
to: "/locations",
},
{
icon: "mdi-cog",
id: 6,
active: computed(() => route.path === "/tools"),
name: "Tools",
to: "/tools",
},
// {
// icon: "mdi-database-export",
// id: 5,
// name: "Export",
// action: () => {
// console.log("Export");
// },
// },
];
function isMutation(method: string | undefined) {
return method === "POST" || method === "PUT" || method === "DELETE";
}
function isSuccess(status: number) {
return status >= 200 && status < 300;
}
const labelStore = useLabelStore();
const reLabel = /\/api\/v1\/labels\/.*/gm;
const rmLabelStoreObserver = defineObserver("labelStore", {
handler: r => {
if (r.status === 201 || r.url.match(reLabel)) {
handler: (resp, req) => {
if (isMutation(req?.method) && isSuccess(resp.status) && resp.url.match(reLabel)) {
labelStore.refresh();
}
console.debug("labelStore handler called by observer");
@@ -196,18 +196,19 @@
const locationStore = useLocationStore();
const reLocation = /\/api\/v1\/locations\/.*/gm;
const rmLocationStoreObserver = defineObserver("locationStore", {
handler: r => {
if (r.status === 201 || r.url.match(reLocation)) {
handler: (resp, req) => {
if (isMutation(req?.method) && isSuccess(resp.status) && resp.url.match(reLocation)) {
locationStore.refreshChildren();
locationStore.refreshParents();
}
console.debug("locationStore handler called by observer");
},
});
const eventBus = useEventBus();
eventBus.on(
EventTypes.ClearStores,
EventTypes.InvalidStores,
() => {
labelStore.refresh();
locationStore.refreshChildren();
@@ -219,7 +220,7 @@
onUnmounted(() => {
rmLabelStoreObserver();
rmLocationStoreObserver();
eventBus.off(EventTypes.ClearStores, "stores");
eventBus.off(EventTypes.InvalidStores, "stores");
});
const authStore = useAuthStore();

View File

@@ -5,7 +5,7 @@ const ZERO_DATE = "0001-01-01T00:00:00Z";
type BaseApiType = {
createdAt: string;
updatedAt: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
};
@@ -26,9 +26,11 @@ export function parseDate<T>(obj: T, keys: Array<keyof T> = []): T {
return;
}
// Ensure date like format YYYY/MM/DD - otherwise results will be 1 day off
const dateStr: string = result[key].split("T")[0].replace(/-/g, "/");
result[key] = new Date(dateStr);
// transform string to ensure dates are parsed as UTC dates instead of
// localized time stamps
const asStr = result[key] as string;
const cleaned = asStr.replaceAll("-", "/").split("T")[0];
result[key] = new Date(cleaned);
}
});

View File

@@ -1,10 +1,16 @@
import { BaseAPI, route } from "../base";
import { EnsureAssetIDResult } from "../types/data-contracts";
import { ActionAmountResult } from "../types/data-contracts";
export class ActionsAPI extends BaseAPI {
ensureAssetIDs() {
return this.http.post<void, EnsureAssetIDResult>({
return this.http.post<void, ActionAmountResult>({
url: route("/actions/ensure-asset-ids"),
});
}
resetItemDateTimes() {
return this.http.post<void, ActionAmountResult>({
url: route("/actions/zero-item-time-fields"),
});
}
}

View File

@@ -21,6 +21,7 @@ export type ItemsQuery = {
locations?: string[];
labels?: string[];
q?: string;
fields?: string[];
};
export class AttachmentsAPI extends BaseAPI {
@@ -48,6 +49,16 @@ export class AttachmentsAPI extends BaseAPI {
}
}
export class FieldsAPI extends BaseAPI {
getAll() {
return this.http.get<string[]>({ url: route("/items/fields") });
}
getAllValues(field: string) {
return this.http.get<string[]>({ url: route(`/items/fields/values`, { field }) });
}
}
export class MaintenanceAPI extends BaseAPI {
getLog(itemId: string) {
return this.http.get<MaintenanceLog>({ url: route(`/items/${itemId}/maintenance`) });
@@ -75,9 +86,11 @@ export class MaintenanceAPI extends BaseAPI {
export class ItemsApi extends BaseAPI {
attachments: AttachmentsAPI;
maintenance: MaintenanceAPI;
fields: FieldsAPI;
constructor(http: Requests, token: string) {
super(http, token);
this.fields = new FieldsAPI(http);
this.attachments = new AttachmentsAPI(http);
this.maintenance = new MaintenanceAPI(http);
}

View File

@@ -1,16 +1,24 @@
import { BaseAPI, route } from "../base";
import { LocationOutCount, LocationCreate, LocationOut, LocationUpdate } from "../types/data-contracts";
import { LocationOutCount, LocationCreate, LocationOut, LocationUpdate, TreeItem } from "../types/data-contracts";
import { Results } from "../types/non-generated";
export type LocationsQuery = {
filterChildren: boolean;
};
export type TreeQuery = {
withItems: boolean;
};
export class LocationsApi extends BaseAPI {
getAll(q: LocationsQuery = { filterChildren: false }) {
return this.http.get<Results<LocationOutCount>>({ url: route("/locations", q) });
}
getTree(tq = { withItems: false }) {
return this.http.get<Results<TreeItem>>({ url: route("/locations/tree", tq) });
}
create(body: LocationCreate) {
return this.http.post<LocationCreate, LocationOut>({ url: route("/locations"), body });
}

View File

@@ -0,0 +1,27 @@
import { BaseAPI, route } from "../base";
export class ReportsAPI extends BaseAPI {
async billOfMaterials(): Promise<void> {
const { data: stream, error } = await this.http.get<ReadableStream>({ url: route("/reporting/bill-of-materials") });
if (error) {
return;
}
const reader = stream.getReader();
let data = "";
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
data += new TextDecoder("utf-8").decode(value);
}
const blob = new Blob([data], { type: "text/tsv" });
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = "bill-of-materials.tsv";
link.click();
}
}

View File

@@ -1,7 +1,7 @@
import { BaseAPI, route } from "../base";
import { GroupStatistics, TotalsByOrganizer, ValueOverTime } from "../types/data-contracts";
function YYYY_DD_MM(date?: Date): string {
function YYYY_MM_DD(date?: Date): string {
if (!date) {
return "";
}
@@ -14,7 +14,7 @@ function YYYY_DD_MM(date?: Date): string {
export class StatsAPI extends BaseAPI {
totalPriceOverTime(start?: Date, end?: Date) {
return this.http.get<ValueOverTime>({
url: route("/groups/statistics/purchase-price", { start: YYYY_DD_MM(start), end: YYYY_DD_MM(end) }),
url: route("/groups/statistics/purchase-price", { start: YYYY_MM_DD(start), end: YYYY_MM_DD(end) }),
});
}

View File

@@ -17,11 +17,11 @@ export interface DocumentOut {
}
export interface Group {
createdAt: Date;
createdAt: Date | string;
currency: string;
id: string;
name: string;
updatedAt: Date;
updatedAt: Date | string;
}
export interface GroupStatistics {
@@ -39,11 +39,11 @@ export interface GroupUpdate {
}
export interface ItemAttachment {
createdAt: Date;
createdAt: Date | string;
document: DocumentOut;
id: string;
type: string;
updatedAt: Date;
updatedAt: Date | string;
}
export interface ItemAttachmentUpdate {
@@ -76,7 +76,7 @@ export interface ItemOut {
assetId: string;
attachments: ItemAttachment[];
children: ItemSummary[];
createdAt: Date;
createdAt: Date | string;
description: string;
fields: ItemField[];
id: string;
@@ -96,23 +96,23 @@ export interface ItemOut {
/** @example "0" */
purchasePrice: string;
/** Purchase */
purchaseTime: Date;
purchaseTime: Date | string;
quantity: number;
serialNumber: string;
soldNotes: string;
/** @example "0" */
soldPrice: string;
/** Sold */
soldTime: Date;
soldTime: Date | string;
soldTo: string;
updatedAt: Date;
updatedAt: Date | string;
warrantyDetails: string;
warrantyExpires: Date;
warrantyExpires: Date | string;
}
export interface ItemSummary {
archived: boolean;
createdAt: Date;
createdAt: Date | string;
description: string;
id: string;
insured: boolean;
@@ -123,7 +123,7 @@ export interface ItemSummary {
/** @example "0" */
purchasePrice: string;
quantity: number;
updatedAt: Date;
updatedAt: Date | string;
}
export interface ItemUpdate {
@@ -148,7 +148,7 @@ export interface ItemUpdate {
/** @example "0" */
purchasePrice: string;
/** Purchase */
purchaseTime: Date;
purchaseTime: Date | string;
quantity: number;
/** Identifications */
serialNumber: string;
@@ -156,10 +156,10 @@ export interface ItemUpdate {
/** @example "0" */
soldPrice: string;
/** Sold */
soldTime: Date;
soldTime: Date | string;
soldTo: string;
warrantyDetails: string;
warrantyExpires: Date;
warrantyExpires: Date | string;
}
export interface LabelCreate {
@@ -169,53 +169,54 @@ export interface LabelCreate {
}
export interface LabelOut {
createdAt: Date;
createdAt: Date | string;
description: string;
id: string;
items: ItemSummary[];
name: string;
updatedAt: Date;
updatedAt: Date | string;
}
export interface LabelSummary {
createdAt: Date;
createdAt: Date | string;
description: string;
id: string;
name: string;
updatedAt: Date;
updatedAt: Date | string;
}
export interface LocationCreate {
description: string;
name: string;
parentId: string | null;
}
export interface LocationOut {
children: LocationSummary[];
createdAt: Date;
createdAt: Date | string;
description: string;
id: string;
items: ItemSummary[];
name: string;
parent: LocationSummary;
updatedAt: Date;
updatedAt: Date | string;
}
export interface LocationOutCount {
createdAt: Date;
createdAt: Date | string;
description: string;
id: string;
itemCount: number;
name: string;
updatedAt: Date;
updatedAt: Date | string;
}
export interface LocationSummary {
createdAt: Date;
createdAt: Date | string;
description: string;
id: string;
name: string;
updatedAt: Date;
updatedAt: Date | string;
}
export interface LocationUpdate {
@@ -228,7 +229,7 @@ export interface LocationUpdate {
export interface MaintenanceEntry {
/** @example "0" */
cost: string;
date: Date;
date: Date | string;
description: string;
id: string;
name: string;
@@ -237,7 +238,7 @@ export interface MaintenanceEntry {
export interface MaintenanceEntryCreate {
/** @example "0" */
cost: string;
date: Date;
date: Date | string;
description: string;
name: string;
}
@@ -245,7 +246,7 @@ export interface MaintenanceEntryCreate {
export interface MaintenanceEntryUpdate {
/** @example "0" */
cost: string;
date: Date;
date: Date | string;
description: string;
name: string;
}
@@ -257,7 +258,7 @@ export interface MaintenanceLog {
itemId: string;
}
export interface PaginationResultRepoItemSummary {
export interface PaginationResultItemSummary {
items: ItemSummary[];
page: number;
pageSize: number;
@@ -270,6 +271,13 @@ export interface TotalsByOrganizer {
total: number;
}
export interface TreeItem {
children: TreeItem[];
id: string;
name: string;
type: string;
}
export interface UserOut {
email: string;
groupId: string;
@@ -294,7 +302,7 @@ export interface ValueOverTime {
}
export interface ValueOverTimeEntry {
date: Date;
date: Date | string;
name: string;
value: number;
}
@@ -322,6 +330,10 @@ export interface UserRegistration {
token: string;
}
export interface ActionAmountResult {
completed: number;
}
export interface ApiSummary {
build: Build;
demo: boolean;
@@ -342,18 +354,14 @@ export interface ChangePassword {
new: string;
}
export interface EnsureAssetIDResult {
completed: number;
}
export interface GroupInvitation {
expiresAt: string;
expiresAt: Date | string;
token: string;
uses: number;
}
export interface GroupInvitationCreate {
expiresAt: string;
expiresAt: Date | string;
uses: number;
}
@@ -363,6 +371,6 @@ export interface ItemAttachmentToken {
export interface TokenResponse {
attachmentToken: string;
expiresAt: string;
expiresAt: Date | string;
token: string;
}

View File

@@ -7,6 +7,7 @@ import { UserApi } from "./classes/users";
import { ActionsAPI } from "./classes/actions";
import { StatsAPI } from "./classes/stats";
import { AssetsApi } from "./classes/assets";
import { ReportsAPI } from "./classes/reports";
import { Requests } from "~~/lib/requests";
export class UserClient extends BaseAPI {
@@ -18,6 +19,7 @@ export class UserClient extends BaseAPI {
actions: ActionsAPI;
stats: StatsAPI;
assets: AssetsApi;
reports: ReportsAPI;
constructor(requests: Requests, attachmentToken: string) {
super(requests, attachmentToken);
@@ -30,6 +32,7 @@ export class UserClient extends BaseAPI {
this.actions = new ActionsAPI(requests);
this.stats = new StatsAPI(requests);
this.assets = new AssetsApi(requests);
this.reports = new ReportsAPI(requests);
Object.freeze(this);
}

Some files were not shown because too many files have changed in this diff Show More