mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-24 06:28:34 +01:00
Compare commits
123 Commits
v0.5.1
...
fix/variou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e48256b77 | ||
|
|
c41a43d804 | ||
|
|
3ed72daa64 | ||
|
|
564b8a2725 | ||
|
|
4a9bcde9ea | ||
|
|
e1e04d49aa | ||
|
|
9020587c9e | ||
|
|
bd0db1ea37 | ||
|
|
d2985ff72c | ||
|
|
8c57ff841e | ||
|
|
0264bfb8c1 | ||
|
|
5dd6844536 | ||
|
|
0f8db862b4 | ||
|
|
be6b5c9c56 | ||
|
|
faed343eda | ||
|
|
ed1230e17d | ||
|
|
2d768e2b9c | ||
|
|
40e76bac0c | ||
|
|
840d220d4f | ||
|
|
975e636fb6 | ||
|
|
d1076baf84 | ||
|
|
40fcef4e9b | ||
|
|
97fb94d231 | ||
|
|
4a8ba6231d | ||
|
|
db80f8a159 | ||
|
|
184b494fc3 | ||
|
|
5a3fa23332 | ||
|
|
ef0690d511 | ||
|
|
9e55c880f6 | ||
|
|
cb9b20e2d2 | ||
|
|
a79e780b4e | ||
|
|
90cbb9bfd1 | ||
|
|
dc08dbbd7a | ||
|
|
1f47d96e4c | ||
|
|
23b5892aef | ||
|
|
2665b666f1 | ||
|
|
14315cb88a | ||
|
|
cf536393f5 | ||
|
|
025521431e | ||
|
|
70297b9d27 | ||
|
|
729293745f | ||
|
|
a6bcb36c5b | ||
|
|
a005fa5b9b | ||
|
|
a2dfa9dcef | ||
|
|
32216f63bd | ||
|
|
ef190e26df | ||
|
|
c3e3702a7e | ||
|
|
fb57120067 | ||
|
|
9d9b05d8a6 | ||
|
|
3ac6c7c858 | ||
|
|
859d3b9ffe | ||
|
|
6cfa6c9fc8 | ||
|
|
12975ce26e | ||
|
|
bd321af29f | ||
|
|
88f9ff90d4 | ||
|
|
354f1adbee | ||
|
|
2a62a43493 | ||
|
|
673db41f37 | ||
|
|
830ce2b0a9 | ||
|
|
e8e6a425dd | ||
|
|
da00db0608 | ||
|
|
efd7069fe4 | ||
|
|
dd349aa98e | ||
|
|
607b06d2f2 | ||
|
|
44f13f751a | ||
|
|
986d2c586e | ||
|
|
9361997a42 | ||
|
|
2e96d8c4c2 | ||
|
|
ff75daf6b3 | ||
|
|
c0953bbd26 | ||
|
|
1f7e917c70 | ||
|
|
6ff2d64996 | ||
|
|
ab22ea6a25 | ||
|
|
ce2fc7712a | ||
|
|
bd933af874 | ||
|
|
f36f17b57d | ||
|
|
504569bed0 | ||
|
|
bd06fdafaf | ||
|
|
7b28973c60 | ||
|
|
cbac17c059 | ||
|
|
6ed1f3695a | ||
|
|
3d295b5132 | ||
|
|
4d220cdd9c | ||
|
|
ad20e4e39b | ||
|
|
3e2f6a96bf | ||
|
|
2ece97c42a | ||
|
|
a8ee4d421b | ||
|
|
91d0c588d9 | ||
|
|
c19fe94c08 | ||
|
|
f532b39c46 | ||
|
|
243742a75c | ||
|
|
2b7c1fa429 | ||
|
|
125b8f5ecd | ||
|
|
580de45cec | ||
|
|
da52b4ec64 | ||
|
|
5b0dba854d | ||
|
|
984c1a08ac | ||
|
|
8419a17109 | ||
|
|
f3406eec19 | ||
|
|
3ed07a909f | ||
|
|
07441eec8e | ||
|
|
c78f10ba5d | ||
|
|
490a0ece86 | ||
|
|
891d41b75f | ||
|
|
58d6f9a28c | ||
|
|
6a8a25e3f8 | ||
|
|
a3954dab0f | ||
|
|
08d483d907 | ||
|
|
a53f89ceac | ||
|
|
5bbb969763 | ||
|
|
d6da63187b | ||
|
|
de419dc37d | ||
|
|
974d6914a2 | ||
|
|
d2aa022347 | ||
|
|
6af048dc93 | ||
|
|
73c42f4784 | ||
|
|
f42a917390 | ||
|
|
f149c3e4ab | ||
|
|
1dc1ee54e2 | ||
|
|
e8f215ce34 | ||
|
|
1aafbcd201 | ||
|
|
6dc2ae1bea | ||
|
|
976f68252d |
31
.github/dependabot.yml
vendored
31
.github/dependabot.yml
vendored
@@ -1,31 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
# Fetch and update latest `npm` packages
|
||||
- package-ecosystem: npm
|
||||
directory: "/frontend"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "00:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- hay-kot
|
||||
assignees:
|
||||
- hay-kot
|
||||
commit-message:
|
||||
prefix: fix
|
||||
prefix-development: chore
|
||||
include: scope
|
||||
- package-ecosystem: gomod
|
||||
directory: backend
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "00:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- hay-kot
|
||||
assignees:
|
||||
- hay-kot
|
||||
commit-message:
|
||||
prefix: fix
|
||||
prefix-development: chore
|
||||
include: scope
|
||||
6
.github/workflows/partial-backend.yaml
vendored
6
.github/workflows/partial-backend.yaml
vendored
@@ -7,12 +7,12 @@ jobs:
|
||||
Go:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.19
|
||||
go-version: "1.20"
|
||||
|
||||
- name: Install Task
|
||||
uses: arduino/setup-task@v1
|
||||
|
||||
40
.github/workflows/partial-frontend.yaml
vendored
40
.github/workflows/partial-frontend.yaml
vendored
@@ -4,11 +4,37 @@ on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
Frontend:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 6.0.2
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --shamefully-hoist
|
||||
working-directory: frontend
|
||||
|
||||
- name: Run Lint
|
||||
run: pnpm run lint:ci
|
||||
working-directory: frontend
|
||||
|
||||
- name: Run Typecheck
|
||||
run: pnpm run typecheck
|
||||
working-directory: frontend
|
||||
|
||||
integration-tests:
|
||||
name: Integration Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -18,15 +44,15 @@ jobs:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.19
|
||||
go-version: "1.20"
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- uses: pnpm/action-setup@v2.2.2
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 6.0.2
|
||||
|
||||
@@ -34,9 +60,5 @@ jobs:
|
||||
run: pnpm install
|
||||
working-directory: frontend
|
||||
|
||||
- name: Run linter 👀
|
||||
run: pnpm lint
|
||||
working-directory: "frontend"
|
||||
|
||||
- name: Run Integration Tests
|
||||
run: task test:ci
|
||||
|
||||
10
.github/workflows/partial-publish.yaml
vendored
10
.github/workflows/partial-publish.yaml
vendored
@@ -20,22 +20,22 @@ jobs:
|
||||
name: "Publish Homebox"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.19
|
||||
go-version: "1.20"
|
||||
|
||||
- name: Set up QEMU
|
||||
id: qemu
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
with:
|
||||
image: tonistiigi/binfmt:latest
|
||||
platforms: all
|
||||
|
||||
- name: install buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
install: true
|
||||
|
||||
|
||||
23
.github/workflows/publish.yaml
vendored
23
.github/workflows/publish.yaml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Build Nightly
|
||||
name: Publish Dockers
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -12,31 +12,17 @@ env:
|
||||
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
||||
|
||||
jobs:
|
||||
backend-tests:
|
||||
name: "Backend Server Tests"
|
||||
uses: hay-kot/homebox/.github/workflows/partial-backend.yaml@main
|
||||
|
||||
frontend-tests:
|
||||
name: "Frontend and End-to-End Tests"
|
||||
uses: hay-kot/homebox/.github/workflows/partial-frontend.yaml@main
|
||||
|
||||
deploy:
|
||||
name: "Deploy Nightly to Fly.io"
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- backend-tests
|
||||
- frontend-tests
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: superfly/flyctl-actions/setup-flyctl@master
|
||||
- run: flyctl deploy --remote-only
|
||||
|
||||
publish-nightly:
|
||||
name: "Publish Nightly"
|
||||
if: github.event_name != 'release'
|
||||
needs:
|
||||
- backend-tests
|
||||
- frontend-tests
|
||||
uses: hay-kot/homebox/.github/workflows/partial-publish.yaml@main
|
||||
with:
|
||||
tag: nightly
|
||||
@@ -46,9 +32,6 @@ jobs:
|
||||
publish-tag:
|
||||
name: "Publish Tag"
|
||||
if: github.event_name == 'release'
|
||||
needs:
|
||||
- backend-tests
|
||||
- frontend-tests
|
||||
uses: hay-kot/homebox/.github/workflows/partial-publish.yaml@main
|
||||
with:
|
||||
release: true
|
||||
@@ -63,7 +46,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Deploy docs
|
||||
uses: mhausenblas/mkdocs-deploy-gh-pages@master
|
||||
|
||||
2
.github/workflows/pull-requests.yaml
vendored
2
.github/workflows/pull-requests.yaml
vendored
@@ -12,4 +12,4 @@ jobs:
|
||||
|
||||
frontend-tests:
|
||||
name: "Frontend and End-to-End Tests"
|
||||
uses: ./.github/workflows/partial-frontend.yaml
|
||||
uses: ./.github/workflows/partial-frontend.yaml
|
||||
51
.github/workflows/tag.yaml
vendored
Normal file
51
.github/workflows/tag.yaml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Publish Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
env:
|
||||
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
||||
|
||||
jobs:
|
||||
backend-tests:
|
||||
name: "Backend Server Tests"
|
||||
uses: hay-kot/homebox/.github/workflows/partial-backend.yaml@main
|
||||
|
||||
frontend-tests:
|
||||
name: "Frontend and End-to-End Tests"
|
||||
uses: hay-kot/homebox/.github/workflows/partial-frontend.yaml@main
|
||||
|
||||
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 7.30.1
|
||||
|
||||
- name: Build Frontend and Copy to Backend
|
||||
working-directory: frontend
|
||||
run: |
|
||||
pnpm install --shamefully-hoist
|
||||
pnpm run build
|
||||
cp -r ./.output/public ../backend/app/api/static/
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
workdir: "backend"
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -45,3 +45,12 @@ node_modules
|
||||
.output
|
||||
.env
|
||||
dist
|
||||
|
||||
.pnpm-store
|
||||
backend/app/api/app
|
||||
backend/app/api/__debug_bin
|
||||
dist/
|
||||
|
||||
# Nuxt Publish Dir
|
||||
backend/app/api/static/public/*
|
||||
!backend/app/api/static/public/.gitkeep
|
||||
33
.scaffold/model/scaffold.yaml
Normal file
33
.scaffold/model/scaffold.yaml
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
# yaml-language-server: $schema=https://hay-kot.github.io/scaffold/schema.json
|
||||
messages:
|
||||
pre: |
|
||||
# Ent Model Generation
|
||||
|
||||
With Boilerplate!
|
||||
post: |
|
||||
Complete!
|
||||
|
||||
questions:
|
||||
- name: "model"
|
||||
prompt:
|
||||
message: "What is the name of the model? (PascalCase)"
|
||||
required: true
|
||||
|
||||
- name: "by_group"
|
||||
prompt:
|
||||
confirm: "Include a Group Edge? (group_id -> id)"
|
||||
required: true
|
||||
|
||||
rewrites:
|
||||
- from: 'templates/model.go'
|
||||
to: 'backend/internal/data/ent/schema/{{ lower .Scaffold.model }}.go'
|
||||
|
||||
inject:
|
||||
- name: "Insert Groups Edge"
|
||||
path: 'backend/internal/data/ent/schema/group.go'
|
||||
at: // $scaffold_edge
|
||||
template: |
|
||||
{{- if .Scaffold.by_group -}}
|
||||
owned("{{ lower .Scaffold.model }}s", {{ .Scaffold.model }}.Type),
|
||||
{{- end -}}
|
||||
40
.scaffold/model/templates/model.go
Normal file
40
.scaffold/model/templates/model.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"entgo.io/ent"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins"
|
||||
)
|
||||
|
||||
type {{ .Scaffold.model }} struct {
|
||||
ent.Schema
|
||||
}
|
||||
|
||||
func ({{ .Scaffold.model }}) Mixin() []ent.Mixin {
|
||||
return []ent.Mixin{
|
||||
mixins.BaseMixin{},
|
||||
{{- if .Scaffold.by_group }}
|
||||
GroupMixin{ref: "{{ snakecase .Scaffold.model }}s"},
|
||||
{{- end }}
|
||||
}
|
||||
}
|
||||
|
||||
// Fields of the {{ .Scaffold.model }}.
|
||||
func ({{ .Scaffold.model }}) Fields() []ent.Field {
|
||||
return []ent.Field{
|
||||
// field.String("name").
|
||||
}
|
||||
}
|
||||
|
||||
// Edges of the {{ .Scaffold.model }}.
|
||||
func ({{ .Scaffold.model }}) Edges() []ent.Edge {
|
||||
return []ent.Edge{
|
||||
// edge.From("group", Group.Type).
|
||||
}
|
||||
}
|
||||
|
||||
func ({{ .Scaffold.model }}) Indexes() []ent.Index {
|
||||
return []ent.Index{
|
||||
// index.Fields("token"),
|
||||
}
|
||||
}
|
||||
47
.vscode/launch.json
vendored
Normal file
47
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Full Stack",
|
||||
"configurations": ["Launch Backend", "Launch Frontend"],
|
||||
"stopAll": true
|
||||
}
|
||||
],
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Backend",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"program": "${workspaceRoot}/backend/app/api/",
|
||||
"args": [],
|
||||
"env": {
|
||||
"HBOX_DEMO": "true",
|
||||
"HBOX_LOG_LEVEL": "debug",
|
||||
"HBOX_DEBUG_ENABLED": "true",
|
||||
"HBOX_STORAGE_DATA": "${workspaceRoot}/backend/.data",
|
||||
"HBOX_STORAGE_SQLITE_URL": "${workspaceRoot}/backend/.data/homebox.db?_fk=1"
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Launch Frontend",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": [
|
||||
"run",
|
||||
"dev"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/frontend",
|
||||
"serverReadyAction": {
|
||||
"action": "debugWithChrome",
|
||||
"pattern": "Local: http://localhost:([0-9]+)",
|
||||
"uriFormat": "http://localhost:%s",
|
||||
"webRoot": "${workspaceFolder}/frontend"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
27
.vscode/settings.json
vendored
27
.vscode/settings.json
vendored
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"yaml.schemas": {
|
||||
"https://squidfunk.github.io/mkdocs-material/schema.json": "mkdocs.yml"
|
||||
},
|
||||
@@ -12,6 +9,26 @@
|
||||
"README.md": "LICENSE, SECURITY.md"
|
||||
},
|
||||
"cSpell.words": [
|
||||
"debughandlers"
|
||||
]
|
||||
"debughandlers",
|
||||
"Homebox"
|
||||
],
|
||||
// use ESLint to format code on save
|
||||
"editor.formatOnSave": false,
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
"eslint.format.enable": true,
|
||||
"css.validate": false,
|
||||
"tailwindCSS.includeLanguages": {
|
||||
"vue": "html",
|
||||
"vue-html": "html"
|
||||
},
|
||||
"editor.quickSuggestions": {
|
||||
"strings": true
|
||||
},
|
||||
"tailwindCSS.experimental.configFile": "./frontend/tailwind.config.js"
|
||||
}
|
||||
|
||||
@@ -48,4 +48,10 @@ start command `task: ui:dev`
|
||||
|
||||
1. The frontend is a Vue 3 app with Nuxt.js that uses Tailwind and DaisyUI for styling.
|
||||
2. We're using Vitest for our automated testing. you can run these with `task ui:watch`.
|
||||
3. Tests require the API server to be running and in some cases the first run will fail due to a race condition. If this happens just run the tests again and they should pass.
|
||||
3. Tests require the API server to be running and in some cases the first run will fail due to a race condition. If this happens just run the tests again and they should pass.
|
||||
|
||||
## Publishing Release
|
||||
|
||||
Create a new tag in github with the version number vX.X.X. This will trigger a new release to be created.
|
||||
|
||||
Test -> Goreleaser -> Publish Release -> Trigger Docker Builds -> Deploy Docs + Fly.io Demo
|
||||
@@ -22,7 +22,7 @@ COPY ./backend .
|
||||
RUN go get -d -v ./...
|
||||
RUN rm -rf ./app/api/public
|
||||
COPY --from=frontend-builder /app/.output/public ./app/api/static/public
|
||||
RUN CGO_ENABLED=1 GOOS=linux go build \
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
||||
-o /go/bin/api \
|
||||
-v ./app/api/*.go
|
||||
@@ -41,9 +41,10 @@ COPY --from=builder /go/bin/api /app
|
||||
RUN chmod +x /app/api
|
||||
|
||||
LABEL Name=homebox Version=0.0.1
|
||||
LABEL org.opencontainers.image.source="https://github.com/hay-kot/homebox"
|
||||
EXPOSE 7745
|
||||
WORKDIR /app
|
||||
VOLUME [ "/data" ]
|
||||
|
||||
ENTRYPOINT [ "/app/api" ]
|
||||
CMD [ "/data/config.yml" ]
|
||||
CMD [ "/data/config.yml" ]
|
||||
|
||||
11
README.md
11
README.md
@@ -16,10 +16,13 @@
|
||||
[Configuration & Docker Compose](https://hay-kot.github.io/homebox/quick-start)
|
||||
|
||||
```bash
|
||||
docker run --name=homebox \
|
||||
--restart=always \
|
||||
--publish=3100:7745 \
|
||||
ghcr.io/hay-kot/homebox:latest
|
||||
docker run -d \
|
||||
--name homebox \
|
||||
--restart unless-stopped \
|
||||
--publish 3100:7745 \
|
||||
--env TZ=Europe/Bucharest \
|
||||
--volume /path/to/data/folder/:/data \
|
||||
ghcr.io/hay-kot/homebox:latest
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
65
Taskfile.yml
65
Taskfile.yml
@@ -1,7 +1,8 @@
|
||||
version: "3"
|
||||
|
||||
env:
|
||||
HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_fk=1
|
||||
HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1
|
||||
HBOX_OPTIONS_ALLOW_REGISTRATION: true
|
||||
UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure"
|
||||
tasks:
|
||||
setup:
|
||||
@@ -26,46 +27,47 @@ tasks:
|
||||
--modular \
|
||||
--path ./backend/app/api/static/docs/swagger.json \
|
||||
--output ./frontend/lib/api/types
|
||||
- python3 ./scripts/process-types.py ./frontend/lib/api/types/data-contracts.ts
|
||||
- go run ./backend/app/tools/typegen/main.go ./frontend/lib/api/types/data-contracts.ts
|
||||
- cp ./backend/app/api/static/docs/swagger.json docs/docs/api/openapi-2.0.json
|
||||
sources:
|
||||
- "./backend/app/api/**/*"
|
||||
- "./backend/internal/data/**"
|
||||
- "./backend/internal/services/**/*"
|
||||
- "./scripts/process-types.py"
|
||||
generates:
|
||||
- "./frontend/lib/api/types/data-contracts.ts"
|
||||
- "./backend/internal/data/ent/schema"
|
||||
- "./backend/app/api/static/docs/swagger.json"
|
||||
- "./backend/app/api/static/docs/swagger.yaml"
|
||||
- "./backend/internal/core/services/**/*"
|
||||
- "./backend/app/tools/typegen/main.go"
|
||||
|
||||
go:run:
|
||||
desc: Starts the backend api server (depends on generate task)
|
||||
dir: backend
|
||||
deps:
|
||||
- generate
|
||||
cmds:
|
||||
- cd backend && go run ./app/api/ {{ .CLI_ARGS }}
|
||||
- go run ./app/api/ {{ .CLI_ARGS }}
|
||||
silent: false
|
||||
|
||||
go:test:
|
||||
desc: Runs all go tests using gotestsum - supports passing gotestsum args
|
||||
dir: backend
|
||||
cmds:
|
||||
- cd backend && gotestsum {{ .CLI_ARGS }} ./...
|
||||
- gotestsum {{ .CLI_ARGS }} ./...
|
||||
|
||||
go:coverage:
|
||||
desc: Runs all go tests with -race flag and generates a coverage report
|
||||
dir: backend
|
||||
cmds:
|
||||
- cd backend && go test -race -coverprofile=coverage.out -covermode=atomic ./app/... ./internal/... ./pkgs/... -v -cover
|
||||
- go test -race -coverprofile=coverage.out -covermode=atomic ./app/... ./internal/... ./pkgs/... -v -cover
|
||||
silent: true
|
||||
|
||||
go:tidy:
|
||||
desc: Runs go mod tidy on the backend
|
||||
dir: backend
|
||||
cmds:
|
||||
- cd backend && go mod tidy
|
||||
- go mod tidy
|
||||
|
||||
go:lint:
|
||||
desc: Runs golangci-lint
|
||||
dir: backend
|
||||
cmds:
|
||||
- cd backend && golangci-lint run ./...
|
||||
- golangci-lint run ./...
|
||||
|
||||
go:all:
|
||||
desc: Runs all go test and lint related tasks
|
||||
@@ -76,19 +78,19 @@ tasks:
|
||||
|
||||
go:build:
|
||||
desc: Builds the backend binary
|
||||
dir: backend
|
||||
cmds:
|
||||
- cd backend && go build -o ../build/backend ./app/api
|
||||
- go build -o ../build/backend ./app/api
|
||||
|
||||
db:generate:
|
||||
desc: Run Entgo.io Code Generation
|
||||
dir: backend/internal/
|
||||
cmds:
|
||||
- |
|
||||
cd backend/internal/ && go generate ./... \
|
||||
go generate ./... \
|
||||
--template=./data/ent/schema/templates/has_id.tmpl
|
||||
sources:
|
||||
- "./backend/internal/data/ent/schema/**/*"
|
||||
generates:
|
||||
- "./backend/internal/ent/"
|
||||
|
||||
db:migration:
|
||||
desc: Runs the database diff engine to generate a SQL migration files
|
||||
@@ -99,13 +101,27 @@ tasks:
|
||||
|
||||
ui:watch:
|
||||
desc: Starts the vitest test runner in watch mode
|
||||
dir: frontend
|
||||
cmds:
|
||||
- cd frontend && pnpm run test:watch
|
||||
- pnpm run test:watch
|
||||
|
||||
ui:dev:
|
||||
desc: Run frontend development server
|
||||
dir: frontend
|
||||
cmds:
|
||||
- cd frontend && pnpm dev
|
||||
- pnpm dev
|
||||
|
||||
ui:fix:
|
||||
desc: Runs prettier and eslint on the frontend
|
||||
dir: frontend
|
||||
cmds:
|
||||
- pnpm run lint:fix
|
||||
|
||||
ui:check:
|
||||
desc: Runs type checking
|
||||
dir: frontend
|
||||
cmds:
|
||||
- pnpm run typecheck
|
||||
|
||||
test:ci:
|
||||
desc: Runs end-to-end test on a live server (only for use in CI)
|
||||
@@ -115,3 +131,12 @@ tasks:
|
||||
- sleep 5
|
||||
- cd frontend && pnpm run test:ci
|
||||
silent: true
|
||||
|
||||
pr:
|
||||
desc: Runs all tasks required for a PR
|
||||
cmds:
|
||||
- task: generate
|
||||
- task: go:all
|
||||
- task: ui:check
|
||||
- task: ui:fix
|
||||
- task: test:ci
|
||||
2
backend/.gitignore
vendored
Normal file
2
backend/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
dist/
|
||||
54
backend/.goreleaser.yaml
Normal file
54
backend/.goreleaser.yaml
Normal file
@@ -0,0 +1,54 @@
|
||||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
before:
|
||||
hooks:
|
||||
# you may remove this if you don't need go generate
|
||||
- go generate ./...
|
||||
builds:
|
||||
- main: ./app/api
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- "386"
|
||||
- arm
|
||||
- arm64
|
||||
ignore:
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
- goos: windows
|
||||
goarch: "386"
|
||||
|
||||
archives:
|
||||
- format: tar.gz
|
||||
# this name template makes the OS and Arch compatible with the results of uname.
|
||||
name_template: >-
|
||||
{{ .ProjectName }}_
|
||||
{{- title .Os }}_
|
||||
{{- if eq .Arch "amd64" }}x86_64
|
||||
{{- else if eq .Arch "386" }}i386
|
||||
{{- else }}{{ .Arch }}{{ end }}
|
||||
{{- if .Arm }}v{{ .Arm }}{{ end }}
|
||||
# use zip for windows archives
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
snapshot:
|
||||
name_template: "{{ incpatch .Version }}-next"
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
|
||||
# The lines beneath this are called `modelines`. See `:help modeline`
|
||||
# Feel free to remove those if you don't want/use them.
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/config"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/mailer"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/hay-kot/safeserve/server"
|
||||
)
|
||||
|
||||
type app struct {
|
||||
@@ -37,8 +37,11 @@ func new(conf *config.Config) *app {
|
||||
}
|
||||
|
||||
func (a *app) startBgTask(t time.Duration, fn func()) {
|
||||
timer := time.NewTimer(t)
|
||||
|
||||
for {
|
||||
timer.Reset(t)
|
||||
a.server.Background(fn)
|
||||
time.Sleep(t)
|
||||
<-timer.C
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/csv"
|
||||
"strings"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
@@ -10,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func (a *app) SetupDemo() {
|
||||
csvText := `Import Ref,Location,Labels,Quantity,Name,Description,Insured,Serial Number,Model Number,Manufacturer,Notes,Purchase From,Purchased Price,Purchased Time,Lifetime Warranty,Warranty Expires,Warranty Details,Sold To,Sold Price,Sold Time,Sold Notes
|
||||
csvText := `HB.import_ref,HB.location,HB.labels,HB.quantity,HB.name,HB.description,HB.insured,HB.serial_number,HB.model_number,HB.manufacturer,HB.notes,HB.purchase_from,HB.purchase_price,HB.purchase_time,HB.lifetime_warranty,HB.warranty_expires,HB.warranty_details,HB.sold_to,HB.sold_price,HB.sold_time,HB.sold_notes
|
||||
,Garage,IOT;Home Assistant; Z-Wave,1,Zooz Universal Relay ZEN17,"Zooz 700 Series Z-Wave Universal Relay ZEN17 for Awnings, Garage Doors, Sprinklers, and More | 2 NO-C-NC Relays (20A, 10A) | Signal Repeater | Hub Required (Compatible with SmartThings and Hubitat)",,,ZEN17,Zooz,,Amazon,39.95,10/13/2021,,,,,,,
|
||||
,Living Room,IOT;Home Assistant; Z-Wave,1,Zooz Motion Sensor,"Zooz Z-Wave Plus S2 Motion Sensor ZSE18 with Magnetic Mount, Works with Vera and SmartThings",,,ZSE18,Zooz,,Amazon,29.95,10/15/2021,,,,,,,
|
||||
,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,"Zooz Z-Wave Plus Power Switch ZEN15 for 110V AC Units, Sump Pumps, Humidifiers, and More",,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,,,,,,
|
||||
@@ -19,16 +18,14 @@ func (a *app) SetupDemo() {
|
||||
,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,"UltraPro Z-Wave Smart Rocker Light Dimmer with QuickFit and SimpleWire, 3-Way Ready, Compatible with Alexa, Google Assistant, ZWave Hub Required, Repeater/Range Extender, White Paddle Only, 39351",,,39351,Honeywell,,Amazon,65.98,09/30/0202,,,,,,,
|
||||
`
|
||||
|
||||
var (
|
||||
registration = services.UserRegistration{
|
||||
Email: "demo@example.com",
|
||||
Name: "Demo",
|
||||
Password: "demo",
|
||||
}
|
||||
)
|
||||
registration := services.UserRegistration{
|
||||
Email: "demo@example.com",
|
||||
Name: "Demo",
|
||||
Password: "demo",
|
||||
}
|
||||
|
||||
// First check if we've already setup a demo user and skip if so
|
||||
_, err := a.services.User.Login(context.Background(), registration.Email, registration.Password)
|
||||
_, err := a.services.User.Login(context.Background(), registration.Email, registration.Password, false)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
@@ -39,20 +36,10 @@ func (a *app) SetupDemo() {
|
||||
log.Fatal().Msg("Failed to setup demo")
|
||||
}
|
||||
|
||||
token, _ := a.services.User.Login(context.Background(), registration.Email, registration.Password)
|
||||
token, _ := a.services.User.Login(context.Background(), registration.Email, registration.Password, false)
|
||||
self, _ := a.services.User.GetSelf(context.Background(), token.Raw)
|
||||
|
||||
// Read CSV Text
|
||||
reader := csv.NewReader(strings.NewReader(csvText))
|
||||
reader.Comma = ','
|
||||
|
||||
records, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to read CSV")
|
||||
log.Fatal().Msg("Failed to setup demo")
|
||||
}
|
||||
|
||||
_, err = a.services.Items.CsvImport(context.Background(), self.GroupID, records)
|
||||
_, err = a.services.Items.CsvImport(context.Background(), self.GroupID, strings.NewReader(csvText))
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to import CSV")
|
||||
log.Fatal().Msg("Failed to setup demo")
|
||||
|
||||
BIN
backend/app/api/handlers/v1/assets/QRIcon.png
Normal file
BIN
backend/app/api/handlers/v1/assets/QRIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
@@ -5,9 +5,26 @@ import (
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
"github.com/hay-kot/safeserve/server"
|
||||
)
|
||||
|
||||
type Results[T any] struct {
|
||||
Items []T `json:"items"`
|
||||
}
|
||||
|
||||
func WrapResults[T any](items []T) Results[T] {
|
||||
return Results[T]{Items: items}
|
||||
}
|
||||
|
||||
type Wrapped struct {
|
||||
Item interface{} `json:"item"`
|
||||
}
|
||||
|
||||
func Wrap(v any) Wrapped {
|
||||
return Wrapped{Item: v}
|
||||
}
|
||||
|
||||
func WithMaxUploadSize(maxUploadSize int64) func(*V1Controller) {
|
||||
return func(ctrl *V1Controller) {
|
||||
ctrl.maxUploadSize = maxUploadSize
|
||||
@@ -44,12 +61,13 @@ type (
|
||||
}
|
||||
|
||||
ApiSummary struct {
|
||||
Healthy bool `json:"health"`
|
||||
Versions []string `json:"versions"`
|
||||
Title string `json:"title"`
|
||||
Message string `json:"message"`
|
||||
Build Build `json:"build"`
|
||||
Demo bool `json:"demo"`
|
||||
Healthy bool `json:"health"`
|
||||
Versions []string `json:"versions"`
|
||||
Title string `json:"title"`
|
||||
Message string `json:"message"`
|
||||
Build Build `json:"build"`
|
||||
Demo bool `json:"demo"`
|
||||
AllowRegistration bool `json:"allowRegistration"`
|
||||
}
|
||||
)
|
||||
|
||||
@@ -74,19 +92,21 @@ func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, options ..
|
||||
}
|
||||
|
||||
// HandleBase godoc
|
||||
// @Summary Retrieves the basic information about the API
|
||||
// @Tags Base
|
||||
// @Produce json
|
||||
// @Success 200 {object} ApiSummary
|
||||
// @Router /v1/status [GET]
|
||||
func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) server.HandlerFunc {
|
||||
//
|
||||
// @Summary Application Info
|
||||
// @Tags Base
|
||||
// @Produce json
|
||||
// @Success 200 {object} ApiSummary
|
||||
// @Router /v1/status [GET]
|
||||
func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
return server.Respond(w, http.StatusOK, ApiSummary{
|
||||
Healthy: ready(),
|
||||
Title: "Go API Template",
|
||||
Message: "Welcome to the Go API Template Application!",
|
||||
Build: build,
|
||||
Demo: ctrl.isDemo,
|
||||
return server.JSON(w, http.StatusOK, ApiSummary{
|
||||
Healthy: ready(),
|
||||
Title: "Homebox",
|
||||
Message: "Track, Manage, and Organize your Things",
|
||||
Build: build,
|
||||
Demo: ctrl.isDemo,
|
||||
AllowRegistration: ctrl.allowRegistration,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func (ctrl *V1Controller) routeID(r *http.Request) (uuid.UUID, error) {
|
||||
func (ctrl *V1Controller) routeUUID(r *http.Request, key string) (uuid.UUID, error) {
|
||||
ID, err := uuid.Parse(chi.URLParam(r, key))
|
||||
if err != nil {
|
||||
return uuid.Nil, validate.NewInvalidRouteKeyError(key)
|
||||
return uuid.Nil, validate.NewRouteKeyError(key)
|
||||
}
|
||||
return ID, nil
|
||||
}
|
||||
|
||||
70
backend/app/api/handlers/v1/v1_ctrl_actions.go
Normal file
70
backend/app/api/handlers/v1/v1_ctrl_actions.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
"github.com/hay-kot/safeserve/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type ActionAmountResult struct {
|
||||
Completed int `json:"completed"`
|
||||
}
|
||||
|
||||
func actionHandlerFactory(ref string, fn func(context.Context, uuid.UUID) (int, error)) errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
|
||||
totalCompleted, err := fn(ctx, ctx.GID)
|
||||
if err != nil {
|
||||
log.Err(err).Str("action_ref", ref).Msg("failed to run action")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.JSON(w, http.StatusOK, ActionAmountResult{Completed: totalCompleted})
|
||||
}
|
||||
}
|
||||
|
||||
// HandleEnsureAssetID godoc
|
||||
//
|
||||
// @Summary Ensure Asset IDs
|
||||
// @Description Ensures all items in the database have an asset ID
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/ensure-asset-ids [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleEnsureAssetID() errchain.HandlerFunc {
|
||||
return actionHandlerFactory("ensure asset IDs", ctrl.svc.Items.EnsureAssetID)
|
||||
}
|
||||
|
||||
// HandleEnsureImportRefs godoc
|
||||
//
|
||||
// @Summary Ensures Import Refs
|
||||
// @Description Ensures all items in the database have an import ref
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/ensure-import-refs [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleEnsureImportRefs() errchain.HandlerFunc {
|
||||
return actionHandlerFactory("ensure import refs", ctrl.svc.Items.EnsureImportRef)
|
||||
}
|
||||
|
||||
// HandleItemDateZeroOut godoc
|
||||
//
|
||||
// @Summary Zero Out Time Fields
|
||||
// @Description Resets all item date fields to the beginning of the day
|
||||
// @Tags Actions
|
||||
// @Produce json
|
||||
// @Success 200 {object} ActionAmountResult
|
||||
// @Router /v1/actions/zero-item-time-fields [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemDateZeroOut() errchain.HandlerFunc {
|
||||
return actionHandlerFactory("zero out date time", ctrl.repo.Items.ZeroOutTimeFields)
|
||||
}
|
||||
62
backend/app/api/handlers/v1/v1_ctrl_assets.go
Normal file
62
backend/app/api/handlers/v1/v1_ctrl_assets.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
"github.com/hay-kot/safeserve/server"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// HandleAssetGet godocs
|
||||
//
|
||||
// @Summary Get Item by Asset ID
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Asset ID"
|
||||
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
|
||||
// @Router /v1/assets/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAssetGet() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
assetIdParam := chi.URLParam(r, "id")
|
||||
assetIdParam = strings.ReplaceAll(assetIdParam, "-", "") // Remove dashes
|
||||
// Convert the asset ID to an int64
|
||||
assetId, err := strconv.ParseInt(assetIdParam, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pageParam := r.URL.Query().Get("page")
|
||||
var page int64 = -1
|
||||
if pageParam != "" {
|
||||
page, err = strconv.ParseInt(pageParam, 10, 64)
|
||||
if err != nil {
|
||||
return server.JSON(w, http.StatusBadRequest, "Invalid page number")
|
||||
}
|
||||
}
|
||||
|
||||
pageSizeParam := r.URL.Query().Get("pageSize")
|
||||
var pageSize int64 = -1
|
||||
if pageSizeParam != "" {
|
||||
pageSize, err = strconv.ParseInt(pageSizeParam, 10, 64)
|
||||
if err != nil {
|
||||
return server.JSON(w, http.StatusBadRequest, "Invalid page size")
|
||||
}
|
||||
}
|
||||
|
||||
items, err := ctrl.repo.Items.QueryByAssetID(r.Context(), ctx.GID, repo.AssetID(assetId), int(page), int(pageSize))
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to get item")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.JSON(w, http.StatusOK, items)
|
||||
}
|
||||
}
|
||||
@@ -3,57 +3,64 @@ package v1
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
"github.com/hay-kot/safeserve/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type (
|
||||
TokenResponse struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
Token string `json:"token"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
AttachmentToken string `json:"attachmentToken"`
|
||||
}
|
||||
|
||||
LoginForm struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
StayLoggedIn bool `json:"stayLoggedIn"`
|
||||
}
|
||||
)
|
||||
|
||||
// HandleAuthLogin godoc
|
||||
// @Summary User Login
|
||||
// @Tags Authentication
|
||||
// @Accept x-www-form-urlencoded
|
||||
// @Accept application/json
|
||||
// @Param username formData string false "string" example(admin@admin.com)
|
||||
// @Param password formData string false "string" example(admin)
|
||||
// @Produce json
|
||||
// @Success 200 {object} TokenResponse
|
||||
// @Router /v1/users/login [POST]
|
||||
func (ctrl *V1Controller) HandleAuthLogin() server.HandlerFunc {
|
||||
//
|
||||
// @Summary User Login
|
||||
// @Tags Authentication
|
||||
// @Accept x-www-form-urlencoded
|
||||
// @Accept application/json
|
||||
// @Param username formData string false "string" example(admin@admin.com)
|
||||
// @Param password formData string false "string" example(admin)
|
||||
// @Param payload body LoginForm true "Login Data"
|
||||
// @Produce json
|
||||
// @Success 200 {object} TokenResponse
|
||||
// @Router /v1/users/login [POST]
|
||||
func (ctrl *V1Controller) HandleAuthLogin() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
loginForm := &LoginForm{}
|
||||
|
||||
switch r.Header.Get("Content-Type") {
|
||||
case server.ContentFormUrlEncoded:
|
||||
case "application/x-www-form-urlencoded":
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
return server.Respond(w, http.StatusBadRequest, server.Wrap(err))
|
||||
return errors.New("failed to parse form")
|
||||
}
|
||||
|
||||
loginForm.Username = r.PostFormValue("username")
|
||||
loginForm.Password = r.PostFormValue("password")
|
||||
case server.ContentJSON:
|
||||
loginForm.StayLoggedIn = r.PostFormValue("stayLoggedIn") == "true"
|
||||
case "application/json":
|
||||
err := server.Decode(r, loginForm)
|
||||
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to decode login form")
|
||||
return errors.New("failed to decode login form")
|
||||
}
|
||||
default:
|
||||
return server.Respond(w, http.StatusBadRequest, errors.New("invalid content type"))
|
||||
return server.JSON(w, http.StatusBadRequest, errors.New("invalid content type"))
|
||||
}
|
||||
|
||||
if loginForm.Username == "" || loginForm.Password == "" {
|
||||
@@ -69,26 +76,27 @@ 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, loginForm.StayLoggedIn)
|
||||
if err != nil {
|
||||
return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusOK, TokenResponse{
|
||||
Token: "Bearer " + newToken.Raw,
|
||||
ExpiresAt: newToken.ExpiresAt,
|
||||
return server.JSON(w, http.StatusOK, TokenResponse{
|
||||
Token: "Bearer " + newToken.Raw,
|
||||
ExpiresAt: newToken.ExpiresAt,
|
||||
AttachmentToken: newToken.AttachmentToken,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAuthLogout godoc
|
||||
// @Summary User Logout
|
||||
// @Tags Authentication
|
||||
// @Success 204
|
||||
// @Router /v1/users/logout [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAuthLogout() server.HandlerFunc {
|
||||
//
|
||||
// @Summary User Logout
|
||||
// @Tags Authentication
|
||||
// @Success 204
|
||||
// @Router /v1/users/logout [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAuthLogout() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
token := services.UseTokenCtx(r.Context())
|
||||
if token == "" {
|
||||
@@ -100,19 +108,20 @@ func (ctrl *V1Controller) HandleAuthLogout() server.HandlerFunc {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusNoContent, nil)
|
||||
return server.JSON(w, http.StatusNoContent, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAuthLogout godoc
|
||||
// @Summary User Token Refresh
|
||||
// @Description handleAuthRefresh returns a handler that will issue a new token from an existing token.
|
||||
// @Description This does not validate that the user still exists within the database.
|
||||
// @Tags Authentication
|
||||
// @Success 200
|
||||
// @Router /v1/users/refresh [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAuthRefresh() server.HandlerFunc {
|
||||
//
|
||||
// @Summary User Token Refresh
|
||||
// @Description handleAuthRefresh returns a handler that will issue a new token from an existing token.
|
||||
// @Description This does not validate that the user still exists within the database.
|
||||
// @Tags Authentication
|
||||
// @Success 200
|
||||
// @Router /v1/users/refresh [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAuthRefresh() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
requestToken := services.UseTokenCtx(r.Context())
|
||||
if requestToken == "" {
|
||||
@@ -124,6 +133,6 @@ func (ctrl *V1Controller) HandleAuthRefresh() server.HandlerFunc {
|
||||
return validate.NewUnauthorizedError()
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusOK, newToken)
|
||||
return server.JSON(w, http.StatusOK, newToken)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,13 @@ import (
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
)
|
||||
|
||||
type (
|
||||
GroupInvitationCreate struct {
|
||||
Uses int `json:"uses"`
|
||||
Uses int `json:"uses" validate:"required,min=1,max=100"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
}
|
||||
|
||||
@@ -25,113 +24,65 @@ type (
|
||||
)
|
||||
|
||||
// HandleGroupGet godoc
|
||||
// @Summary Get the current user's group
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.GroupStatistics
|
||||
// @Router /v1/groups/statistics [Get]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupStatistics() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
|
||||
stats, err := ctrl.repo.Groups.GroupStatistics(ctx, ctx.GID)
|
||||
if err != nil {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusOK, stats)
|
||||
//
|
||||
// @Summary Get Group
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.Group
|
||||
// @Router /v1/groups [Get]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupGet() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) (repo.Group, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Groups.GroupByID(auth, auth.GID)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleGroupGet godoc
|
||||
// @Summary Get the current user's group
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.Group
|
||||
// @Router /v1/groups [Get]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupGet() server.HandlerFunc {
|
||||
return ctrl.handleGroupGeneral()
|
||||
return adapters.Command(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleGroupUpdate godoc
|
||||
// @Summary Updates some fields of the current users group
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Param payload body repo.GroupUpdate true "User Data"
|
||||
// @Success 200 {object} repo.Group
|
||||
// @Router /v1/groups [Put]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupUpdate() server.HandlerFunc {
|
||||
return ctrl.handleGroupGeneral()
|
||||
}
|
||||
|
||||
func (ctrl *V1Controller) handleGroupGeneral() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
group, err := ctrl.repo.Groups.GroupByID(ctx, ctx.GID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to get group")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusOK, group)
|
||||
|
||||
case http.MethodPut:
|
||||
data := repo.GroupUpdate{}
|
||||
if err := server.Decode(r, &data); err != nil {
|
||||
return validate.NewRequestError(err, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
group, err := ctrl.svc.Group.UpdateGroup(ctx, data)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to update group")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusOK, group)
|
||||
}
|
||||
|
||||
return nil
|
||||
//
|
||||
// @Summary Update Group
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Param payload body repo.GroupUpdate true "User Data"
|
||||
// @Success 200 {object} repo.Group
|
||||
// @Router /v1/groups [Put]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupUpdate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, body repo.GroupUpdate) (repo.Group, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.svc.Group.UpdateGroup(auth, body)
|
||||
}
|
||||
|
||||
return adapters.Action(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleGroupInvitationsCreate godoc
|
||||
// @Summary Get the current user
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Param payload body GroupInvitationCreate true "User Data"
|
||||
// @Success 200 {object} GroupInvitation
|
||||
// @Router /v1/groups/invitations [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupInvitationsCreate() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
data := GroupInvitationCreate{}
|
||||
if err := server.Decode(r, &data); err != nil {
|
||||
log.Err(err).Msg("failed to decode user registration data")
|
||||
return validate.NewRequestError(err, http.StatusBadRequest)
|
||||
//
|
||||
// @Summary Create Group Invitation
|
||||
// @Tags Group
|
||||
// @Produce json
|
||||
// @Param payload body GroupInvitationCreate true "User Data"
|
||||
// @Success 200 {object} GroupInvitation
|
||||
// @Router /v1/groups/invitations [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupInvitationsCreate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, body GroupInvitationCreate) (GroupInvitation, error) {
|
||||
if body.ExpiresAt.IsZero() {
|
||||
body.ExpiresAt = time.Now().Add(time.Hour * 24)
|
||||
}
|
||||
|
||||
if data.ExpiresAt.IsZero() {
|
||||
data.ExpiresAt = time.Now().Add(time.Hour * 24)
|
||||
}
|
||||
auth := services.NewContext(r.Context())
|
||||
|
||||
ctx := services.NewContext(r.Context())
|
||||
token, err := ctrl.svc.Group.NewInvitation(auth, body.Uses, body.ExpiresAt)
|
||||
|
||||
token, err := ctrl.svc.Group.NewInvitation(ctx, data.Uses, data.ExpiresAt)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to create new token")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusCreated, GroupInvitation{
|
||||
return GroupInvitation{
|
||||
Token: token,
|
||||
ExpiresAt: data.ExpiresAt,
|
||||
Uses: data.Uses,
|
||||
})
|
||||
ExpiresAt: body.ExpiresAt,
|
||||
Uses: body.Uses,
|
||||
}, err
|
||||
}
|
||||
|
||||
return adapters.Action(fn, http.StatusCreated)
|
||||
}
|
||||
|
||||
@@ -1,171 +1,223 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
"github.com/hay-kot/safeserve/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// HandleItemsGetAll godoc
|
||||
// @Summary Get All Items
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param q query string false "search string"
|
||||
// @Param page query int false "page number"
|
||||
// @Param pageSize query int false "items per page"
|
||||
// @Param labels query []string false "label Ids" collectionFormat(multi)
|
||||
// @Param locations query []string false "location Ids" collectionFormat(multi)
|
||||
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
|
||||
// @Router /v1/items [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemsGetAll() server.HandlerFunc {
|
||||
|
||||
//
|
||||
// @Summary Query All Items
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param q query string false "search string"
|
||||
// @Param page query int false "page number"
|
||||
// @Param pageSize query int false "items per page"
|
||||
// @Param labels query []string false "label Ids" collectionFormat(multi)
|
||||
// @Param locations query []string false "location Ids" collectionFormat(multi)
|
||||
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
|
||||
// @Router /v1/items [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemsGetAll() errchain.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("perPage")),
|
||||
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) {
|
||||
return server.JSON(w, http.StatusOK, repo.PaginationResult[repo.ItemSummary]{
|
||||
Items: []repo.ItemSummary{},
|
||||
})
|
||||
}
|
||||
log.Err(err).Msg("failed to get items")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusOK, items)
|
||||
return server.JSON(w, http.StatusOK, items)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleItemsCreate godoc
|
||||
// @Summary Create a new item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param payload body repo.ItemCreate true "Item Data"
|
||||
// @Success 200 {object} repo.ItemSummary
|
||||
// @Router /v1/items [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemsCreate() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
createData := repo.ItemCreate{}
|
||||
if err := server.Decode(r, &createData); err != nil {
|
||||
log.Err(err).Msg("failed to decode request body")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
user := services.UseUserCtx(r.Context())
|
||||
item, err := ctrl.repo.Items.Create(r.Context(), user.GroupID, createData)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to create item")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusCreated, item)
|
||||
//
|
||||
// @Summary Create Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param payload body repo.ItemCreate true "Item Data"
|
||||
// @Success 201 {object} repo.ItemSummary
|
||||
// @Router /v1/items [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemsCreate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, body repo.ItemCreate) (repo.ItemOut, error) {
|
||||
return ctrl.svc.Items.Create(services.NewContext(r.Context()), body)
|
||||
}
|
||||
|
||||
return adapters.Action(fn, http.StatusCreated)
|
||||
}
|
||||
|
||||
// HandleItemGet godocs
|
||||
// @Summary Gets a item and fields
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemGet() server.HandlerFunc {
|
||||
return ctrl.handleItemsGeneral()
|
||||
//
|
||||
// @Summary Get Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemGet() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (repo.ItemOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
|
||||
return ctrl.repo.Items.GetOneByGroup(auth, auth.GID, ID)
|
||||
}
|
||||
|
||||
return adapters.CommandID("id", fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleItemDelete godocs
|
||||
// @Summary deletes a item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Success 204
|
||||
// @Router /v1/items/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemDelete() server.HandlerFunc {
|
||||
return ctrl.handleItemsGeneral()
|
||||
//
|
||||
// @Summary Delete Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Success 204
|
||||
// @Router /v1/items/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemDelete() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
err := ctrl.repo.Items.DeleteByGroup(auth, auth.GID, ID)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return adapters.CommandID("id", fn, http.StatusNoContent)
|
||||
}
|
||||
|
||||
// HandleItemUpdate godocs
|
||||
// @Summary updates a item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param payload body repo.ItemUpdate true "Item Data"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemUpdate() server.HandlerFunc {
|
||||
return ctrl.handleItemsGeneral()
|
||||
//
|
||||
// @Summary Update Item
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param payload body repo.ItemUpdate true "Item Data"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemUpdate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID, body repo.ItemUpdate) (repo.ItemOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
|
||||
body.ID = ID
|
||||
return ctrl.repo.Items.UpdateByGroup(auth, auth.GID, body)
|
||||
}
|
||||
|
||||
return adapters.ActionID("id", fn, http.StatusOK)
|
||||
}
|
||||
|
||||
func (ctrl *V1Controller) handleItemsGeneral() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
ID, err := ctrl.routeID(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
items, err := ctrl.repo.Items.GetOneByGroup(r.Context(), ctx.GID, ID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to get item")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusOK, items)
|
||||
case http.MethodDelete:
|
||||
err = ctrl.repo.Items.DeleteByGroup(r.Context(), ctx.GID, ID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to delete item")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusNoContent, nil)
|
||||
case http.MethodPut:
|
||||
body := repo.ItemUpdate{}
|
||||
if err := server.Decode(r, &body); err != nil {
|
||||
log.Err(err).Msg("failed to decode request body")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
body.ID = ID
|
||||
result, err := ctrl.repo.Items.UpdateByGroup(r.Context(), ctx.GID, body)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to update item")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
return nil
|
||||
// HandleGetAllCustomFieldNames godocs
|
||||
//
|
||||
// @Summary Get All Custom Field Names
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Success 200
|
||||
// @Router /v1/items/fields [GET]
|
||||
// @Success 200 {object} []string
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGetAllCustomFieldNames() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) ([]string, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Items.GetAllCustomFieldNames(auth, auth.GID)
|
||||
}
|
||||
|
||||
return adapters.Command(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleGetAllCustomFieldValues godocs
|
||||
//
|
||||
// @Summary Get All Custom Field Values
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Success 200
|
||||
// @Router /v1/items/fields/values [GET]
|
||||
// @Success 200 {object} []string
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGetAllCustomFieldValues() errchain.HandlerFunc {
|
||||
type query struct {
|
||||
Field string `schema:"field" validate:"required"`
|
||||
}
|
||||
|
||||
fn := func(r *http.Request, q query) ([]string, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Items.GetAllCustomFieldValues(auth, auth.GID, q.Field)
|
||||
}
|
||||
|
||||
return adapters.Action(fn, http.StatusOK)
|
||||
|
||||
}
|
||||
|
||||
// HandleItemsImport godocs
|
||||
// @Summary imports items into the database
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Param csv formData file true "Image to upload"
|
||||
// @Router /v1/items/import [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemsImport() server.HandlerFunc {
|
||||
//
|
||||
// @Summary Import Items
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Param csv formData file true "Image to upload"
|
||||
// @Router /v1/items/import [Post]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemsImport() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
|
||||
err := r.ParseMultipartForm(ctrl.maxUploadSize << 20)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to parse multipart form")
|
||||
@@ -178,21 +230,40 @@ func (ctrl *V1Controller) HandleItemsImport() server.HandlerFunc {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
reader := csv.NewReader(file)
|
||||
data, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to read csv")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
user := services.UseUserCtx(r.Context())
|
||||
|
||||
_, err = ctrl.svc.Items.CsvImport(r.Context(), user.GroupID, data)
|
||||
_, err = ctrl.svc.Items.CsvImport(r.Context(), user.GroupID, file)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to import items")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusNoContent, nil)
|
||||
return server.JSON(w, http.StatusNoContent, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleItemsExport godocs
|
||||
//
|
||||
// @Summary Export Items
|
||||
// @Tags Items
|
||||
// @Success 200 {string} string "text/csv"
|
||||
// @Router /v1/items/export [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemsExport() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
|
||||
csvData, err := ctrl.svc.Items.ExportTSV(r.Context(), ctx.GID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to export items")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/tsv")
|
||||
w.Header().Set("Content-Disposition", "attachment;filename=homebox-items.tsv")
|
||||
|
||||
writer := csv.NewWriter(w)
|
||||
writer.Comma = '\t'
|
||||
return writer.WriteAll(csvData)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@ package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
"github.com/hay-kot/safeserve/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
@@ -19,19 +19,20 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// HandleItemsImport godocs
|
||||
// @Summary imports items into the database
|
||||
// @Tags Items Attachments
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param file formData file true "File attachment"
|
||||
// @Param type formData string true "Type of file"
|
||||
// @Param name formData string true "name of the file including extension"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Failure 422 {object} server.ErrorResponse
|
||||
// @Router /v1/items/{id}/attachments [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentCreate() server.HandlerFunc {
|
||||
// HandleItemAttachmentCreate godocs
|
||||
//
|
||||
// @Summary Create Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Produce json
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param file formData file true "File attachment"
|
||||
// @Param type formData string true "Type of file"
|
||||
// @Param name formData string true "name of the file including extension"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Failure 422 {object} mid.ErrorResponse
|
||||
// @Router /v1/items/{id}/attachments [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
err := r.ParseMultipartForm(ctrl.maxUploadSize << 20)
|
||||
if err != nil {
|
||||
@@ -61,7 +62,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() server.HandlerFunc {
|
||||
}
|
||||
|
||||
if !errs.Nil() {
|
||||
return server.Respond(w, http.StatusUnprocessableEntity, errs)
|
||||
return server.JSON(w, http.StatusUnprocessableEntity, errs)
|
||||
}
|
||||
|
||||
attachmentType := r.FormValue("type")
|
||||
@@ -83,78 +84,53 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() server.HandlerFunc {
|
||||
attachment.Type(attachmentType),
|
||||
file,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to add attachment")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusCreated, item)
|
||||
return server.JSON(w, http.StatusCreated, item)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleItemAttachmentGet godocs
|
||||
// @Summary retrieves an attachment for an item
|
||||
// @Tags Items Attachments
|
||||
// @Produce application/octet-stream
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param token query string true "Attachment token"
|
||||
// @Success 200
|
||||
// @Router /v1/items/{id}/attachments/download [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentDownload() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
token := server.GetParam(r, "token", "")
|
||||
|
||||
doc, err := ctrl.svc.Items.AttachmentPath(r.Context(), token)
|
||||
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to get attachment")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", doc.Title))
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
http.ServeFile(w, r, doc.Path)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// HandleItemAttachmentToken godocs
|
||||
// @Summary retrieves an attachment for an item
|
||||
// @Tags Items Attachments
|
||||
// @Produce application/octet-stream
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Success 200 {object} ItemAttachmentToken
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentToken() server.HandlerFunc {
|
||||
//
|
||||
// @Summary Get Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Produce application/octet-stream
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Success 200 {object} ItemAttachmentToken
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentGet() errchain.HandlerFunc {
|
||||
return ctrl.handleItemAttachmentsHandler
|
||||
}
|
||||
|
||||
// HandleItemAttachmentDelete godocs
|
||||
// @Summary retrieves an attachment for an item
|
||||
// @Tags Items Attachments
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Success 204
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentDelete() server.HandlerFunc {
|
||||
//
|
||||
// @Summary Delete Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Success 204
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentDelete() errchain.HandlerFunc {
|
||||
return ctrl.handleItemAttachmentsHandler
|
||||
}
|
||||
|
||||
// HandleItemAttachmentUpdate godocs
|
||||
// @Summary retrieves an attachment for an item
|
||||
// @Tags Items Attachments
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Param payload body repo.ItemAttachmentUpdate true "Attachment Update"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentUpdate() server.HandlerFunc {
|
||||
//
|
||||
// @Summary Update Item Attachment
|
||||
// @Tags Items Attachments
|
||||
// @Param id path string true "Item ID"
|
||||
// @Param attachment_id path string true "Attachment ID"
|
||||
// @Param payload body repo.ItemAttachmentUpdate true "Attachment Update"
|
||||
// @Success 200 {object} repo.ItemOut
|
||||
// @Router /v1/items/{id}/attachments/{attachment_id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleItemAttachmentUpdate() errchain.HandlerFunc {
|
||||
return ctrl.handleItemAttachmentsHandler
|
||||
}
|
||||
|
||||
@@ -171,33 +147,15 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
|
||||
|
||||
ctx := services.NewContext(r.Context())
|
||||
switch r.Method {
|
||||
// Token Handler
|
||||
case http.MethodGet:
|
||||
token, err := ctrl.svc.Items.AttachmentToken(ctx, ID, attachmentID)
|
||||
doc, err := ctrl.svc.Items.AttachmentPath(r.Context(), attachmentID)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case services.ErrNotFound:
|
||||
log.Err(err).
|
||||
Str("id", attachmentID.String()).
|
||||
Msg("failed to find attachment with id")
|
||||
|
||||
return validate.NewRequestError(err, http.StatusNotFound)
|
||||
|
||||
case services.ErrFileNotFound:
|
||||
log.Err(err).
|
||||
Str("id", attachmentID.String()).
|
||||
Msg("failed to find file path for attachment with id")
|
||||
log.Warn().Msg("attachment with no file path removed from database")
|
||||
|
||||
return validate.NewRequestError(err, http.StatusNotFound)
|
||||
|
||||
default:
|
||||
log.Err(err).Msg("failed to get attachment")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
log.Err(err).Msg("failed to get attachment path")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusOK, ItemAttachmentToken{Token: token})
|
||||
http.ServeFile(w, r, doc.Path)
|
||||
return nil
|
||||
|
||||
// Delete Attachment Handler
|
||||
case http.MethodDelete:
|
||||
@@ -207,7 +165,7 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusNoContent, nil)
|
||||
return server.JSON(w, http.StatusNoContent, nil)
|
||||
|
||||
// Update Attachment Handler
|
||||
case http.MethodPut:
|
||||
@@ -225,7 +183,7 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusOK, val)
|
||||
return server.JSON(w, http.StatusOK, val)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -3,141 +3,100 @@ package v1
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
)
|
||||
|
||||
// HandleLabelsGetAll godoc
|
||||
// @Summary Get All Labels
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Success 200 {object} server.Results{items=[]repo.LabelOut}
|
||||
// @Router /v1/labels [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelsGetAll() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
user := services.UseUserCtx(r.Context())
|
||||
labels, err := ctrl.repo.Labels.GetAll(r.Context(), user.GroupID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("error getting labels")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusOK, server.Results{Items: labels})
|
||||
//
|
||||
// @Summary Get All Labels
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.LabelOut
|
||||
// @Router /v1/labels [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelsGetAll() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) ([]repo.LabelSummary, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Labels.GetAll(auth, auth.GID)
|
||||
}
|
||||
|
||||
return adapters.Command(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleLabelsCreate godoc
|
||||
// @Summary Create a new label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param payload body repo.LabelCreate true "Label Data"
|
||||
// @Success 200 {object} repo.LabelSummary
|
||||
// @Router /v1/labels [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelsCreate() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
createData := repo.LabelCreate{}
|
||||
if err := server.Decode(r, &createData); err != nil {
|
||||
log.Err(err).Msg("error decoding label create data")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
user := services.UseUserCtx(r.Context())
|
||||
label, err := ctrl.repo.Labels.Create(r.Context(), user.GroupID, createData)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("error creating label")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusCreated, label)
|
||||
//
|
||||
// @Summary Create Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param payload body repo.LabelCreate true "Label Data"
|
||||
// @Success 200 {object} repo.LabelSummary
|
||||
// @Router /v1/labels [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelsCreate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, data repo.LabelCreate) (repo.LabelOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Labels.Create(auth, auth.GID, data)
|
||||
}
|
||||
|
||||
return adapters.Action(fn, http.StatusCreated)
|
||||
}
|
||||
|
||||
// HandleLabelDelete godocs
|
||||
// @Summary deletes a label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 204
|
||||
// @Router /v1/labels/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelDelete() server.HandlerFunc {
|
||||
return ctrl.handleLabelsGeneral()
|
||||
//
|
||||
// @Summary Delete Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 204
|
||||
// @Router /v1/labels/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelDelete() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
err := ctrl.repo.Labels.DeleteByGroup(auth, auth.GID, ID)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return adapters.CommandID("id", fn, http.StatusNoContent)
|
||||
}
|
||||
|
||||
// HandleLabelGet godocs
|
||||
// @Summary Gets a label and fields
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 200 {object} repo.LabelOut
|
||||
// @Router /v1/labels/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelGet() server.HandlerFunc {
|
||||
return ctrl.handleLabelsGeneral()
|
||||
//
|
||||
// @Summary Get Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 200 {object} repo.LabelOut
|
||||
// @Router /v1/labels/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelGet() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (repo.LabelOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Labels.GetOneByGroup(auth, auth.GID, ID)
|
||||
}
|
||||
|
||||
return adapters.CommandID("id", fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleLabelUpdate godocs
|
||||
// @Summary updates a label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 200 {object} repo.LabelOut
|
||||
// @Router /v1/labels/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelUpdate() server.HandlerFunc {
|
||||
return ctrl.handleLabelsGeneral()
|
||||
}
|
||||
|
||||
func (ctrl *V1Controller) handleLabelsGeneral() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
ID, err := ctrl.routeID(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
labels, err := ctrl.repo.Labels.GetOneByGroup(r.Context(), ctx.GID, ID)
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
log.Err(err).
|
||||
Str("id", ID.String()).
|
||||
Msg("label not found")
|
||||
return validate.NewRequestError(err, http.StatusNotFound)
|
||||
}
|
||||
log.Err(err).Msg("error getting label")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusOK, labels)
|
||||
|
||||
case http.MethodDelete:
|
||||
err = ctrl.repo.Labels.DeleteByGroup(ctx, ctx.GID, ID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("error deleting label")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusNoContent, nil)
|
||||
|
||||
case http.MethodPut:
|
||||
body := repo.LabelUpdate{}
|
||||
if err := server.Decode(r, &body); err != nil {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
body.ID = ID
|
||||
result, err := ctrl.repo.Labels.UpdateByGroup(ctx, ctx.GID, body)
|
||||
if err != nil {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
return nil
|
||||
//
|
||||
// @Summary Update Label
|
||||
// @Tags Labels
|
||||
// @Produce json
|
||||
// @Param id path string true "Label ID"
|
||||
// @Success 200 {object} repo.LabelOut
|
||||
// @Router /v1/labels/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLabelUpdate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID, data repo.LabelUpdate) (repo.LabelOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
data.ID = ID
|
||||
return ctrl.repo.Labels.UpdateByGroup(auth, auth.GID, data)
|
||||
}
|
||||
|
||||
return adapters.ActionID("id", fn, http.StatusOK)
|
||||
}
|
||||
|
||||
@@ -3,154 +3,120 @@ package v1
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
)
|
||||
|
||||
// HandleLocationGetAll godoc
|
||||
// @Summary Get All Locations
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param filterChildren query bool false "Filter locations with parents"
|
||||
// @Success 200 {object} server.Results{items=[]repo.LocationOutCount}
|
||||
// @Router /v1/locations [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationGetAll() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
user := services.UseUserCtx(r.Context())
|
||||
|
||||
q := r.URL.Query()
|
||||
|
||||
filter := repo.LocationQuery{
|
||||
FilterChildren: queryBool(q.Get("filterChildren")),
|
||||
}
|
||||
|
||||
locations, err := ctrl.repo.Locations.GetAll(r.Context(), user.GroupID, filter)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to get locations")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusOK, server.Results{Items: locations})
|
||||
// HandleLocationTreeQuery
|
||||
//
|
||||
// @Summary Get Locations Tree
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param withItems query bool false "include items in response tree"
|
||||
// @Success 200 {object} []repo.TreeItem
|
||||
// @Router /v1/locations/tree [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationTreeQuery() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, query repo.TreeQuery) ([]repo.TreeItem, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Locations.Tree(auth, auth.GID, query)
|
||||
}
|
||||
|
||||
return adapters.Query(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleLocationCreate godoc
|
||||
// @Summary Create a new location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param payload body repo.LocationCreate true "Location Data"
|
||||
// @Success 200 {object} repo.LocationSummary
|
||||
// @Router /v1/locations [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationCreate() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
createData := repo.LocationCreate{}
|
||||
if err := server.Decode(r, &createData); err != nil {
|
||||
log.Err(err).Msg("failed to decode location create data")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
user := services.UseUserCtx(r.Context())
|
||||
location, err := ctrl.repo.Locations.Create(r.Context(), user.GroupID, createData)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to create location")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusCreated, location)
|
||||
// HandleLocationGetAll
|
||||
//
|
||||
// @Summary Get All Locations
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param filterChildren query bool false "Filter locations with parents"
|
||||
// @Success 200 {object} []repo.LocationOutCount
|
||||
// @Router /v1/locations [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationGetAll() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, q repo.LocationQuery) ([]repo.LocationOutCount, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Locations.GetAll(auth, auth.GID, q)
|
||||
}
|
||||
|
||||
return adapters.Query(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleLocationDelete godocs
|
||||
// @Summary deletes a location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Success 204
|
||||
// @Router /v1/locations/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationDelete() server.HandlerFunc {
|
||||
return ctrl.handleLocationGeneral()
|
||||
}
|
||||
|
||||
// HandleLocationGet godocs
|
||||
// @Summary Gets a location and fields
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Success 200 {object} repo.LocationOut
|
||||
// @Router /v1/locations/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationGet() server.HandlerFunc {
|
||||
return ctrl.handleLocationGeneral()
|
||||
}
|
||||
|
||||
// HandleLocationUpdate godocs
|
||||
// @Summary updates a location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Param payload body repo.LocationUpdate true "Location Data"
|
||||
// @Success 200 {object} repo.LocationOut
|
||||
// @Router /v1/locations/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationUpdate() server.HandlerFunc {
|
||||
return ctrl.handleLocationGeneral()
|
||||
}
|
||||
|
||||
func (ctrl *V1Controller) handleLocationGeneral() server.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
ID, err := ctrl.routeID(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
location, err := ctrl.repo.Locations.GetOneByGroup(r.Context(), ctx.GID, ID)
|
||||
if err != nil {
|
||||
l := log.Err(err).
|
||||
Str("ID", ID.String()).
|
||||
Str("GID", ctx.GID.String())
|
||||
|
||||
if ent.IsNotFound(err) {
|
||||
l.Msg("location not found")
|
||||
return validate.NewRequestError(err, http.StatusNotFound)
|
||||
}
|
||||
|
||||
l.Msg("failed to get location")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusOK, location)
|
||||
case http.MethodPut:
|
||||
body := repo.LocationUpdate{}
|
||||
if err := server.Decode(r, &body); err != nil {
|
||||
log.Err(err).Msg("failed to decode location update data")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
body.ID = ID
|
||||
|
||||
result, err := ctrl.repo.Locations.UpdateOneByGroup(r.Context(), ctx.GID, ID, body)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to update location")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusOK, result)
|
||||
case http.MethodDelete:
|
||||
err = ctrl.repo.Locations.DeleteByGroup(r.Context(), ctx.GID, ID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to delete location")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return server.Respond(w, http.StatusNoContent, nil)
|
||||
}
|
||||
return nil
|
||||
// HandleLocationCreate
|
||||
//
|
||||
// @Summary Create Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param payload body repo.LocationCreate true "Location Data"
|
||||
// @Success 200 {object} repo.LocationSummary
|
||||
// @Router /v1/locations [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationCreate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, createData repo.LocationCreate) (repo.LocationOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Locations.Create(auth, auth.GID, createData)
|
||||
}
|
||||
|
||||
return adapters.Action(fn, http.StatusCreated)
|
||||
}
|
||||
|
||||
// HandleLocationDelete
|
||||
//
|
||||
// @Summary Delete Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Success 204
|
||||
// @Router /v1/locations/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationDelete() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
err := ctrl.repo.Locations.DeleteByGroup(auth, auth.GID, ID)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return adapters.CommandID("id", fn, http.StatusNoContent)
|
||||
}
|
||||
|
||||
// HandleLocationGet
|
||||
//
|
||||
// @Summary Get Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Success 200 {object} repo.LocationOut
|
||||
// @Router /v1/locations/{id} [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationGet() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (repo.LocationOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Locations.GetOneByGroup(auth, auth.GID, ID)
|
||||
}
|
||||
|
||||
return adapters.CommandID("id", fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleLocationUpdate
|
||||
//
|
||||
// @Summary Update Location
|
||||
// @Tags Locations
|
||||
// @Produce json
|
||||
// @Param id path string true "Location ID"
|
||||
// @Param payload body repo.LocationUpdate true "Location Data"
|
||||
// @Success 200 {object} repo.LocationOut
|
||||
// @Router /v1/locations/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleLocationUpdate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID, body repo.LocationUpdate) (repo.LocationOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
body.ID = ID
|
||||
return ctrl.repo.Locations.UpdateByGroup(auth, auth.GID, ID, body)
|
||||
}
|
||||
|
||||
return adapters.ActionID("id", fn, http.StatusOK)
|
||||
}
|
||||
|
||||
82
backend/app/api/handlers/v1/v1_ctrl_maint_entry.go
Normal file
82
backend/app/api/handlers/v1/v1_ctrl_maint_entry.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
)
|
||||
|
||||
// HandleMaintenanceGetLog godoc
|
||||
//
|
||||
// @Summary Get Maintenance Log
|
||||
// @Tags Maintenance
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.MaintenanceLog
|
||||
// @Router /v1/items/{id}/maintenance [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleMaintenanceLogGet() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID, q repo.MaintenanceLogQuery) (repo.MaintenanceLog, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.MaintEntry.GetLog(auth, auth.GID, ID, q)
|
||||
}
|
||||
|
||||
return adapters.QueryID("id", fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleMaintenanceEntryCreate godoc
|
||||
//
|
||||
// @Summary Create Maintenance Entry
|
||||
// @Tags Maintenance
|
||||
// @Produce json
|
||||
// @Param payload body repo.MaintenanceEntryCreate true "Entry Data"
|
||||
// @Success 201 {object} repo.MaintenanceEntry
|
||||
// @Router /v1/items/{id}/maintenance [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleMaintenanceEntryCreate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, itemID uuid.UUID, body repo.MaintenanceEntryCreate) (repo.MaintenanceEntry, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.MaintEntry.Create(auth, itemID, body)
|
||||
}
|
||||
|
||||
return adapters.ActionID("id", fn, http.StatusCreated)
|
||||
}
|
||||
|
||||
// HandleMaintenanceEntryDelete godoc
|
||||
//
|
||||
// @Summary Delete Maintenance Entry
|
||||
// @Tags Maintenance
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Router /v1/items/{id}/maintenance/{entry_id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleMaintenanceEntryDelete() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, entryID uuid.UUID) (any, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
err := ctrl.repo.MaintEntry.Delete(auth, entryID)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return adapters.CommandID("entry_id", fn, http.StatusNoContent)
|
||||
}
|
||||
|
||||
// HandleMaintenanceEntryUpdate godoc
|
||||
//
|
||||
// @Summary Update Maintenance Entry
|
||||
// @Tags Maintenance
|
||||
// @Produce json
|
||||
// @Param payload body repo.MaintenanceEntryUpdate true "Entry Data"
|
||||
// @Success 200 {object} repo.MaintenanceEntry
|
||||
// @Router /v1/items/{id}/maintenance/{entry_id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleMaintenanceEntryUpdate() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, entryID uuid.UUID, body repo.MaintenanceEntryUpdate) (repo.MaintenanceEntry, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.MaintEntry.Update(auth, entryID, body)
|
||||
}
|
||||
|
||||
return adapters.ActionID("entry_id", fn, http.StatusOK)
|
||||
}
|
||||
105
backend/app/api/handlers/v1/v1_ctrl_notifiers.go
Normal file
105
backend/app/api/handlers/v1/v1_ctrl_notifiers.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/containrrr/shoutrrr"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
)
|
||||
|
||||
// HandleGetUserNotifiers godoc
|
||||
//
|
||||
// @Summary Get Notifiers
|
||||
// @Tags Notifiers
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.NotifierOut
|
||||
// @Router /v1/notifiers [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGetUserNotifiers() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, _ struct{}) ([]repo.NotifierOut, error) {
|
||||
user := services.UseUserCtx(r.Context())
|
||||
return ctrl.repo.Notifiers.GetByUser(r.Context(), user.ID)
|
||||
}
|
||||
|
||||
return adapters.Query(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleCreateNotifier godoc
|
||||
//
|
||||
// @Summary Create Notifier
|
||||
// @Tags Notifiers
|
||||
// @Produce json
|
||||
// @Param payload body repo.NotifierCreate true "Notifier Data"
|
||||
// @Success 200 {object} repo.NotifierOut
|
||||
// @Router /v1/notifiers [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleCreateNotifier() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, in repo.NotifierCreate) (repo.NotifierOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Notifiers.Create(auth, auth.GID, auth.UID, in)
|
||||
}
|
||||
|
||||
return adapters.Action(fn, http.StatusCreated)
|
||||
}
|
||||
|
||||
// HandleDeleteNotifier godocs
|
||||
//
|
||||
// @Summary Delete a Notifier
|
||||
// @Tags Notifiers
|
||||
// @Param id path string true "Notifier ID"
|
||||
// @Success 204
|
||||
// @Router /v1/notifiers/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleDeleteNotifier() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return nil, ctrl.repo.Notifiers.Delete(auth, auth.UID, ID)
|
||||
}
|
||||
|
||||
return adapters.CommandID("id", fn, http.StatusNoContent)
|
||||
}
|
||||
|
||||
// HandleUpdateNotifier godocs
|
||||
//
|
||||
// @Summary Update Notifier
|
||||
// @Tags Notifiers
|
||||
// @Param id path string true "Notifier ID"
|
||||
// @Param payload body repo.NotifierUpdate true "Notifier Data"
|
||||
// @Success 200 {object} repo.NotifierOut
|
||||
// @Router /v1/notifiers/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUpdateNotifier() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request, ID uuid.UUID, in repo.NotifierUpdate) (repo.NotifierOut, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Notifiers.Update(auth, auth.UID, ID, in)
|
||||
}
|
||||
|
||||
return adapters.ActionID("id", fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandlerNotifierTest godoc
|
||||
//
|
||||
// @Summary Test Notifier
|
||||
// @Tags Notifiers
|
||||
// @Produce json
|
||||
// @Param id path string true "Notifier ID"
|
||||
// @Param url query string true "URL"
|
||||
// @Success 204
|
||||
// @Router /v1/notifiers/test [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandlerNotifierTest() errchain.HandlerFunc {
|
||||
type body struct {
|
||||
URL string `json:"url" validate:"required"`
|
||||
}
|
||||
|
||||
fn := func(r *http.Request, q body) (any, error) {
|
||||
err := shoutrrr.Send(q.URL, "Test message from Homebox")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return adapters.Action(fn, http.StatusOK)
|
||||
}
|
||||
66
backend/app/api/handlers/v1/v1_ctrl_qrcode.go
Normal file
66
backend/app/api/handlers/v1/v1_ctrl_qrcode.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image/png"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
"github.com/yeqown/go-qrcode/v2"
|
||||
"github.com/yeqown/go-qrcode/writer/standard"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
//go:embed assets/QRIcon.png
|
||||
var qrcodeLogo []byte
|
||||
|
||||
// HandleGenerateQRCode godoc
|
||||
//
|
||||
// @Summary Create QR Code
|
||||
// @Tags Items
|
||||
// @Produce json
|
||||
// @Param data query string false "data to be encoded into qrcode"
|
||||
// @Success 200 {string} string "image/jpeg"
|
||||
// @Router /v1/qrcode [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGenerateQRCode() errchain.HandlerFunc {
|
||||
type query struct {
|
||||
// 4,296 characters is the maximum length of a QR code
|
||||
Data string `schema:"data" validate:"required,max=4296"`
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
q, err := adapters.DecodeQuery[query](r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
image, err := png.Decode(bytes.NewReader(qrcodeLogo))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
qrc, err := qrcode.New(q.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toWriteCloser := struct {
|
||||
io.Writer
|
||||
io.Closer
|
||||
}{
|
||||
Writer: w,
|
||||
Closer: io.NopCloser(nil),
|
||||
}
|
||||
|
||||
qrwriter := standard.NewWithWriter(toWriteCloser, standard.WithLogoImage(image))
|
||||
|
||||
// Return the QR code as a jpeg image
|
||||
w.Header().Set("Content-Type", "image/jpeg")
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=qrcode.jpg")
|
||||
return qrc.Save(qrwriter)
|
||||
}
|
||||
}
|
||||
32
backend/app/api/handlers/v1/v1_ctrl_reporting.go
Normal file
32
backend/app/api/handlers/v1/v1_ctrl_reporting.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
)
|
||||
|
||||
// HandleBillOfMaterialsExport godoc
|
||||
//
|
||||
// @Summary Export Bill of Materials
|
||||
// @Tags Reporting
|
||||
// @Produce json
|
||||
// @Success 200 {string} string "text/csv"
|
||||
// @Router /v1/reporting/bill-of-materials [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleBillOfMaterialsExport() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
actor := services.UseUserCtx(r.Context())
|
||||
|
||||
csv, err := ctrl.svc.Items.ExportBillOfMaterialsTSV(r.Context(), actor.GroupID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/tsv")
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=bill-of-materials.tsv")
|
||||
_, err = w.Write(csv)
|
||||
return err
|
||||
}
|
||||
}
|
||||
104
backend/app/api/handlers/v1/v1_ctrl_statistics.go
Normal file
104
backend/app/api/handlers/v1/v1_ctrl_statistics.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
"github.com/hay-kot/safeserve/server"
|
||||
)
|
||||
|
||||
// HandleGroupGet godoc
|
||||
//
|
||||
// @Summary Get Location Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.TotalsByOrganizer
|
||||
// @Router /v1/groups/statistics/locations [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupStatisticsLocations() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) ([]repo.TotalsByOrganizer, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Groups.StatsLocationsByPurchasePrice(auth, auth.GID)
|
||||
}
|
||||
|
||||
return adapters.Command(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleGroupStatisticsLabels godoc
|
||||
//
|
||||
// @Summary Get Label Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} []repo.TotalsByOrganizer
|
||||
// @Router /v1/groups/statistics/labels [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupStatisticsLabels() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) ([]repo.TotalsByOrganizer, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Groups.StatsLabelsByPurchasePrice(auth, auth.GID)
|
||||
}
|
||||
|
||||
return adapters.Command(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleGroupStatistics godoc
|
||||
//
|
||||
// @Summary Get Group Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.GroupStatistics
|
||||
// @Router /v1/groups/statistics [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupStatistics() errchain.HandlerFunc {
|
||||
fn := func(r *http.Request) (repo.GroupStatistics, error) {
|
||||
auth := services.NewContext(r.Context())
|
||||
return ctrl.repo.Groups.StatsGroup(auth, auth.GID)
|
||||
}
|
||||
|
||||
return adapters.Command(fn, http.StatusOK)
|
||||
}
|
||||
|
||||
// HandleGroupStatisticsPriceOverTime godoc
|
||||
//
|
||||
// @Summary Get Purchase Price Statistics
|
||||
// @Tags Statistics
|
||||
// @Produce json
|
||||
// @Success 200 {object} repo.ValueOverTime
|
||||
// @Param start query string false "start date"
|
||||
// @Param end query string false "end date"
|
||||
// @Router /v1/groups/statistics/purchase-price [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleGroupStatisticsPriceOverTime() errchain.HandlerFunc {
|
||||
parseDate := func(datestr string, defaultDate time.Time) (time.Time, error) {
|
||||
if datestr == "" {
|
||||
return defaultDate, nil
|
||||
}
|
||||
return time.Parse("2006-01-02", datestr)
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := services.NewContext(r.Context())
|
||||
|
||||
startDate, err := parseDate(r.URL.Query().Get("start"), time.Now().AddDate(0, -1, 0))
|
||||
if err != nil {
|
||||
return validate.NewRequestError(err, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
endDate, err := parseDate(r.URL.Query().Get("end"), time.Now())
|
||||
if err != nil {
|
||||
return validate.NewRequestError(err, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
stats, err := ctrl.repo.Groups.StatsPurchasePrice(ctx, ctx.GID, startDate, endDate)
|
||||
if err != nil {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.JSON(w, http.StatusOK, stats)
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,27 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
"github.com/hay-kot/safeserve/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// HandleUserSelf godoc
|
||||
// @Summary Get the current user
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Param payload body services.UserRegistration true "User Data"
|
||||
// @Success 204
|
||||
// @Router /v1/users/register [Post]
|
||||
func (ctrl *V1Controller) HandleUserRegistration() server.HandlerFunc {
|
||||
// HandleUserRegistration godoc
|
||||
//
|
||||
// @Summary Register New User
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Param payload body services.UserRegistration true "User Data"
|
||||
// @Success 204
|
||||
// @Router /v1/users/register [Post]
|
||||
func (ctrl *V1Controller) HandleUserRegistration() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
regData := services.UserRegistration{}
|
||||
|
||||
@@ -28,7 +31,7 @@ func (ctrl *V1Controller) HandleUserRegistration() server.HandlerFunc {
|
||||
}
|
||||
|
||||
if !ctrl.allowRegistration && regData.GroupToken == "" {
|
||||
return validate.NewRequestError(nil, http.StatusForbidden)
|
||||
return validate.NewRequestError(fmt.Errorf("user registration disabled"), http.StatusForbidden)
|
||||
}
|
||||
|
||||
_, err := ctrl.svc.User.RegisterUser(r.Context(), regData)
|
||||
@@ -37,18 +40,19 @@ func (ctrl *V1Controller) HandleUserRegistration() server.HandlerFunc {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusNoContent, nil)
|
||||
return server.JSON(w, http.StatusNoContent, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleUserSelf godoc
|
||||
// @Summary Get the current user
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Success 200 {object} server.Result{item=repo.UserOut}
|
||||
// @Router /v1/users/self [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelf() server.HandlerFunc {
|
||||
//
|
||||
// @Summary Get User Self
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Success 200 {object} Wrapped{item=repo.UserOut}
|
||||
// @Router /v1/users/self [GET]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelf() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
token := services.UseTokenCtx(r.Context())
|
||||
usr, err := ctrl.svc.User.GetSelf(r.Context(), token)
|
||||
@@ -57,19 +61,20 @@ func (ctrl *V1Controller) HandleUserSelf() server.HandlerFunc {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusOK, server.Wrap(usr))
|
||||
return server.JSON(w, http.StatusOK, Wrap(usr))
|
||||
}
|
||||
}
|
||||
|
||||
// HandleUserSelfUpdate godoc
|
||||
// @Summary Update the current user
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Param payload body repo.UserUpdate true "User Data"
|
||||
// @Success 200 {object} server.Result{item=repo.UserUpdate}
|
||||
// @Router /v1/users/self [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelfUpdate() server.HandlerFunc {
|
||||
//
|
||||
// @Summary Update Account
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Param payload body repo.UserUpdate true "User Data"
|
||||
// @Success 200 {object} Wrapped{item=repo.UserUpdate}
|
||||
// @Router /v1/users/self [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelfUpdate() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
updateData := repo.UserUpdate{}
|
||||
if err := server.Decode(r, &updateData); err != nil {
|
||||
@@ -79,23 +84,23 @@ func (ctrl *V1Controller) HandleUserSelfUpdate() server.HandlerFunc {
|
||||
|
||||
actor := services.UseUserCtx(r.Context())
|
||||
newData, err := ctrl.svc.User.UpdateSelf(r.Context(), actor.ID, updateData)
|
||||
|
||||
if err != nil {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusOK, server.Wrap(newData))
|
||||
return server.JSON(w, http.StatusOK, Wrap(newData))
|
||||
}
|
||||
}
|
||||
|
||||
// HandleUserSelfDelete godoc
|
||||
// @Summary Deletes the user account
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Router /v1/users/self [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelfDelete() server.HandlerFunc {
|
||||
//
|
||||
// @Summary Delete Account
|
||||
// @Tags User
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Router /v1/users/self [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelfDelete() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
if ctrl.isDemo {
|
||||
return validate.NewRequestError(nil, http.StatusForbidden)
|
||||
@@ -106,7 +111,7 @@ func (ctrl *V1Controller) HandleUserSelfDelete() server.HandlerFunc {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusNoContent, nil)
|
||||
return server.JSON(w, http.StatusNoContent, nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,13 +123,14 @@ type (
|
||||
)
|
||||
|
||||
// HandleUserSelfChangePassword godoc
|
||||
// @Summary Updates the users password
|
||||
// @Tags User
|
||||
// @Success 204
|
||||
// @Param payload body ChangePassword true "Password Payload"
|
||||
// @Router /v1/users/change-password [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelfChangePassword() server.HandlerFunc {
|
||||
//
|
||||
// @Summary Change Password
|
||||
// @Tags User
|
||||
// @Success 204
|
||||
// @Param payload body ChangePassword true "Password Payload"
|
||||
// @Router /v1/users/change-password [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleUserSelfChangePassword() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
if ctrl.isDemo {
|
||||
return validate.NewRequestError(nil, http.StatusForbidden)
|
||||
@@ -143,6 +149,6 @@ func (ctrl *V1Controller) HandleUserSelfChangePassword() server.HandlerFunc {
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return server.Respond(w, http.StatusNoContent, nil)
|
||||
return server.JSON(w, http.StatusNoContent, nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -9,6 +10,9 @@ import (
|
||||
|
||||
atlas "ariga.io/atlas/sql/migrate"
|
||||
"entgo.io/ent/dialect/sql/schema"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/app/api/static/docs"
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||
@@ -16,9 +20,13 @@ import (
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/config"
|
||||
"github.com/hay-kot/homebox/backend/internal/web/mid"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
"github.com/hay-kot/safeserve/server"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/rs/zerolog/pkgerrors"
|
||||
|
||||
_ "github.com/hay-kot/homebox/backend/pkgs/cgofreesqlite"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -27,9 +35,9 @@ var (
|
||||
buildTime = "now"
|
||||
)
|
||||
|
||||
// @title Go API Templates
|
||||
// @title Homebox API
|
||||
// @version 1.0
|
||||
// @description This is a simple Rest API Server Template that implements some basic User and Authentication patterns to help you get started and bootstrap your next project!.
|
||||
// @description Track, Manage, and Organize your Things.
|
||||
// @contact.name Don't
|
||||
// @license.name MIT
|
||||
// @BasePath /api
|
||||
@@ -38,6 +46,8 @@ var (
|
||||
// @name Authorization
|
||||
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
|
||||
func main() {
|
||||
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
|
||||
|
||||
cfg, err := config.New()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -57,7 +67,7 @@ func run(cfg *config.Config) error {
|
||||
// =========================================================================
|
||||
// Initialize Database & Repos
|
||||
|
||||
err := os.MkdirAll(cfg.Storage.Data, 0755)
|
||||
err := os.MkdirAll(cfg.Storage.Data, 0o755)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("failed to create data directory")
|
||||
}
|
||||
@@ -112,29 +122,33 @@ func run(cfg *config.Config) error {
|
||||
|
||||
app.db = c
|
||||
app.repos = repo.New(c, cfg.Storage.Data)
|
||||
app.services = services.New(app.repos)
|
||||
app.services = services.New(
|
||||
app.repos,
|
||||
services.WithAutoIncrementAssetID(cfg.Options.AutoIncrementAssetID),
|
||||
)
|
||||
|
||||
// =========================================================================
|
||||
// Start Server\
|
||||
// Start Server
|
||||
|
||||
logger := log.With().Caller().Logger()
|
||||
|
||||
mwLogger := mid.Logger(logger)
|
||||
if app.conf.Mode == config.ModeDevelopment {
|
||||
mwLogger = mid.SugarLogger(logger)
|
||||
}
|
||||
router := chi.NewMux()
|
||||
router.Use(
|
||||
middleware.RequestID,
|
||||
middleware.RealIP,
|
||||
mid.Logger(logger),
|
||||
middleware.Recoverer,
|
||||
middleware.StripSlashes,
|
||||
)
|
||||
|
||||
chain := errchain.New(mid.Errors(app.server, logger))
|
||||
|
||||
app.mountRoutes(router, chain, app.repos)
|
||||
|
||||
app.server = server.NewServer(
|
||||
server.WithHost(app.conf.Web.Host),
|
||||
server.WithPort(app.conf.Web.Port),
|
||||
server.WithMiddleware(
|
||||
mwLogger,
|
||||
mid.Errors(logger),
|
||||
mid.Panic(app.conf.Mode == config.ModeDevelopment),
|
||||
),
|
||||
)
|
||||
|
||||
app.mountRoutes(app.repos)
|
||||
|
||||
log.Info().Msgf("Starting HTTP Server on %s:%s", app.server.Host, app.server.Port)
|
||||
|
||||
// =========================================================================
|
||||
@@ -156,6 +170,19 @@ func run(cfg *config.Config) error {
|
||||
Msg("failed to purge expired invitations")
|
||||
}
|
||||
})
|
||||
go app.startBgTask(time.Duration(1)*time.Hour, func() {
|
||||
now := time.Now()
|
||||
|
||||
if now.Hour() == 8 {
|
||||
fmt.Println("run notifiers")
|
||||
err := app.services.BackgroundService.SendNotifiersToday(context.Background())
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Err(err).
|
||||
Msg("failed to send notifiers")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// TODO: Remove through external API that does setup
|
||||
if cfg.Demo {
|
||||
@@ -172,5 +199,5 @@ func run(cfg *config.Config) error {
|
||||
}()
|
||||
}
|
||||
|
||||
return app.server.Start()
|
||||
return app.server.Start(router)
|
||||
}
|
||||
|
||||
@@ -1,31 +1,150 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
)
|
||||
|
||||
type tokenHasKey struct {
|
||||
key string
|
||||
}
|
||||
|
||||
var hashedToken = tokenHasKey{key: "hashedToken"}
|
||||
|
||||
type RoleMode int
|
||||
|
||||
const (
|
||||
RoleModeOr RoleMode = 0
|
||||
RoleModeAnd RoleMode = 1
|
||||
)
|
||||
|
||||
// mwRoles is a middleware that will validate the required roles are met. All roles
|
||||
// are required to be met for the request to be allowed. If the user does not have
|
||||
// the required roles, a 403 Forbidden will be returned.
|
||||
//
|
||||
// WARNING: This middleware _MUST_ be called after mwAuthToken or else it will panic
|
||||
func (a *app) mwRoles(rm RoleMode, required ...string) errchain.Middleware {
|
||||
return func(next errchain.Handler) errchain.Handler {
|
||||
return errchain.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := r.Context()
|
||||
|
||||
maybeToken := ctx.Value(hashedToken)
|
||||
if maybeToken == nil {
|
||||
panic("mwRoles: token not found in context, you must call mwAuthToken before mwRoles")
|
||||
}
|
||||
|
||||
token := maybeToken.(string)
|
||||
|
||||
roles, err := a.repos.AuthTokens.GetRoles(r.Context(), token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outer:
|
||||
switch rm {
|
||||
case RoleModeOr:
|
||||
for _, role := range required {
|
||||
if roles.Contains(role) {
|
||||
break outer
|
||||
}
|
||||
}
|
||||
return validate.NewRequestError(errors.New("Forbidden"), http.StatusForbidden)
|
||||
case RoleModeAnd:
|
||||
for _, req := range required {
|
||||
if !roles.Contains(req) {
|
||||
return validate.NewRequestError(errors.New("Unauthorized"), http.StatusForbidden)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type KeyFunc func(r *http.Request) (string, error)
|
||||
|
||||
func getBearer(r *http.Request) (string, error) {
|
||||
auth := r.Header.Get("Authorization")
|
||||
if auth == "" {
|
||||
return "", errors.New("authorization header is required")
|
||||
}
|
||||
|
||||
return auth, nil
|
||||
}
|
||||
|
||||
func getQuery(r *http.Request) (string, error) {
|
||||
token := r.URL.Query().Get("access_token")
|
||||
if token == "" {
|
||||
return "", errors.New("access_token query is required")
|
||||
}
|
||||
|
||||
token, err := url.QueryUnescape(token)
|
||||
if err != nil {
|
||||
return "", errors.New("access_token query is required")
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func getCookie(r *http.Request) (string, error) {
|
||||
cookie, err := r.Cookie("hb.auth.token")
|
||||
if err != nil {
|
||||
return "", errors.New("access_token cookie is required")
|
||||
}
|
||||
|
||||
token, err := url.QueryUnescape(cookie.Value)
|
||||
if err != nil {
|
||||
return "", errors.New("access_token cookie is required")
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// mwAuthToken is a middleware that will check the database for a stateful token
|
||||
// and attach it to the request context with the user, or return a 401 if it doesn't exist.
|
||||
func (a *app) mwAuthToken(next server.Handler) server.Handler {
|
||||
return server.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||
requestToken := r.Header.Get("Authorization")
|
||||
// and attach it's user to the request context, or return an appropriate error.
|
||||
// Authorization support is by token via Headers or Query Parameter
|
||||
//
|
||||
// Example:
|
||||
// - header = "Bearer 1234567890"
|
||||
// - query = "?access_token=1234567890"
|
||||
// - cookie = hb.auth.token = 1234567890
|
||||
func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler {
|
||||
return errchain.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||
keyFuncs := [...]KeyFunc{
|
||||
getBearer,
|
||||
getCookie,
|
||||
getQuery,
|
||||
}
|
||||
|
||||
var requestToken string
|
||||
for _, keyFunc := range keyFuncs {
|
||||
token, err := keyFunc(r)
|
||||
if err == nil {
|
||||
requestToken = token
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if requestToken == "" {
|
||||
return validate.NewRequestError(errors.New("Authorization header is required"), http.StatusUnauthorized)
|
||||
return validate.NewRequestError(errors.New("Authorization header or query is required"), http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
requestToken = strings.TrimPrefix(requestToken, "Bearer ")
|
||||
usr, err := a.services.User.GetSelf(r.Context(), requestToken)
|
||||
|
||||
r = r.WithContext(context.WithValue(r.Context(), hashedToken, requestToken))
|
||||
|
||||
usr, err := a.services.User.GetSelf(r.Context(), requestToken)
|
||||
// Check the database for the token
|
||||
if err != nil {
|
||||
return validate.NewRequestError(errors.New("Authorization header is required"), http.StatusUnauthorized)
|
||||
return validate.NewRequestError(errors.New("valid authorization header is required"), http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken))
|
||||
|
||||
@@ -10,11 +10,13 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/hay-kot/homebox/backend/app/api/handlers/debughandlers"
|
||||
v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1"
|
||||
_ "github.com/hay-kot/homebox/backend/app/api/static/docs"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
||||
"github.com/hay-kot/safeserve/errchain"
|
||||
httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware
|
||||
)
|
||||
|
||||
@@ -35,12 +37,12 @@ func (a *app) debugRouter() *http.ServeMux {
|
||||
}
|
||||
|
||||
// registerRoutes registers all the routes for the API
|
||||
func (a *app) mountRoutes(repos *repo.AllRepos) {
|
||||
func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllRepos) {
|
||||
registerMimes()
|
||||
|
||||
a.server.Get("/swagger/*", server.ToHandler(httpSwagger.Handler(
|
||||
r.Get("/swagger/*", httpSwagger.Handler(
|
||||
httpSwagger.URL(fmt.Sprintf("%s://%s/swagger/doc.json", a.conf.Swagger.Scheme, a.conf.Swagger.Host)),
|
||||
)))
|
||||
))
|
||||
|
||||
// =========================================================================
|
||||
// API Version 1
|
||||
@@ -51,62 +53,107 @@ func (a *app) mountRoutes(repos *repo.AllRepos) {
|
||||
a.services,
|
||||
a.repos,
|
||||
v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize),
|
||||
v1.WithRegistration(a.conf.AllowRegistration),
|
||||
v1.WithRegistration(a.conf.Options.AllowRegistration),
|
||||
v1.WithDemoStatus(a.conf.Demo), // Disable Password Change in Demo Mode
|
||||
)
|
||||
|
||||
a.server.Get(v1Base("/status"), v1Ctrl.HandleBase(func() bool { return true }, v1.Build{
|
||||
r.Get(v1Base("/status"), chain.ToHandlerFunc(v1Ctrl.HandleBase(func() bool { return true }, v1.Build{
|
||||
Version: version,
|
||||
Commit: commit,
|
||||
BuildTime: buildTime,
|
||||
}))
|
||||
})))
|
||||
|
||||
a.server.Post(v1Base("/users/register"), v1Ctrl.HandleUserRegistration())
|
||||
a.server.Post(v1Base("/users/login"), v1Ctrl.HandleAuthLogin())
|
||||
r.Post(v1Base("/users/register"), chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration()))
|
||||
r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin()))
|
||||
|
||||
// Attachment download URl needs a `token` query param to be passed in the request.
|
||||
// and also needs to be outside of the `auth` middleware.
|
||||
a.server.Get(v1Base("/items/{id}/attachments/download"), v1Ctrl.HandleItemAttachmentDownload())
|
||||
userMW := []errchain.Middleware{
|
||||
a.mwAuthToken,
|
||||
a.mwRoles(RoleModeOr, authroles.RoleUser.String()),
|
||||
}
|
||||
|
||||
a.server.Get(v1Base("/users/self"), v1Ctrl.HandleUserSelf(), a.mwAuthToken)
|
||||
a.server.Put(v1Base("/users/self"), v1Ctrl.HandleUserSelfUpdate(), a.mwAuthToken)
|
||||
a.server.Delete(v1Base("/users/self"), v1Ctrl.HandleUserSelfDelete(), a.mwAuthToken)
|
||||
a.server.Post(v1Base("/users/logout"), v1Ctrl.HandleAuthLogout(), a.mwAuthToken)
|
||||
a.server.Get(v1Base("/users/refresh"), v1Ctrl.HandleAuthRefresh(), a.mwAuthToken)
|
||||
a.server.Put(v1Base("/users/self/change-password"), v1Ctrl.HandleUserSelfChangePassword(), a.mwAuthToken)
|
||||
r.Get(v1Base("/users/self"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelf(), userMW...))
|
||||
r.Put(v1Base("/users/self"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelfUpdate(), userMW...))
|
||||
r.Delete(v1Base("/users/self"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelfDelete(), userMW...))
|
||||
r.Post(v1Base("/users/logout"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogout(), userMW...))
|
||||
r.Get(v1Base("/users/refresh"), chain.ToHandlerFunc(v1Ctrl.HandleAuthRefresh(), userMW...))
|
||||
r.Put(v1Base("/users/self/change-password"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelfChangePassword(), userMW...))
|
||||
|
||||
a.server.Post(v1Base("/groups/invitations"), v1Ctrl.HandleGroupInvitationsCreate(), a.mwAuthToken)
|
||||
a.server.Get(v1Base("/groups/statistics"), v1Ctrl.HandleGroupStatistics(), a.mwAuthToken)
|
||||
r.Post(v1Base("/groups/invitations"), chain.ToHandlerFunc(v1Ctrl.HandleGroupInvitationsCreate(), userMW...))
|
||||
r.Get(v1Base("/groups/statistics"), chain.ToHandlerFunc(v1Ctrl.HandleGroupStatistics(), userMW...))
|
||||
r.Get(v1Base("/groups/statistics/purchase-price"), chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsPriceOverTime(), userMW...))
|
||||
r.Get(v1Base("/groups/statistics/locations"), chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsLocations(), userMW...))
|
||||
r.Get(v1Base("/groups/statistics/labels"), chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsLabels(), userMW...))
|
||||
|
||||
// TODO: I don't like /groups being the URL for users
|
||||
a.server.Get(v1Base("/groups"), v1Ctrl.HandleGroupGet(), a.mwAuthToken)
|
||||
a.server.Put(v1Base("/groups"), v1Ctrl.HandleGroupUpdate(), a.mwAuthToken)
|
||||
r.Get(v1Base("/groups"), chain.ToHandlerFunc(v1Ctrl.HandleGroupGet(), userMW...))
|
||||
r.Put(v1Base("/groups"), chain.ToHandlerFunc(v1Ctrl.HandleGroupUpdate(), userMW...))
|
||||
|
||||
a.server.Get(v1Base("/locations"), v1Ctrl.HandleLocationGetAll(), a.mwAuthToken)
|
||||
a.server.Post(v1Base("/locations"), v1Ctrl.HandleLocationCreate(), a.mwAuthToken)
|
||||
a.server.Get(v1Base("/locations/{id}"), v1Ctrl.HandleLocationGet(), a.mwAuthToken)
|
||||
a.server.Put(v1Base("/locations/{id}"), v1Ctrl.HandleLocationUpdate(), a.mwAuthToken)
|
||||
a.server.Delete(v1Base("/locations/{id}"), v1Ctrl.HandleLocationDelete(), a.mwAuthToken)
|
||||
r.Post(v1Base("/actions/ensure-asset-ids"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureAssetID(), userMW...))
|
||||
r.Post(v1Base("/actions/zero-item-time-fields"), chain.ToHandlerFunc(v1Ctrl.HandleItemDateZeroOut(), userMW...))
|
||||
r.Post(v1Base("/actions/ensure-import-refs"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureImportRefs(), userMW...))
|
||||
|
||||
a.server.Get(v1Base("/labels"), v1Ctrl.HandleLabelsGetAll(), a.mwAuthToken)
|
||||
a.server.Post(v1Base("/labels"), v1Ctrl.HandleLabelsCreate(), a.mwAuthToken)
|
||||
a.server.Get(v1Base("/labels/{id}"), v1Ctrl.HandleLabelGet(), a.mwAuthToken)
|
||||
a.server.Put(v1Base("/labels/{id}"), v1Ctrl.HandleLabelUpdate(), a.mwAuthToken)
|
||||
a.server.Delete(v1Base("/labels/{id}"), v1Ctrl.HandleLabelDelete(), a.mwAuthToken)
|
||||
r.Get(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationGetAll(), userMW...))
|
||||
r.Post(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationCreate(), userMW...))
|
||||
r.Get(v1Base("/locations/tree"), chain.ToHandlerFunc(v1Ctrl.HandleLocationTreeQuery(), userMW...))
|
||||
r.Get(v1Base("/locations/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLocationGet(), userMW...))
|
||||
r.Put(v1Base("/locations/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLocationUpdate(), userMW...))
|
||||
r.Delete(v1Base("/locations/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLocationDelete(), userMW...))
|
||||
|
||||
a.server.Get(v1Base("/items"), v1Ctrl.HandleItemsGetAll(), a.mwAuthToken)
|
||||
a.server.Post(v1Base("/items/import"), v1Ctrl.HandleItemsImport(), a.mwAuthToken)
|
||||
a.server.Post(v1Base("/items"), v1Ctrl.HandleItemsCreate(), a.mwAuthToken)
|
||||
a.server.Get(v1Base("/items/{id}"), v1Ctrl.HandleItemGet(), a.mwAuthToken)
|
||||
a.server.Put(v1Base("/items/{id}"), v1Ctrl.HandleItemUpdate(), a.mwAuthToken)
|
||||
a.server.Delete(v1Base("/items/{id}"), v1Ctrl.HandleItemDelete(), a.mwAuthToken)
|
||||
r.Get(v1Base("/labels"), chain.ToHandlerFunc(v1Ctrl.HandleLabelsGetAll(), userMW...))
|
||||
r.Post(v1Base("/labels"), chain.ToHandlerFunc(v1Ctrl.HandleLabelsCreate(), userMW...))
|
||||
r.Get(v1Base("/labels/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLabelGet(), userMW...))
|
||||
r.Put(v1Base("/labels/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLabelUpdate(), userMW...))
|
||||
r.Delete(v1Base("/labels/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLabelDelete(), userMW...))
|
||||
|
||||
a.server.Post(v1Base("/items/{id}/attachments"), v1Ctrl.HandleItemAttachmentCreate(), a.mwAuthToken)
|
||||
a.server.Get(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentToken(), a.mwAuthToken)
|
||||
a.server.Put(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentUpdate(), a.mwAuthToken)
|
||||
a.server.Delete(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentDelete(), a.mwAuthToken)
|
||||
r.Get(v1Base("/items"), chain.ToHandlerFunc(v1Ctrl.HandleItemsGetAll(), userMW...))
|
||||
r.Post(v1Base("/items"), chain.ToHandlerFunc(v1Ctrl.HandleItemsCreate(), userMW...))
|
||||
r.Post(v1Base("/items/import"), chain.ToHandlerFunc(v1Ctrl.HandleItemsImport(), userMW...))
|
||||
r.Get(v1Base("/items/export"), chain.ToHandlerFunc(v1Ctrl.HandleItemsExport(), userMW...))
|
||||
r.Get(v1Base("/items/fields"), chain.ToHandlerFunc(v1Ctrl.HandleGetAllCustomFieldNames(), userMW...))
|
||||
r.Get(v1Base("/items/fields/values"), chain.ToHandlerFunc(v1Ctrl.HandleGetAllCustomFieldValues(), userMW...))
|
||||
|
||||
r.Get(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemGet(), userMW...))
|
||||
r.Put(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemUpdate(), userMW...))
|
||||
r.Delete(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemDelete(), userMW...))
|
||||
|
||||
r.Post(v1Base("/items/{id}/attachments"), chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentCreate(), userMW...))
|
||||
r.Put(v1Base("/items/{id}/attachments/{attachment_id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentUpdate(), userMW...))
|
||||
r.Delete(v1Base("/items/{id}/attachments/{attachment_id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentDelete(), userMW...))
|
||||
|
||||
r.Get(v1Base("/items/{id}/maintenance"), chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceLogGet(), userMW...))
|
||||
r.Post(v1Base("/items/{id}/maintenance"), chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryCreate(), userMW...))
|
||||
r.Put(v1Base("/items/{id}/maintenance/{entry_id}"), chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryUpdate(), userMW...))
|
||||
r.Delete(v1Base("/items/{id}/maintenance/{entry_id}"), chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryDelete(), userMW...))
|
||||
|
||||
r.Get(v1Base("/asset/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleAssetGet(), userMW...))
|
||||
|
||||
// Notifiers
|
||||
r.Get(v1Base("/notifiers"), chain.ToHandlerFunc(v1Ctrl.HandleGetUserNotifiers(), userMW...))
|
||||
r.Post(v1Base("/notifiers"), chain.ToHandlerFunc(v1Ctrl.HandleCreateNotifier(), userMW...))
|
||||
r.Put(v1Base("/notifiers/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleUpdateNotifier(), userMW...))
|
||||
r.Delete(v1Base("/notifiers/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleDeleteNotifier(), userMW...))
|
||||
r.Post(v1Base("/notifiers/test"), chain.ToHandlerFunc(v1Ctrl.HandlerNotifierTest(), userMW...))
|
||||
|
||||
// Asset-Like endpoints
|
||||
assetMW := []errchain.Middleware{
|
||||
a.mwAuthToken,
|
||||
a.mwRoles(RoleModeOr, authroles.RoleUser.String(), authroles.RoleAttachments.String()),
|
||||
}
|
||||
|
||||
r.Get(
|
||||
v1Base("/qrcode"),
|
||||
chain.ToHandlerFunc(v1Ctrl.HandleGenerateQRCode(), assetMW...),
|
||||
)
|
||||
r.Get(
|
||||
v1Base("/items/{id}/attachments/{attachment_id}"),
|
||||
chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentGet(), assetMW...),
|
||||
)
|
||||
|
||||
// Reporting Services
|
||||
r.Get(v1Base("/reporting/bill-of-materials"), chain.ToHandlerFunc(v1Ctrl.HandleBillOfMaterialsExport(), userMW...))
|
||||
|
||||
r.NotFound(chain.ToHandlerFunc(notFoundHandler()))
|
||||
|
||||
a.server.NotFound(notFoundHandler())
|
||||
}
|
||||
|
||||
func registerMimes() {
|
||||
@@ -123,7 +170,7 @@ func registerMimes() {
|
||||
|
||||
// notFoundHandler perform the main logic around handling the internal SPA embed and ensuring that
|
||||
// the client side routing is handled correctly.
|
||||
func notFoundHandler() server.HandlerFunc {
|
||||
func notFoundHandler() errchain.HandlerFunc {
|
||||
tryRead := func(fs embed.FS, prefix, requestedPath string, w http.ResponseWriter) error {
|
||||
f, err := fs.Open(path.Join(prefix, requestedPath))
|
||||
if err != nil {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
@@ -39,4 +40,6 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatalf("failed generating migration file: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("Migration file generated successfully.")
|
||||
}
|
||||
|
||||
80
backend/app/tools/typegen/main.go
Normal file
80
backend/app/tools/typegen/main.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type ReReplace struct {
|
||||
Regex *regexp.Regexp
|
||||
Text string
|
||||
}
|
||||
|
||||
func NewReReplace(regex string, replace string) ReReplace {
|
||||
return ReReplace{
|
||||
Regex: regexp.MustCompile(regex),
|
||||
Text: replace,
|
||||
}
|
||||
}
|
||||
|
||||
func NewReDate(dateStr string) ReReplace {
|
||||
return ReReplace{
|
||||
Regex: regexp.MustCompile(fmt.Sprintf(`%s: string`, dateStr)),
|
||||
Text: fmt.Sprintf(`%s: Date | string`, dateStr),
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Println("Please provide a file path as an argument")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
path := os.Args[1]
|
||||
|
||||
fmt.Printf("Processing %s\n", path)
|
||||
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
fmt.Printf("File %s does not exist\n", path)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
text := "/* post-processed by ./scripts/process-types.go */\n"
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
text += string(data)
|
||||
|
||||
replaces := [...]ReReplace{
|
||||
NewReReplace(` Repo`, " "),
|
||||
NewReReplace(` PaginationResultRepo`, " PaginationResult"),
|
||||
NewReReplace(` Services`, " "),
|
||||
NewReReplace(` V1`, " "),
|
||||
NewReReplace(`\?:`, ":"),
|
||||
NewReDate("createdAt"),
|
||||
NewReDate("updatedAt"),
|
||||
NewReDate("soldTime"),
|
||||
NewReDate("purchaseTime"),
|
||||
NewReDate("warrantyExpires"),
|
||||
NewReDate("expiresAt"),
|
||||
NewReDate("date"),
|
||||
NewReDate("completedDate"),
|
||||
NewReDate("scheduledDate"),
|
||||
}
|
||||
|
||||
for _, replace := range replaces {
|
||||
fmt.Printf("Replacing '%v' -> '%s'\n", replace.Regex, replace.Text)
|
||||
text = replace.Regex.ReplaceAllString(text, replace.Text)
|
||||
}
|
||||
|
||||
err = os.WriteFile(path, []byte(text), 0644)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
@@ -1,20 +1,28 @@
|
||||
module github.com/hay-kot/homebox/backend
|
||||
|
||||
go 1.19
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
ariga.io/atlas v0.7.2-0.20220927111110-867ee0cca56a
|
||||
entgo.io/ent v0.11.3
|
||||
github.com/ardanlabs/conf/v2 v2.2.0
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
github.com/go-playground/validator/v10 v10.11.1
|
||||
ariga.io/atlas v0.10.0
|
||||
entgo.io/ent v0.11.10
|
||||
github.com/ardanlabs/conf/v3 v3.1.5
|
||||
github.com/containrrr/shoutrrr v0.7.1
|
||||
github.com/go-chi/chi/v5 v5.0.8
|
||||
github.com/go-playground/validator/v10 v10.12.0
|
||||
github.com/gocarina/gocsv v0.0.0-20230226133904-70c27cb2918a
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/schema v1.2.0
|
||||
github.com/hay-kot/safeserve v0.0.1
|
||||
github.com/mattn/go-sqlite3 v1.14.16
|
||||
github.com/rs/zerolog v1.28.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/swaggo/http-swagger v1.3.3
|
||||
github.com/swaggo/swag v1.8.7
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rs/zerolog v1.29.0
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/swaggo/http-swagger v1.3.4
|
||||
github.com/swaggo/swag v1.8.11
|
||||
github.com/yeqown/go-qrcode/v2 v2.2.1
|
||||
github.com/yeqown/go-qrcode/writer/standard v1.2.1
|
||||
golang.org/x/crypto v0.7.0
|
||||
modernc.org/sqlite v1.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -22,28 +30,45 @@ require (
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/fogleman/gg v1.3.0 // indirect
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
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.14.1 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.15.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/leodido/go-urn v1.2.2 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a // indirect
|
||||
github.com/zclconf/go-cty v1.11.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.0.0-20220923203811-8be639271d50 // indirect
|
||||
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.13-0.20220804200503-81c7dc4e4efa // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/swaggo/files v1.0.0 // indirect
|
||||
github.com/yeqown/reedsolomon v1.0.0 // indirect
|
||||
github.com/zclconf/go-cty v1.12.1 // indirect
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/tools v0.6.1-0.20230222164832-25d2519c8696 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/uint128 v1.2.0 // indirect
|
||||
modernc.org/cc/v3 v3.40.0 // indirect
|
||||
modernc.org/ccgo/v3 v3.16.13 // indirect
|
||||
modernc.org/libc v1.22.3 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/opt v0.1.3 // indirect
|
||||
modernc.org/strutil v1.1.3 // indirect
|
||||
modernc.org/token v1.0.1 // indirect
|
||||
)
|
||||
|
||||
1228
backend/go.sum
1228
backend/go.sum
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,48 @@
|
||||
package services
|
||||
|
||||
import "github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
import (
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
)
|
||||
|
||||
type AllServices struct {
|
||||
User *UserService
|
||||
Group *GroupService
|
||||
Items *ItemService
|
||||
User *UserService
|
||||
Group *GroupService
|
||||
Items *ItemService
|
||||
BackgroundService *BackgroundService
|
||||
}
|
||||
|
||||
func New(repos *repo.AllRepos) *AllServices {
|
||||
type OptionsFunc func(*options)
|
||||
|
||||
type options struct {
|
||||
autoIncrementAssetID bool
|
||||
}
|
||||
|
||||
func WithAutoIncrementAssetID(v bool) func(*options) {
|
||||
return func(o *options) {
|
||||
o.autoIncrementAssetID = v
|
||||
}
|
||||
}
|
||||
|
||||
func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices {
|
||||
if repos == nil {
|
||||
panic("repos cannot be nil")
|
||||
}
|
||||
|
||||
options := &options{
|
||||
autoIncrementAssetID: true,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(options)
|
||||
}
|
||||
|
||||
return &AllServices{
|
||||
User: &UserService{repos},
|
||||
Group: &GroupService{repos},
|
||||
Items: &ItemService{
|
||||
repo: repos,
|
||||
at: attachmentTokens{},
|
||||
repo: repos,
|
||||
autoIncrementAssetID: options.autoIncrementAssetID,
|
||||
},
|
||||
BackgroundService: &BackgroundService{repos},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,8 @@ package services
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
@@ -49,8 +47,6 @@ func bootstrap() {
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
rand.Seed(int64(time.Now().Unix()))
|
||||
|
||||
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
|
||||
if err != nil {
|
||||
log.Fatalf("failed opening connection to sqlite: %v", err)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
Import Ref,Location,Labels,Quantity,Name,Description,Insured,Serial Number,Mode Number,Manufacturer,Notes,Purchase From,Purchased Price,Purchased Time,Lifetime Warranty,Warranty Expires,Warranty Details,Sold To,Sold Price,Sold Time,Sold Notes
|
||||
A,Garage,IOT;Home Assistant; Z-Wave,1,Zooz Universal Relay ZEN17,Description 1,TRUE,,ZEN17,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021,
|
||||
B,Living Room,IOT;Home Assistant; Z-Wave,1,Zooz Motion Sensor,Description 2,FALSE,,ZSE18,Zooz,,Amazon,29.95,10/15/2021,,10/15/2021,,,,10/15/2021,
|
||||
C,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,Description 3,TRUE,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021,
|
||||
D,Downstairs,IOT;Home Assistant; Z-Wave,1,Ecolink Z-Wave PIR Motion Sensor,Description 4,FALSE,,PIRZWAVE2.5-ECO,Ecolink,,Amazon,35.58,10/21/2020,,10/21/2020,,,,10/21/2020,
|
||||
E,Entry,IOT;Home Assistant; Z-Wave,1,Yale Security Touchscreen Deadbolt,Description 5,TRUE,,YRD226ZW2619,Yale,,Amazon,120.39,10/14/2020,,10/14/2020,,,,10/14/2020,
|
||||
F,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,Description 6,FALSE,,39351,Honeywell,,Amazon,65.98,09/30/2020,,09/30/2020,,,,09/30/2020,
|
||||
|
@@ -0,0 +1,7 @@
|
||||
Import Ref Location Labels Quantity Name Description Insured Serial Number Mode Number Manufacturer Notes Purchase From Purchased Price Purchased Time Lifetime Warranty Warranty Expires Warranty Details Sold To Sold Price Sold Time Sold Notes
|
||||
A Garage IOT;Home Assistant; Z-Wave 1 Zooz Universal Relay ZEN17 Description 1 TRUE ZEN17 Zooz Amazon 39.95 10/13/2021 10/13/2021 10/13/2021
|
||||
B Living Room IOT;Home Assistant; Z-Wave 1 Zooz Motion Sensor Description 2 FALSE ZSE18 Zooz Amazon 29.95 10/15/2021 10/15/2021 10/15/2021
|
||||
C Office IOT;Home Assistant; Z-Wave 1 Zooz 110v Power Switch Description 3 TRUE ZEN15 Zooz Amazon 39.95 10/13/2021 10/13/2021 10/13/2021
|
||||
D Downstairs IOT;Home Assistant; Z-Wave 1 Ecolink Z-Wave PIR Motion Sensor Description 4 FALSE PIRZWAVE2.5-ECO Ecolink Amazon 35.58 10/21/2020 10/21/2020 10/21/2020
|
||||
E Entry IOT;Home Assistant; Z-Wave 1 Yale Security Touchscreen Deadbolt Description 5 TRUE YRD226ZW2619 Yale Amazon 120.39 10/14/2020 10/14/2020 10/14/2020
|
||||
F Kitchen IOT;Home Assistant; Z-Wave 1 Smart Rocker Light Dimmer Description 6 FALSE 39351 Honeywell Amazon 65.98 09/30/2020 09/30/2020 09/30/2020
|
||||
|
@@ -0,0 +1,5 @@
|
||||
HB.location,HB.name,HB.quantity,HB.description,HB.field.Custom Field 1,HB.field.Custom Field 2,HB.field.Custom Field 3
|
||||
loc,Item 1,1,Description 1,Value 1[1],Value 1[2],Value 1[3]
|
||||
loc,Item 2,2,Description 2,Value 2[1],Value 2[2],Value 2[3]
|
||||
loc,Item 3,3,Description 3,Value 3[1],Value 3[2],Value 3[3]
|
||||
|
||||
|
@@ -0,0 +1,4 @@
|
||||
HB.location,HB.name,HB.quantity,HB.description
|
||||
loc,Item 1,1,Description 1
|
||||
loc,Item 2,2,Description 2
|
||||
loc,Item 3,3,Description 3
|
||||
|
@@ -0,0 +1,4 @@
|
||||
HB.name,HB.asset_id,HB.location,HB.labels
|
||||
Item 1,1,Path / To / Location 1,L1 ; L2 ; L3
|
||||
Item 2,000-002,Path /To/ Location 2,L1;L2;L3
|
||||
Item 3,1000-003,Path / To /Location 3 , L1;L2; L3
|
||||
|
@@ -0,0 +1,42 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"github.com/gocarina/gocsv"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||
)
|
||||
|
||||
// =================================================================================================
|
||||
|
||||
type BillOfMaterialsEntry struct {
|
||||
PurchaseDate types.Date `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 BillOfMaterialsTSV(entities []repo.ItemOut) ([]byte, error) {
|
||||
bomEntries := make([]BillOfMaterialsEntry, len(entities))
|
||||
for i, entity := range entities {
|
||||
bomEntries[i] = BillOfMaterialsEntry{
|
||||
PurchaseDate: 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)
|
||||
}
|
||||
93
backend/internal/core/services/reporting/import.go
Normal file
93
backend/internal/core/services/reporting/import.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoHomeboxHeaders = errors.New("no headers found")
|
||||
ErrMissingRequiredHeaders = errors.New("missing required headers `HB.location` or `HB.name`")
|
||||
)
|
||||
|
||||
// determineSeparator determines the separator used in the CSV file
|
||||
// It returns the separator as a rune and an error if it could not be determined
|
||||
//
|
||||
// It is assumed that the first row is the header row and that the separator is the same
|
||||
// for all rows.
|
||||
//
|
||||
// Supported separators are `,` and `\t`
|
||||
func determineSeparator(data []byte) (rune, error) {
|
||||
// First row
|
||||
firstRow := bytes.Split(data, []byte("\n"))[0]
|
||||
|
||||
// find first comma or /t
|
||||
comma := bytes.IndexByte(firstRow, ',')
|
||||
tab := bytes.IndexByte(firstRow, '\t')
|
||||
|
||||
switch {
|
||||
case comma == -1 && tab == -1:
|
||||
return 0, errors.New("could not determine separator")
|
||||
case tab > comma:
|
||||
return '\t', nil
|
||||
default:
|
||||
return ',', nil
|
||||
}
|
||||
}
|
||||
|
||||
// readRawCsv reads a CSV file and returns the raw data as a 2D string array
|
||||
// It determines the separator used in the CSV file and returns an error if
|
||||
// it could not be determined
|
||||
func readRawCsv(r io.Reader) ([][]string, error) {
|
||||
data, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader := csv.NewReader(bytes.NewReader(data))
|
||||
|
||||
// Determine separator
|
||||
sep, err := determineSeparator(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader.Comma = sep
|
||||
|
||||
return reader.ReadAll()
|
||||
}
|
||||
|
||||
// parseHeaders parses the homebox headers from the CSV file and returns a map of the headers
|
||||
// and their column index as well as a list of the field headers (HB.field.*) in the order
|
||||
// they appear in the CSV file
|
||||
//
|
||||
// It returns an error if no homebox headers are found
|
||||
func parseHeaders(headers []string) (hbHeaders map[string]int, fieldHeaders []string, err error) {
|
||||
hbHeaders = map[string]int{} // initialize map
|
||||
|
||||
for col, h := range headers {
|
||||
if strings.HasPrefix(h, "HB.field.") {
|
||||
fieldHeaders = append(fieldHeaders, h)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(h, "HB.") {
|
||||
hbHeaders[h] = col
|
||||
}
|
||||
}
|
||||
|
||||
required := []string{"HB.location", "HB.name"}
|
||||
for _, h := range required {
|
||||
if _, ok := hbHeaders[h]; !ok {
|
||||
return nil, nil, ErrMissingRequiredHeaders
|
||||
}
|
||||
}
|
||||
|
||||
if len(hbHeaders) == 0 {
|
||||
return nil, nil, ErrNoHomeboxHeaders
|
||||
}
|
||||
|
||||
return hbHeaders, fieldHeaders, nil
|
||||
}
|
||||
85
backend/internal/core/services/reporting/io_row.go
Normal file
85
backend/internal/core/services/reporting/io_row.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||
)
|
||||
|
||||
type ExportItemFields struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
type ExportTSVRow struct {
|
||||
ImportRef string `csv:"HB.import_ref"`
|
||||
Location LocationString `csv:"HB.location"`
|
||||
LabelStr LabelString `csv:"HB.labels"`
|
||||
AssetID repo.AssetID `csv:"HB.asset_id"`
|
||||
Archived bool `csv:"HB.archived"`
|
||||
|
||||
Name string `csv:"HB.name"`
|
||||
Quantity int `csv:"HB.quantity"`
|
||||
Description string `csv:"HB.description"`
|
||||
Insured bool `csv:"HB.insured"`
|
||||
Notes string `csv:"HB.notes"`
|
||||
|
||||
PurchasePrice float64 `csv:"HB.purchase_price"`
|
||||
PurchaseFrom string `csv:"HB.purchase_from"`
|
||||
PurchaseTime types.Date `csv:"HB.purchase_time"`
|
||||
|
||||
Manufacturer string `csv:"HB.manufacturer"`
|
||||
ModelNumber string `csv:"HB.model_number"`
|
||||
SerialNumber string `csv:"HB.serial_number"`
|
||||
|
||||
LifetimeWarranty bool `csv:"HB.lifetime_warranty"`
|
||||
WarrantyExpires types.Date `csv:"HB.warranty_expires"`
|
||||
WarrantyDetails string `csv:"HB.warranty_details"`
|
||||
|
||||
SoldTo string `csv:"HB.sold_to"`
|
||||
SoldPrice float64 `csv:"HB.sold_price"`
|
||||
SoldTime types.Date `csv:"HB.sold_time"`
|
||||
SoldNotes string `csv:"HB.sold_notes"`
|
||||
|
||||
Fields []ExportItemFields `csv:"-"`
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// LabelString is a string slice that is used to represent a list of labels.
|
||||
//
|
||||
// For example, a list of labels "Important; Work" would be represented as a
|
||||
// LabelString with the following values:
|
||||
//
|
||||
// LabelString{"Important", "Work"}
|
||||
type LabelString []string
|
||||
|
||||
func parseLabelString(s string) LabelString {
|
||||
v, _ := parseSeparatedString(s, ";")
|
||||
return v
|
||||
}
|
||||
|
||||
func (ls LabelString) String() string {
|
||||
return strings.Join(ls, "; ")
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// LocationString is a string slice that is used to represent a location
|
||||
// hierarchy.
|
||||
//
|
||||
// For example, a location hierarchy of "Home / Bedroom / Desk" would be
|
||||
// represented as a LocationString with the following values:
|
||||
//
|
||||
// LocationString{"Home", "Bedroom", "Desk"}
|
||||
type LocationString []string
|
||||
|
||||
func parseLocationString(s string) LocationString {
|
||||
v, _ := parseSeparatedString(s, "/")
|
||||
return v
|
||||
}
|
||||
|
||||
func (csf LocationString) String() string {
|
||||
return strings.Join(csf, " / ")
|
||||
}
|
||||
310
backend/internal/core/services/reporting/io_sheet.go
Normal file
310
backend/internal/core/services/reporting/io_sheet.go
Normal file
@@ -0,0 +1,310 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// IOSheet is the representation of a CSV/TSV sheet that is used for importing/exporting
|
||||
// items from homebox. It is used to read/write the data from/to a CSV/TSV file given
|
||||
// the standard format of the file.
|
||||
//
|
||||
// See ExportTSVRow for the format of the data in the sheet.
|
||||
type IOSheet struct {
|
||||
headers []string
|
||||
custom []int
|
||||
index map[string]int
|
||||
Rows []ExportTSVRow
|
||||
}
|
||||
|
||||
func (s *IOSheet) indexHeaders() {
|
||||
s.index = make(map[string]int)
|
||||
|
||||
for i, h := range s.headers {
|
||||
if strings.HasPrefix(h, "HB.field") {
|
||||
s.custom = append(s.custom, i)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(h, "HB.") {
|
||||
s.index[h] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *IOSheet) GetColumn(str string) (col int, ok bool) {
|
||||
if s.index == nil {
|
||||
s.indexHeaders()
|
||||
}
|
||||
|
||||
col, ok = s.index[str]
|
||||
return
|
||||
}
|
||||
|
||||
// Read reads a CSV/TSV and populates the "Rows" field with the data from the sheet
|
||||
// Custom Fields are supported via the `HB.field.*` headers. The `HB.field.*` the "Name"
|
||||
// of the field is the part after the `HB.field.` prefix. Additionally, Custom Fields with
|
||||
// no value are excluded from the row.Fields slice, this includes empty strings.
|
||||
//
|
||||
// Note That
|
||||
// - the first row is assumed to be the header
|
||||
// - at least 1 row of data is required
|
||||
// - rows and columns must be rectangular (i.e. all rows must have the same number of columns)
|
||||
func (s *IOSheet) Read(data io.Reader) error {
|
||||
sheet, err := readRawCsv(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(sheet) < 2 {
|
||||
return fmt.Errorf("sheet must have at least 1 row of data (header + 1)")
|
||||
}
|
||||
|
||||
s.headers = sheet[0]
|
||||
s.Rows = make([]ExportTSVRow, len(sheet)-1)
|
||||
|
||||
for i, row := range sheet[1:] {
|
||||
if len(row) != len(s.headers) {
|
||||
return fmt.Errorf("row has %d columns, expected %d", len(row), len(s.headers))
|
||||
}
|
||||
|
||||
rowData := ExportTSVRow{}
|
||||
|
||||
st := reflect.TypeOf(ExportTSVRow{})
|
||||
|
||||
for i := 0; i < st.NumField(); i++ {
|
||||
field := st.Field(i)
|
||||
tag := field.Tag.Get("csv")
|
||||
if tag == "" || tag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
col, ok := s.GetColumn(tag)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
val := row[col]
|
||||
|
||||
var v interface{}
|
||||
|
||||
switch field.Type {
|
||||
case reflect.TypeOf(""):
|
||||
v = val
|
||||
case reflect.TypeOf(int(0)):
|
||||
v = parseInt(val)
|
||||
case reflect.TypeOf(bool(false)):
|
||||
v = parseBool(val)
|
||||
case reflect.TypeOf(float64(0)):
|
||||
v = parseFloat(val)
|
||||
|
||||
// Custom Types
|
||||
case reflect.TypeOf(types.Date{}):
|
||||
v = types.DateFromString(val)
|
||||
case reflect.TypeOf(repo.AssetID(0)):
|
||||
v, _ = repo.ParseAssetID(val)
|
||||
case reflect.TypeOf(LocationString{}):
|
||||
v = parseLocationString(val)
|
||||
case reflect.TypeOf(LabelString{}):
|
||||
v = parseLabelString(val)
|
||||
}
|
||||
|
||||
log.Debug().
|
||||
Str("tag", tag).
|
||||
Interface("val", v).
|
||||
Str("type", fmt.Sprintf("%T", v)).
|
||||
Msg("parsed value")
|
||||
|
||||
// Nil values are not allowed at the moment. This may change.
|
||||
if v == nil {
|
||||
return fmt.Errorf("could not convert %q to %s", val, field.Type)
|
||||
}
|
||||
|
||||
ptrField := reflect.ValueOf(&rowData).Elem().Field(i)
|
||||
ptrField.Set(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
for _, col := range s.custom {
|
||||
colName := strings.TrimPrefix(s.headers[col], "HB.field.")
|
||||
customVal := row[col]
|
||||
if customVal == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
rowData.Fields = append(rowData.Fields, ExportItemFields{
|
||||
Name: colName,
|
||||
Value: customVal,
|
||||
})
|
||||
}
|
||||
|
||||
s.Rows[i] = rowData
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write writes the sheet to a writer.
|
||||
func (s *IOSheet) ReadItems(items []repo.ItemOut) {
|
||||
s.Rows = make([]ExportTSVRow, len(items))
|
||||
|
||||
extraHeaders := map[string]struct{}{}
|
||||
|
||||
for i := range items {
|
||||
item := items[i]
|
||||
|
||||
// TODO: Support fetching nested locations
|
||||
locString := LocationString{item.Location.Name}
|
||||
|
||||
labelString := make([]string, len(item.Labels))
|
||||
|
||||
for i, l := range item.Labels {
|
||||
labelString[i] = l.Name
|
||||
}
|
||||
|
||||
customFields := make([]ExportItemFields, len(item.Fields))
|
||||
|
||||
for i, f := range item.Fields {
|
||||
extraHeaders[f.Name] = struct{}{}
|
||||
|
||||
customFields[i] = ExportItemFields{
|
||||
Name: f.Name,
|
||||
Value: f.TextValue,
|
||||
}
|
||||
}
|
||||
|
||||
s.Rows[i] = ExportTSVRow{
|
||||
// fill struct
|
||||
Location: locString,
|
||||
LabelStr: labelString,
|
||||
|
||||
ImportRef: item.ImportRef,
|
||||
AssetID: item.AssetID,
|
||||
Name: item.Name,
|
||||
Quantity: item.Quantity,
|
||||
Description: item.Description,
|
||||
Insured: item.Insured,
|
||||
Archived: item.Archived,
|
||||
|
||||
PurchasePrice: item.PurchasePrice,
|
||||
PurchaseFrom: item.PurchaseFrom,
|
||||
PurchaseTime: item.PurchaseTime,
|
||||
|
||||
Manufacturer: item.Manufacturer,
|
||||
ModelNumber: item.ModelNumber,
|
||||
SerialNumber: item.SerialNumber,
|
||||
|
||||
LifetimeWarranty: item.LifetimeWarranty,
|
||||
WarrantyExpires: item.WarrantyExpires,
|
||||
WarrantyDetails: item.WarrantyDetails,
|
||||
|
||||
SoldTo: item.SoldTo,
|
||||
SoldTime: item.SoldTime,
|
||||
SoldPrice: item.SoldPrice,
|
||||
SoldNotes: item.SoldNotes,
|
||||
|
||||
Fields: customFields,
|
||||
}
|
||||
}
|
||||
|
||||
// Extract and sort additional headers for deterministic output
|
||||
customHeaders := make([]string, 0, len(extraHeaders))
|
||||
|
||||
for k := range extraHeaders {
|
||||
customHeaders = append(customHeaders, k)
|
||||
}
|
||||
|
||||
sort.Strings(customHeaders)
|
||||
|
||||
st := reflect.TypeOf(ExportTSVRow{})
|
||||
|
||||
// Write headers
|
||||
for i := 0; i < st.NumField(); i++ {
|
||||
field := st.Field(i)
|
||||
tag := field.Tag.Get("csv")
|
||||
if tag == "" || tag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
s.headers = append(s.headers, tag)
|
||||
}
|
||||
|
||||
for _, h := range customHeaders {
|
||||
s.headers = append(s.headers, "HB.field."+h)
|
||||
}
|
||||
}
|
||||
|
||||
// Writes the current sheet to a writer in TSV format.
|
||||
func (s *IOSheet) TSV() ([][]string, error) {
|
||||
memcsv := make([][]string, len(s.Rows)+1)
|
||||
|
||||
memcsv[0] = s.headers
|
||||
|
||||
// use struct tags in rows to dertmine column order
|
||||
for i, row := range s.Rows {
|
||||
rowIdx := i + 1
|
||||
|
||||
memcsv[rowIdx] = make([]string, len(s.headers))
|
||||
|
||||
st := reflect.TypeOf(row)
|
||||
|
||||
for i := 0; i < st.NumField(); i++ {
|
||||
field := st.Field(i)
|
||||
tag := field.Tag.Get("csv")
|
||||
if tag == "" || tag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
col, ok := s.GetColumn(tag)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(row).Field(i)
|
||||
|
||||
var v string
|
||||
|
||||
switch field.Type {
|
||||
case reflect.TypeOf(""):
|
||||
v = val.String()
|
||||
case reflect.TypeOf(int(0)):
|
||||
v = strconv.Itoa(int(val.Int()))
|
||||
case reflect.TypeOf(bool(false)):
|
||||
v = strconv.FormatBool(val.Bool())
|
||||
case reflect.TypeOf(float64(0)):
|
||||
v = strconv.FormatFloat(val.Float(), 'f', -1, 64)
|
||||
|
||||
// Custom Types
|
||||
case reflect.TypeOf(types.Date{}):
|
||||
v = val.Interface().(types.Date).String()
|
||||
case reflect.TypeOf(repo.AssetID(0)):
|
||||
v = val.Interface().(repo.AssetID).String()
|
||||
case reflect.TypeOf(LocationString{}):
|
||||
v = val.Interface().(LocationString).String()
|
||||
case reflect.TypeOf(LabelString{}):
|
||||
v = val.Interface().(LabelString).String()
|
||||
default:
|
||||
log.Debug().Str("type", field.Type.String()).Msg("unknown type")
|
||||
}
|
||||
|
||||
memcsv[rowIdx][col] = v
|
||||
}
|
||||
|
||||
for _, f := range row.Fields {
|
||||
col, ok := s.GetColumn("HB.field." + f.Name)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
memcsv[i+1][col] = f.Value
|
||||
}
|
||||
}
|
||||
|
||||
return memcsv, nil
|
||||
}
|
||||
226
backend/internal/core/services/reporting/io_sheet_test.go
Normal file
226
backend/internal/core/services/reporting/io_sheet_test.go
Normal file
@@ -0,0 +1,226 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed .testdata/import/minimal.csv
|
||||
minimalImportCSV []byte
|
||||
|
||||
//go:embed .testdata/import/fields.csv
|
||||
customFieldImportCSV []byte
|
||||
|
||||
//go:embed .testdata/import/types.csv
|
||||
customTypesImportCSV []byte
|
||||
|
||||
//go:embed .testdata/import.csv
|
||||
CSVData_Comma []byte
|
||||
|
||||
//go:embed .testdata/import.tsv
|
||||
CSVData_Tab []byte
|
||||
)
|
||||
|
||||
func TestSheet_Read(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
want []ExportTSVRow
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "minimal import",
|
||||
data: minimalImportCSV,
|
||||
want: []ExportTSVRow{
|
||||
{Location: LocationString{"loc"}, Name: "Item 1", Quantity: 1, Description: "Description 1"},
|
||||
{Location: LocationString{"loc"}, Name: "Item 2", Quantity: 2, Description: "Description 2"},
|
||||
{Location: LocationString{"loc"}, Name: "Item 3", Quantity: 3, Description: "Description 3"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom field import",
|
||||
data: customFieldImportCSV,
|
||||
want: []ExportTSVRow{
|
||||
{
|
||||
Location: LocationString{"loc"}, Name: "Item 1", Quantity: 1, Description: "Description 1",
|
||||
Fields: []ExportItemFields{
|
||||
{Name: "Custom Field 1", Value: "Value 1[1]"},
|
||||
{Name: "Custom Field 2", Value: "Value 1[2]"},
|
||||
{Name: "Custom Field 3", Value: "Value 1[3]"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Location: LocationString{"loc"}, Name: "Item 2", Quantity: 2, Description: "Description 2",
|
||||
Fields: []ExportItemFields{
|
||||
{Name: "Custom Field 1", Value: "Value 2[1]"},
|
||||
{Name: "Custom Field 2", Value: "Value 2[2]"},
|
||||
{Name: "Custom Field 3", Value: "Value 2[3]"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Location: LocationString{"loc"}, Name: "Item 3", Quantity: 3, Description: "Description 3",
|
||||
Fields: []ExportItemFields{
|
||||
{Name: "Custom Field 1", Value: "Value 3[1]"},
|
||||
{Name: "Custom Field 2", Value: "Value 3[2]"},
|
||||
{Name: "Custom Field 3", Value: "Value 3[3]"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom types import",
|
||||
data: customTypesImportCSV,
|
||||
want: []ExportTSVRow{
|
||||
{
|
||||
Name: "Item 1",
|
||||
AssetID: repo.AssetID(1),
|
||||
Location: LocationString{"Path", "To", "Location 1"},
|
||||
LabelStr: LabelString{"L1", "L2", "L3"},
|
||||
},
|
||||
{
|
||||
Name: "Item 2",
|
||||
AssetID: repo.AssetID(2),
|
||||
Location: LocationString{"Path", "To", "Location 2"},
|
||||
LabelStr: LabelString{"L1", "L2", "L3"},
|
||||
},
|
||||
{
|
||||
Name: "Item 3",
|
||||
AssetID: repo.AssetID(1000003),
|
||||
Location: LocationString{"Path", "To", "Location 3"},
|
||||
LabelStr: LabelString{"L1", "L2", "L3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
reader := bytes.NewReader(tt.data)
|
||||
|
||||
sheet := &IOSheet{}
|
||||
err := sheet.Read(reader)
|
||||
|
||||
switch {
|
||||
case tt.wantErr:
|
||||
assert.Error(t, err)
|
||||
default:
|
||||
assert.NoError(t, err)
|
||||
assert.ElementsMatch(t, tt.want, sheet.Rows)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseHeaders(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rawHeaders []string
|
||||
wantHbHeaders map[string]int
|
||||
wantFieldHeaders []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "no hombox headers",
|
||||
rawHeaders: []string{"Header 1", "Header 2", "Header 3"},
|
||||
wantHbHeaders: nil,
|
||||
wantFieldHeaders: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "field headers only",
|
||||
rawHeaders: []string{"HB.location", "HB.name", "HB.field.1", "HB.field.2", "HB.field.3"},
|
||||
wantHbHeaders: map[string]int{
|
||||
"HB.location": 0,
|
||||
"HB.name": 1,
|
||||
"HB.field.1": 2,
|
||||
"HB.field.2": 3,
|
||||
"HB.field.3": 4,
|
||||
},
|
||||
wantFieldHeaders: []string{"HB.field.1", "HB.field.2", "HB.field.3"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "mixed headers",
|
||||
rawHeaders: []string{"Header 1", "HB.name", "Header 2", "HB.field.2", "Header 3", "HB.field.3", "HB.location"},
|
||||
wantHbHeaders: map[string]int{
|
||||
"HB.name": 1,
|
||||
"HB.field.2": 3,
|
||||
"HB.field.3": 5,
|
||||
"HB.location": 6,
|
||||
},
|
||||
wantFieldHeaders: []string{"HB.field.2", "HB.field.3"},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotHbHeaders, gotFieldHeaders, err := parseHeaders(tt.rawHeaders)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseHeaders() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(gotHbHeaders, tt.wantHbHeaders) {
|
||||
t.Errorf("parseHeaders() gotHbHeaders = %v, want %v", gotHbHeaders, tt.wantHbHeaders)
|
||||
}
|
||||
if !reflect.DeepEqual(gotFieldHeaders, tt.wantFieldHeaders) {
|
||||
t.Errorf("parseHeaders() gotFieldHeaders = %v, want %v", gotFieldHeaders, tt.wantFieldHeaders)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_determineSeparator(t *testing.T) {
|
||||
type args struct {
|
||||
data []byte
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want rune
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "comma",
|
||||
args: args{
|
||||
data: CSVData_Comma,
|
||||
},
|
||||
want: ',',
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "tab",
|
||||
args: args{
|
||||
data: CSVData_Tab,
|
||||
},
|
||||
want: '\t',
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid",
|
||||
args: args{
|
||||
data: []byte("a;b;c"),
|
||||
},
|
||||
want: 0,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := determineSeparator(tt.args.data)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("determineSeparator() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("determineSeparator() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
38
backend/internal/core/services/reporting/value_parsers.go
Normal file
38
backend/internal/core/services/reporting/value_parsers.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parseSeparatedString(s string, sep string) ([]string, error) {
|
||||
list := strings.Split(s, sep)
|
||||
|
||||
csf := make([]string, 0, len(list))
|
||||
for _, s := range list {
|
||||
trimmed := strings.TrimSpace(s)
|
||||
if trimmed != "" {
|
||||
csf = append(csf, trimmed)
|
||||
}
|
||||
}
|
||||
|
||||
return csf, nil
|
||||
}
|
||||
|
||||
func parseFloat(s string) float64 {
|
||||
if s == "" {
|
||||
return 0
|
||||
}
|
||||
f, _ := strconv.ParseFloat(s, 64)
|
||||
return f
|
||||
}
|
||||
|
||||
func parseBool(s string) bool {
|
||||
b, _ := strconv.ParseBool(s)
|
||||
return b
|
||||
}
|
||||
|
||||
func parseInt(s string) int {
|
||||
i, _ := strconv.Atoi(s)
|
||||
return i
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_parseSeparatedString(t *testing.T) {
|
||||
type args struct {
|
||||
s string
|
||||
sep string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "comma",
|
||||
args: args{
|
||||
s: "a,b,c",
|
||||
sep: ",",
|
||||
},
|
||||
want: []string{"a", "b", "c"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "trimmed comma",
|
||||
args: args{
|
||||
s: "a, b, c",
|
||||
sep: ",",
|
||||
},
|
||||
want: []string{"a", "b", "c"},
|
||||
},
|
||||
{
|
||||
name: "excessive whitespace",
|
||||
args: args{
|
||||
s: " a, b, c ",
|
||||
sep: ",",
|
||||
},
|
||||
want: []string{"a", "b", "c"},
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
args: args{
|
||||
s: "",
|
||||
sep: ",",
|
||||
},
|
||||
want: []string{},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseSeparatedString(tt.args.s, tt.args.sep)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseSeparatedString() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("parseSeparatedString() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
81
backend/internal/core/services/service_background.go
Normal file
81
backend/internal/core/services/service_background.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containrrr/shoutrrr"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type BackgroundService struct {
|
||||
repos *repo.AllRepos
|
||||
}
|
||||
|
||||
func (svc *BackgroundService) SendNotifiersToday(ctx context.Context) error {
|
||||
// Get All Groups
|
||||
groups, err := svc.repos.Groups.GetAllGroups(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
today := types.DateFromTime(time.Now())
|
||||
|
||||
for i := range groups {
|
||||
group := groups[i]
|
||||
|
||||
entries, err := svc.repos.MaintEntry.GetScheduled(ctx, group.ID, today)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
log.Debug().
|
||||
Str("group_name", group.Name).
|
||||
Str("group_id", group.ID.String()).
|
||||
Msg("No scheduled maintenance for today")
|
||||
continue
|
||||
}
|
||||
|
||||
notifiers, err := svc.repos.Notifiers.GetByGroup(ctx, group.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
urls := make([]string, len(notifiers))
|
||||
for i := range notifiers {
|
||||
urls[i] = notifiers[i].URL
|
||||
}
|
||||
|
||||
bldr := strings.Builder{}
|
||||
|
||||
bldr.WriteString("Homebox Maintenance for (")
|
||||
bldr.WriteString(today.String())
|
||||
bldr.WriteString("):\n")
|
||||
|
||||
for i := range entries {
|
||||
entry := entries[i]
|
||||
bldr.WriteString(" - ")
|
||||
bldr.WriteString(entry.Name)
|
||||
bldr.WriteString("\n")
|
||||
}
|
||||
|
||||
var sendErrs []error
|
||||
for i := range urls {
|
||||
err := shoutrrr.Send(urls[i], bldr.String())
|
||||
|
||||
if err != nil {
|
||||
sendErrs = append(sendErrs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(sendErrs) > 0 {
|
||||
return sendErrs[0]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -3,10 +3,13 @@ package services
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/core/services/reporting"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -18,179 +21,332 @@ type ItemService struct {
|
||||
repo *repo.AllRepos
|
||||
|
||||
filepath string
|
||||
// at is a map of tokens to attachment IDs. This is used to store the attachment ID
|
||||
// for issued URLs
|
||||
at attachmentTokens
|
||||
|
||||
autoIncrementAssetID bool
|
||||
}
|
||||
|
||||
func (svc *ItemService) CsvImport(ctx context.Context, GID uuid.UUID, data [][]string) (int, error) {
|
||||
loaded := []csvRow{}
|
||||
|
||||
// Skip first row
|
||||
for _, row := range data[1:] {
|
||||
// Skip empty rows
|
||||
if len(row) == 0 {
|
||||
continue
|
||||
func (svc *ItemService) Create(ctx Context, item repo.ItemCreate) (repo.ItemOut, error) {
|
||||
if svc.autoIncrementAssetID {
|
||||
highest, err := svc.repo.Items.GetHighestAssetID(ctx, ctx.GID)
|
||||
if err != nil {
|
||||
return repo.ItemOut{}, err
|
||||
}
|
||||
|
||||
if len(row) != NumOfCols {
|
||||
return 0, ErrInvalidCsv
|
||||
}
|
||||
|
||||
r := newCsvRow(row)
|
||||
loaded = append(loaded, r)
|
||||
item.AssetID = repo.AssetID(highest + 1)
|
||||
}
|
||||
|
||||
// validate rows
|
||||
var errMap = map[int][]error{}
|
||||
var hasErr bool
|
||||
for i, r := range loaded {
|
||||
return svc.repo.Items.Create(ctx, ctx.GID, item)
|
||||
}
|
||||
|
||||
errs := r.validate()
|
||||
|
||||
if len(errs) > 0 {
|
||||
hasErr = true
|
||||
lineNum := i + 2
|
||||
|
||||
errMap[lineNum] = errs
|
||||
}
|
||||
}
|
||||
|
||||
if hasErr {
|
||||
for lineNum, errs := range errMap {
|
||||
for _, err := range errs {
|
||||
log.Error().Err(err).Int("line", lineNum).Msg("csv import error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bootstrap the locations and labels so we can reuse the created IDs for the items
|
||||
locations := map[string]uuid.UUID{}
|
||||
existingLocation, err := svc.repo.Locations.GetAll(ctx, GID, repo.LocationQuery{})
|
||||
func (svc *ItemService) EnsureAssetID(ctx context.Context, GID uuid.UUID) (int, error) {
|
||||
items, err := svc.repo.Items.GetAllZeroAssetID(ctx, GID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for _, loc := range existingLocation {
|
||||
locations[loc.Name] = loc.ID
|
||||
}
|
||||
|
||||
labels := map[string]uuid.UUID{}
|
||||
existingLabels, err := svc.repo.Labels.GetAll(ctx, GID)
|
||||
highest, err := svc.repo.Items.GetHighestAssetID(ctx, GID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for _, label := range existingLabels {
|
||||
labels[label.Name] = label.ID
|
||||
}
|
||||
|
||||
for _, row := range loaded {
|
||||
finished := 0
|
||||
for _, item := range items {
|
||||
highest++
|
||||
|
||||
// Locations
|
||||
if _, exists := locations[row.Location]; !exists {
|
||||
result, err := svc.repo.Locations.Create(ctx, GID, repo.LocationCreate{
|
||||
Name: row.Location,
|
||||
Description: "",
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
locations[row.Location] = result.ID
|
||||
err = svc.repo.Items.SetAssetID(ctx, GID, item.ID, repo.AssetID(highest))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Labels
|
||||
finished++
|
||||
}
|
||||
|
||||
for _, label := range row.getLabels() {
|
||||
if _, exists := labels[label]; exists {
|
||||
continue
|
||||
}
|
||||
result, err := svc.repo.Labels.Create(ctx, GID, repo.LabelCreate{
|
||||
Name: label,
|
||||
Description: "",
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
labels[label] = result.ID
|
||||
return finished, nil
|
||||
}
|
||||
|
||||
func (svc *ItemService) EnsureImportRef(ctx context.Context, GID uuid.UUID) (int, error) {
|
||||
ids, err := svc.repo.Items.GetAllZeroImportRef(ctx, GID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
finished := 0
|
||||
for _, itemID := range ids {
|
||||
ref := uuid.New().String()[0:8]
|
||||
|
||||
err = svc.repo.Items.Patch(ctx, GID, itemID, repo.ItemPatch{ImportRef: &ref})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
finished++
|
||||
}
|
||||
|
||||
return finished, nil
|
||||
}
|
||||
|
||||
func serializeLocation[T ~[]string](location T) string {
|
||||
return strings.Join(location, "/")
|
||||
}
|
||||
|
||||
// CsvImport imports items from a CSV file. using the standard defined format.
|
||||
//
|
||||
// CsvImport applies the following rules/operations
|
||||
//
|
||||
// 1. If the item does not exist, it is created.
|
||||
// 2. If the item has a ImportRef and it exists it is skipped
|
||||
// 3. Locations and Labels are created if they do not exist.
|
||||
func (svc *ItemService) CsvImport(ctx context.Context, GID uuid.UUID, data io.Reader) (int, error) {
|
||||
sheet := reporting.IOSheet{}
|
||||
|
||||
err := sheet.Read(data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Labels
|
||||
|
||||
labelMap := make(map[string]uuid.UUID)
|
||||
{
|
||||
labels, err := svc.repo.Labels.GetAll(ctx, GID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
for _, label := range labels {
|
||||
labelMap[label.Name] = label.ID
|
||||
}
|
||||
}
|
||||
|
||||
// Create the items
|
||||
var count int
|
||||
for _, row := range loaded {
|
||||
// Check Import Ref
|
||||
if row.Item.ImportRef != "" {
|
||||
exists, err := svc.repo.Items.CheckRef(ctx, GID, row.Item.ImportRef)
|
||||
// ========================================
|
||||
// Locations
|
||||
|
||||
locationMap := make(map[string]uuid.UUID)
|
||||
{
|
||||
locations, err := svc.repo.Locations.Tree(ctx, GID, repo.TreeQuery{WithItems: false})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Traverse the tree and build a map of location full paths to IDs
|
||||
// where the full path is the location name joined by slashes.
|
||||
var traverse func(location *repo.TreeItem, path []string)
|
||||
traverse = func(location *repo.TreeItem, path []string) {
|
||||
path = append(path, location.Name)
|
||||
|
||||
locationMap[serializeLocation(path)] = location.ID
|
||||
|
||||
for _, child := range location.Children {
|
||||
traverse(child, path)
|
||||
}
|
||||
}
|
||||
|
||||
for _, location := range locations {
|
||||
traverse(&location, []string{})
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Import items
|
||||
|
||||
// Asset ID Pre-Check
|
||||
highestAID := repo.AssetID(-1)
|
||||
if svc.autoIncrementAssetID {
|
||||
highestAID, err = svc.repo.Items.GetHighestAssetID(ctx, GID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
finished := 0
|
||||
|
||||
for i := range sheet.Rows {
|
||||
row := sheet.Rows[i]
|
||||
|
||||
createRequired := true
|
||||
|
||||
// ========================================
|
||||
// Preflight check for existing item
|
||||
if row.ImportRef != "" {
|
||||
exists, err := svc.repo.Items.CheckRef(ctx, GID, row.ImportRef)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error checking for existing item with ref %q: %w", row.ImportRef, err)
|
||||
}
|
||||
|
||||
if exists {
|
||||
continue
|
||||
createRequired = false
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Pre-Create Labels as necessary
|
||||
labelIds := make([]uuid.UUID, len(row.LabelStr))
|
||||
|
||||
for j := range row.LabelStr {
|
||||
label := row.LabelStr[j]
|
||||
|
||||
id, ok := labelMap[label]
|
||||
if !ok {
|
||||
newLabel, err := svc.repo.Labels.Create(ctx, GID, repo.LabelCreate{Name: label})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
id = newLabel.ID
|
||||
}
|
||||
|
||||
labelIds[j] = id
|
||||
labelMap[label] = id
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Pre-Create Locations as necessary
|
||||
path := serializeLocation(row.Location)
|
||||
|
||||
locationID, ok := locationMap[path]
|
||||
if !ok { // Traverse the path of LocationStr and check each path element to see if it exists already, if not create it.
|
||||
paths := []string{}
|
||||
for i, pathElement := range row.Location {
|
||||
paths = append(paths, pathElement)
|
||||
path := serializeLocation(paths)
|
||||
|
||||
locationID, ok = locationMap[path]
|
||||
if !ok {
|
||||
parentID := uuid.Nil
|
||||
|
||||
// Get the parent ID
|
||||
if i > 0 {
|
||||
parentPath := serializeLocation(row.Location[:i])
|
||||
parentID = locationMap[parentPath]
|
||||
}
|
||||
|
||||
newLocation, err := svc.repo.Locations.Create(ctx, GID, repo.LocationCreate{
|
||||
ParentID: parentID,
|
||||
Name: pathElement,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
locationID = newLocation.ID
|
||||
}
|
||||
|
||||
locationMap[path] = locationID
|
||||
}
|
||||
|
||||
locationID, ok = locationMap[path]
|
||||
if !ok {
|
||||
return 0, errors.New("failed to create location")
|
||||
}
|
||||
}
|
||||
|
||||
var effAID repo.AssetID
|
||||
if svc.autoIncrementAssetID && row.AssetID.Nil() {
|
||||
effAID = highestAID + 1
|
||||
highestAID++
|
||||
} else {
|
||||
effAID = row.AssetID
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Create Item
|
||||
var item repo.ItemOut
|
||||
switch {
|
||||
case createRequired:
|
||||
newItem := repo.ItemCreate{
|
||||
ImportRef: row.ImportRef,
|
||||
Name: row.Name,
|
||||
Description: row.Description,
|
||||
AssetID: effAID,
|
||||
LocationID: locationID,
|
||||
LabelIDs: labelIds,
|
||||
}
|
||||
|
||||
item, err = svc.repo.Items.Create(ctx, GID, newItem)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("error checking import ref")
|
||||
return 0, err
|
||||
}
|
||||
default:
|
||||
item, err = svc.repo.Items.GetByRef(ctx, GID, row.ImportRef)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
locationID := locations[row.Location]
|
||||
labelIDs := []uuid.UUID{}
|
||||
for _, label := range row.getLabels() {
|
||||
labelIDs = append(labelIDs, labels[label])
|
||||
if item.ID == uuid.Nil {
|
||||
panic("item ID is nil on import - this should never happen")
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Str("name", row.Item.Name).
|
||||
Str("location", row.Location).
|
||||
Msgf("Creating Item: %s", row.Item.Name)
|
||||
|
||||
result, err := svc.repo.Items.Create(ctx, GID, repo.ItemCreate{
|
||||
ImportRef: row.Item.ImportRef,
|
||||
Name: row.Item.Name,
|
||||
Description: row.Item.Description,
|
||||
LabelIDs: labelIDs,
|
||||
LocationID: locationID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return count, err
|
||||
fields := make([]repo.ItemField, len(row.Fields))
|
||||
for i := range row.Fields {
|
||||
fields[i] = repo.ItemField{
|
||||
Name: row.Fields[i].Name,
|
||||
Type: "text",
|
||||
TextValue: row.Fields[i].Value,
|
||||
}
|
||||
}
|
||||
|
||||
// Update the item with the rest of the data
|
||||
_, err = svc.repo.Items.UpdateByGroup(ctx, GID, repo.ItemUpdate{
|
||||
// Edges
|
||||
updateItem := repo.ItemUpdate{
|
||||
ID: item.ID,
|
||||
LabelIDs: labelIds,
|
||||
LocationID: locationID,
|
||||
LabelIDs: labelIDs,
|
||||
|
||||
// General Fields
|
||||
ID: result.ID,
|
||||
Name: result.Name,
|
||||
Description: result.Description,
|
||||
Insured: row.Item.Insured,
|
||||
Notes: row.Item.Notes,
|
||||
Quantity: row.Item.Quantity,
|
||||
Name: row.Name,
|
||||
Description: row.Description,
|
||||
AssetID: effAID,
|
||||
Insured: row.Insured,
|
||||
Quantity: row.Quantity,
|
||||
Archived: row.Archived,
|
||||
|
||||
// Identifies the item as imported
|
||||
SerialNumber: row.Item.SerialNumber,
|
||||
ModelNumber: row.Item.ModelNumber,
|
||||
Manufacturer: row.Item.Manufacturer,
|
||||
PurchasePrice: row.PurchasePrice,
|
||||
PurchaseFrom: row.PurchaseFrom,
|
||||
PurchaseTime: row.PurchaseTime,
|
||||
|
||||
// Purchase
|
||||
PurchaseFrom: row.Item.PurchaseFrom,
|
||||
PurchasePrice: row.Item.PurchasePrice,
|
||||
PurchaseTime: row.Item.PurchaseTime,
|
||||
Manufacturer: row.Manufacturer,
|
||||
ModelNumber: row.ModelNumber,
|
||||
SerialNumber: row.SerialNumber,
|
||||
|
||||
// Warranty
|
||||
LifetimeWarranty: row.Item.LifetimeWarranty,
|
||||
WarrantyExpires: row.Item.WarrantyExpires,
|
||||
WarrantyDetails: row.Item.WarrantyDetails,
|
||||
LifetimeWarranty: row.LifetimeWarranty,
|
||||
WarrantyExpires: row.WarrantyExpires,
|
||||
WarrantyDetails: row.WarrantyDetails,
|
||||
|
||||
SoldTo: row.Item.SoldTo,
|
||||
SoldPrice: row.Item.SoldPrice,
|
||||
SoldTime: row.Item.SoldTime,
|
||||
SoldNotes: row.Item.SoldNotes,
|
||||
})
|
||||
SoldTo: row.SoldTo,
|
||||
SoldTime: row.SoldTime,
|
||||
SoldPrice: row.SoldPrice,
|
||||
SoldNotes: row.SoldNotes,
|
||||
|
||||
if err != nil {
|
||||
return count, err
|
||||
Notes: row.Notes,
|
||||
Fields: fields,
|
||||
}
|
||||
|
||||
count++
|
||||
item, err = svc.repo.Items.UpdateByGroup(ctx, GID, updateItem)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
finished++
|
||||
}
|
||||
return count, nil
|
||||
|
||||
return finished, nil
|
||||
}
|
||||
|
||||
func (svc *ItemService) ExportTSV(ctx context.Context, GID uuid.UUID) ([][]string, error) {
|
||||
items, err := svc.repo.Items.GetAll(ctx, GID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sheet := reporting.IOSheet{}
|
||||
|
||||
sheet.ReadItems(items)
|
||||
|
||||
return sheet.TSV()
|
||||
}
|
||||
|
||||
func (svc *ItemService) ExportBillOfMaterialsTSV(ctx context.Context, GID uuid.UUID) ([]byte, error) {
|
||||
items, err := svc.repo.Items.GetAll(ctx, GID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reporting.BillOfMaterialsTSV(items)
|
||||
}
|
||||
|
||||
@@ -4,71 +4,15 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/hasher"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// TODO: this isn't a scalable solution, tokens should be stored in the database
|
||||
type attachmentTokens map[string]uuid.UUID
|
||||
|
||||
func (at attachmentTokens) Add(token string, id uuid.UUID) {
|
||||
at[token] = id
|
||||
|
||||
log.Debug().Str("token", token).Str("uuid", id.String()).Msg("added token")
|
||||
|
||||
go func() {
|
||||
ch := time.After(1 * time.Minute)
|
||||
<-ch
|
||||
at.Delete(token)
|
||||
log.Debug().Str("token", token).Msg("deleted token")
|
||||
}()
|
||||
}
|
||||
|
||||
func (at attachmentTokens) Get(token string) (uuid.UUID, bool) {
|
||||
id, ok := at[token]
|
||||
return id, ok
|
||||
}
|
||||
|
||||
func (at attachmentTokens) Delete(token string) {
|
||||
delete(at, token)
|
||||
}
|
||||
|
||||
func (svc *ItemService) AttachmentToken(ctx Context, itemId, attachmentId uuid.UUID) (string, error) {
|
||||
_, err := svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
token := hasher.GenerateToken()
|
||||
|
||||
// Ensure that the file exists
|
||||
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(attachment.Edges.Document.Path); os.IsNotExist(err) {
|
||||
_ = svc.AttachmentDelete(ctx, ctx.GID, itemId, attachmentId)
|
||||
return "", ErrNotFound
|
||||
}
|
||||
|
||||
svc.at.Add(token.Raw, attachmentId)
|
||||
|
||||
return token.Raw, nil
|
||||
}
|
||||
|
||||
func (svc *ItemService) AttachmentPath(ctx context.Context, token string) (*ent.Document, error) {
|
||||
attachmentId, ok := svc.at.Get(token)
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
func (svc *ItemService) AttachmentPath(ctx context.Context, attachmentId uuid.UUID) (*ent.Document, error) {
|
||||
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -58,5 +58,4 @@ func TestItemService_AddAttachment(t *testing.T) {
|
||||
bts, err := os.ReadFile(storedPath)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, contents, string(bts))
|
||||
|
||||
}
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
)
|
||||
|
||||
var ErrInvalidCsv = errors.New("invalid csv")
|
||||
|
||||
const NumOfCols = 21
|
||||
|
||||
func parseFloat(s string) float64 {
|
||||
if s == "" {
|
||||
return 0
|
||||
}
|
||||
f, _ := strconv.ParseFloat(s, 64)
|
||||
return f
|
||||
}
|
||||
|
||||
func parseDate(s string) time.Time {
|
||||
if s == "" {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
p, _ := time.Parse("01/02/2006", s)
|
||||
return p
|
||||
}
|
||||
|
||||
func parseBool(s string) bool {
|
||||
switch strings.ToLower(s) {
|
||||
case "true", "yes", "1":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func parseInt(s string) int {
|
||||
i, _ := strconv.Atoi(s)
|
||||
return i
|
||||
}
|
||||
|
||||
type csvRow struct {
|
||||
Item repo.ItemOut
|
||||
Location string
|
||||
LabelStr string
|
||||
}
|
||||
|
||||
func newCsvRow(row []string) csvRow {
|
||||
return csvRow{
|
||||
Location: row[1],
|
||||
LabelStr: row[2],
|
||||
Item: repo.ItemOut{
|
||||
ItemSummary: repo.ItemSummary{
|
||||
ImportRef: row[0],
|
||||
Quantity: parseInt(row[3]),
|
||||
Name: row[4],
|
||||
Description: row[5],
|
||||
Insured: parseBool(row[6]),
|
||||
},
|
||||
SerialNumber: row[7],
|
||||
ModelNumber: row[8],
|
||||
Manufacturer: row[9],
|
||||
Notes: row[10],
|
||||
PurchaseFrom: row[11],
|
||||
PurchasePrice: parseFloat(row[12]),
|
||||
PurchaseTime: parseDate(row[13]),
|
||||
LifetimeWarranty: parseBool(row[14]),
|
||||
WarrantyExpires: parseDate(row[15]),
|
||||
WarrantyDetails: row[16],
|
||||
SoldTo: row[17],
|
||||
SoldPrice: parseFloat(row[18]),
|
||||
SoldTime: parseDate(row[19]),
|
||||
SoldNotes: row[20],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c csvRow) getLabels() []string {
|
||||
split := strings.Split(c.LabelStr, ";")
|
||||
|
||||
// Trim each
|
||||
for i, s := range split {
|
||||
split[i] = strings.TrimSpace(s)
|
||||
}
|
||||
|
||||
// Remove empty
|
||||
for i, s := range split {
|
||||
if s == "" {
|
||||
split = append(split[:i], split[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return split
|
||||
}
|
||||
|
||||
func (c csvRow) validate() []error {
|
||||
var errs []error
|
||||
|
||||
add := func(err error) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
required := func(s string, name string) {
|
||||
if s == "" {
|
||||
add(errors.New(name + " is required"))
|
||||
}
|
||||
}
|
||||
|
||||
required(c.Location, "Location")
|
||||
required(c.Item.Name, "Name")
|
||||
|
||||
return errs
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const CSV_DATA = `
|
||||
Import Ref,Location,Labels,Quantity,Name,Description,Insured,Serial Number,Mode Number,Manufacturer,Notes,Purchase From,Purchased Price,Purchased Time,Lifetime Warranty,Warranty Expires,Warranty Details,Sold To,Sold Price,Sold Time,Sold Notes
|
||||
A,Garage,IOT;Home Assistant; Z-Wave,1,Zooz Universal Relay ZEN17,Description 1,TRUE,,ZEN17,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021,
|
||||
B,Living Room,IOT;Home Assistant; Z-Wave,1,Zooz Motion Sensor,Description 2,FALSE,,ZSE18,Zooz,,Amazon,29.95,10/15/2021,,10/15/2021,,,,10/15/2021,
|
||||
C,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,Description 3,TRUE,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021,
|
||||
D,Downstairs,IOT;Home Assistant; Z-Wave,1,Ecolink Z-Wave PIR Motion Sensor,Description 4,FALSE,,PIRZWAVE2.5-ECO,Ecolink,,Amazon,35.58,10/21/2020,,10/21/2020,,,,10/21/2020,
|
||||
E,Entry,IOT;Home Assistant; Z-Wave,1,Yale Security Touchscreen Deadbolt,Description 5,TRUE,,YRD226ZW2619,Yale,,Amazon,120.39,10/14/2020,,10/14/2020,,,,10/14/2020,
|
||||
F,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,Description 6,FALSE,,39351,Honeywell,,Amazon,65.98,09/30/2020,,09/30/2020,,,,09/30/2020,`
|
||||
|
||||
func loadcsv() [][]string {
|
||||
reader := csv.NewReader(bytes.NewBuffer([]byte(CSV_DATA)))
|
||||
|
||||
records, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return records
|
||||
}
|
||||
|
||||
func Test_CorrectDateParsing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
expected := []time.Time{
|
||||
time.Date(2021, 10, 13, 0, 0, 0, 0, time.UTC),
|
||||
time.Date(2021, 10, 15, 0, 0, 0, 0, time.UTC),
|
||||
time.Date(2021, 10, 13, 0, 0, 0, 0, time.UTC),
|
||||
time.Date(2020, 10, 21, 0, 0, 0, 0, time.UTC),
|
||||
time.Date(2020, 10, 14, 0, 0, 0, 0, time.UTC),
|
||||
time.Date(2020, 9, 30, 0, 0, 0, 0, time.UTC),
|
||||
}
|
||||
|
||||
records := loadcsv()
|
||||
|
||||
for i, record := range records {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
entity := newCsvRow(record)
|
||||
expected := expected[i-1]
|
||||
|
||||
assert.Equal(t, expected, entity.Item.PurchaseTime, fmt.Sprintf("Failed on row %d", i))
|
||||
assert.Equal(t, expected, entity.Item.WarrantyExpires, fmt.Sprintf("Failed on row %d", i))
|
||||
assert.Equal(t, expected, entity.Item.SoldTime, fmt.Sprintf("Failed on row %d", i))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_csvRow_getLabels(t *testing.T) {
|
||||
type fields struct {
|
||||
LabelStr string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "basic test",
|
||||
fields: fields{
|
||||
LabelStr: "IOT;Home Assistant;Z-Wave",
|
||||
},
|
||||
want: []string{"IOT", "Home Assistant", "Z-Wave"},
|
||||
},
|
||||
{
|
||||
name: "no labels",
|
||||
fields: fields{
|
||||
LabelStr: "",
|
||||
},
|
||||
want: []string{},
|
||||
},
|
||||
{
|
||||
name: "single label",
|
||||
fields: fields{
|
||||
LabelStr: "IOT",
|
||||
},
|
||||
want: []string{"IOT"},
|
||||
},
|
||||
{
|
||||
name: "trailing semicolon",
|
||||
fields: fields{
|
||||
LabelStr: "IOT;",
|
||||
},
|
||||
want: []string{"IOT"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "whitespace",
|
||||
fields: fields{
|
||||
LabelStr: " IOT; Home Assistant; Z-Wave ",
|
||||
},
|
||||
want: []string{"IOT", "Home Assistant", "Z-Wave"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := csvRow{
|
||||
LabelStr: tt.fields.LabelStr,
|
||||
}
|
||||
if got := c.getLabels(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("csvRow.getLabels() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestItemService_CsvImport(t *testing.T) {
|
||||
data := loadcsv()
|
||||
svc := &ItemService{
|
||||
repo: tRepos,
|
||||
}
|
||||
count, err := svc.CsvImport(context.Background(), tGroup.ID, data)
|
||||
assert.Equal(t, 6, count)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check import refs are deduplicated
|
||||
count, err = svc.CsvImport(context.Background(), tGroup.ID, data)
|
||||
assert.Equal(t, 0, count)
|
||||
assert.NoError(t, err)
|
||||
|
||||
items, err := svc.repo.Items.GetAll(context.Background(), tGroup.ID)
|
||||
assert.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
for _, item := range items {
|
||||
err := svc.repo.Items.Delete(context.Background(), item.ID)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
|
||||
assert.Equal(t, len(items), 6)
|
||||
|
||||
dataCsv := []csvRow{}
|
||||
for _, item := range data {
|
||||
dataCsv = append(dataCsv, newCsvRow(item))
|
||||
}
|
||||
|
||||
allLocation, err := tRepos.Locations.GetAll(context.Background(), tGroup.ID, repo.LocationQuery{})
|
||||
assert.NoError(t, err)
|
||||
locNames := []string{}
|
||||
for _, loc := range allLocation {
|
||||
locNames = append(locNames, loc.Name)
|
||||
}
|
||||
|
||||
allLabels, err := tRepos.Labels.GetAll(context.Background(), tGroup.ID)
|
||||
assert.NoError(t, err)
|
||||
labelNames := []string{}
|
||||
for _, label := range allLabels {
|
||||
labelNames = append(labelNames, label.Name)
|
||||
}
|
||||
|
||||
ids := []uuid.UUID{}
|
||||
t.Cleanup((func() {
|
||||
for _, id := range ids {
|
||||
err := svc.repo.Items.Delete(context.Background(), id)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}))
|
||||
|
||||
for _, item := range items {
|
||||
assert.Contains(t, locNames, item.Location.Name)
|
||||
for _, label := range item.Labels {
|
||||
assert.Contains(t, labelNames, label.Name)
|
||||
}
|
||||
|
||||
for _, csvRow := range dataCsv {
|
||||
if csvRow.Item.Name == item.Name {
|
||||
assert.Equal(t, csvRow.Item.Description, item.Description)
|
||||
assert.Equal(t, csvRow.Item.Quantity, item.Quantity)
|
||||
assert.Equal(t, csvRow.Item.Insured, item.Insured)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/pkgs/hasher"
|
||||
"github.com/rs/zerolog/log"
|
||||
@@ -30,8 +31,9 @@ type (
|
||||
Password string `json:"password"`
|
||||
}
|
||||
UserAuthTokenDetail struct {
|
||||
Raw string `json:"raw"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
Raw string `json:"raw"`
|
||||
AttachmentToken string `json:"attachmentToken"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
}
|
||||
LoginForm struct {
|
||||
Username string `json:"username"`
|
||||
@@ -49,21 +51,25 @@ 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
|
||||
log.Debug().Msg("creating new group")
|
||||
creatingGroup = true
|
||||
group, err = svc.repos.Groups.GroupCreate(ctx, "Home")
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to create group")
|
||||
return repo.UserOut{}, err
|
||||
}
|
||||
default:
|
||||
log.Debug().Msg("joining existing group")
|
||||
token, err = svc.repos.Groups.InvitationGet(ctx, hasher.HashToken(data.GroupToken))
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to get invitation token")
|
||||
@@ -79,7 +85,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)
|
||||
@@ -87,21 +93,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, usr.GroupID, label)
|
||||
if err != nil {
|
||||
return repo.UserOut{}, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, location := range defaultLocations() {
|
||||
_, err := svc.repos.Locations.Create(ctx, usr.GroupID, 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 {
|
||||
@@ -131,21 +140,46 @@ func (svc *UserService) UpdateSelf(ctx context.Context, ID uuid.UUID, data repo.
|
||||
// ============================================================================
|
||||
// User Authentication
|
||||
|
||||
func (svc *UserService) createToken(ctx context.Context, userId uuid.UUID) (UserAuthTokenDetail, error) {
|
||||
newToken := hasher.GenerateToken()
|
||||
func (svc *UserService) createSessionToken(ctx context.Context, userId uuid.UUID, extendedSession bool) (UserAuthTokenDetail, error) {
|
||||
attachmentToken := hasher.GenerateToken()
|
||||
|
||||
created, err := svc.repos.AuthTokens.CreateToken(ctx, repo.UserAuthTokenCreate{
|
||||
expiresAt := time.Now().Add(oneWeek)
|
||||
if extendedSession {
|
||||
expiresAt = time.Now().Add(oneWeek * 4)
|
||||
}
|
||||
|
||||
attachmentData := repo.UserAuthTokenCreate{
|
||||
UserID: userId,
|
||||
TokenHash: newToken.Hash,
|
||||
ExpiresAt: time.Now().Add(oneWeek),
|
||||
})
|
||||
TokenHash: attachmentToken.Hash,
|
||||
ExpiresAt: expiresAt,
|
||||
}
|
||||
|
||||
return UserAuthTokenDetail{Raw: newToken.Raw, ExpiresAt: created.ExpiresAt}, err
|
||||
_, err := svc.repos.AuthTokens.CreateToken(ctx, attachmentData, authroles.RoleAttachments)
|
||||
if err != nil {
|
||||
return UserAuthTokenDetail{}, err
|
||||
}
|
||||
|
||||
userToken := hasher.GenerateToken()
|
||||
data := repo.UserAuthTokenCreate{
|
||||
UserID: userId,
|
||||
TokenHash: userToken.Hash,
|
||||
ExpiresAt: expiresAt,
|
||||
}
|
||||
|
||||
created, err := svc.repos.AuthTokens.CreateToken(ctx, data, authroles.RoleUser)
|
||||
if err != nil {
|
||||
return UserAuthTokenDetail{}, err
|
||||
}
|
||||
|
||||
return UserAuthTokenDetail{
|
||||
Raw: userToken.Raw,
|
||||
ExpiresAt: created.ExpiresAt,
|
||||
AttachmentToken: attachmentToken.Raw,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (svc *UserService) Login(ctx context.Context, username, password string) (UserAuthTokenDetail, error) {
|
||||
func (svc *UserService) Login(ctx context.Context, username, password string, extendedSession bool) (UserAuthTokenDetail, error) {
|
||||
usr, err := svc.repos.Users.GetOneEmail(ctx, username)
|
||||
|
||||
if err != nil {
|
||||
// SECURITY: Perform hash to ensure response times are the same
|
||||
hasher.CheckPasswordHash("not-a-real-password", "not-a-real-password")
|
||||
@@ -156,7 +190,7 @@ func (svc *UserService) Login(ctx context.Context, username, password string) (U
|
||||
return UserAuthTokenDetail{}, ErrorInvalidLogin
|
||||
}
|
||||
|
||||
return svc.createToken(ctx, usr.ID)
|
||||
return svc.createSessionToken(ctx, usr.ID, extendedSession)
|
||||
}
|
||||
|
||||
func (svc *UserService) Logout(ctx context.Context, token string) error {
|
||||
@@ -169,14 +203,11 @@ func (svc *UserService) RenewToken(ctx context.Context, token string) (UserAuthT
|
||||
hash := hasher.HashToken(token)
|
||||
|
||||
dbToken, err := svc.repos.AuthTokens.GetUserFromToken(ctx, hash)
|
||||
|
||||
if err != nil {
|
||||
return UserAuthTokenDetail{}, ErrorInvalidToken
|
||||
}
|
||||
|
||||
newToken, _ := svc.createToken(ctx, dbToken.ID)
|
||||
|
||||
return newToken, nil
|
||||
return svc.createSessionToken(ctx, dbToken.ID, false)
|
||||
}
|
||||
|
||||
// DeleteSelf deletes the user that is currently logged based of the provided UUID
|
||||
|
||||
@@ -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,
|
||||
@@ -189,9 +189,3 @@ func (a *Attachment) String() string {
|
||||
|
||||
// Attachments is a parsable slice of Attachment.
|
||||
type Attachments []*Attachment
|
||||
|
||||
func (a Attachments) config(cfg config) {
|
||||
for _i := range a {
|
||||
a[_i].config = cfg
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,251 +13,157 @@ import (
|
||||
|
||||
// ID filters vertices based on their ID field.
|
||||
func ID(id uuid.UUID) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDEQ applies the EQ predicate on the ID field.
|
||||
func IDEQ(id uuid.UUID) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDNEQ applies the NEQ predicate on the ID field.
|
||||
func IDNEQ(id uuid.UUID) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldNEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDIn applies the In predicate on the ID field.
|
||||
func IDIn(ids ...uuid.UUID) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
v := make([]any, len(ids))
|
||||
for i := range v {
|
||||
v[i] = ids[i]
|
||||
}
|
||||
s.Where(sql.In(s.C(FieldID), v...))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDNotIn applies the NotIn predicate on the ID field.
|
||||
func IDNotIn(ids ...uuid.UUID) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
v := make([]any, len(ids))
|
||||
for i := range v {
|
||||
v[i] = ids[i]
|
||||
}
|
||||
s.Where(sql.NotIn(s.C(FieldID), v...))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldNotIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDGT applies the GT predicate on the ID field.
|
||||
func IDGT(id uuid.UUID) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldGT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDGTE applies the GTE predicate on the ID field.
|
||||
func IDGTE(id uuid.UUID) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldGTE(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLT applies the LT predicate on the ID field.
|
||||
func IDLT(id uuid.UUID) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldLT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLTE applies the LTE predicate on the ID field.
|
||||
func IDLTE(id uuid.UUID) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldLTE(FieldID, id))
|
||||
}
|
||||
|
||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||
func CreatedAt(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
||||
func UpdatedAt(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||
func CreatedAtNEQ(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldNEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||
func CreatedAtIn(vs ...time.Time) predicate.Attachment {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldCreatedAt), v...))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||
func CreatedAtNotIn(vs ...time.Time) predicate.Attachment {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldCreatedAt), v...))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||
func CreatedAtGT(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldGT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||
func CreatedAtGTE(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldGTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||
func CreatedAtLT(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldLT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||
func CreatedAtLTE(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldLTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
||||
func UpdatedAtEQ(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
||||
func UpdatedAtNEQ(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldNEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
||||
func UpdatedAtIn(vs ...time.Time) predicate.Attachment {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldUpdatedAt), v...))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldIn(FieldUpdatedAt, vs...))
|
||||
}
|
||||
|
||||
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
||||
func UpdatedAtNotIn(vs ...time.Time) predicate.Attachment {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldUpdatedAt), v...))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldNotIn(FieldUpdatedAt, vs...))
|
||||
}
|
||||
|
||||
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
||||
func UpdatedAtGT(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldGT(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
||||
func UpdatedAtGTE(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldGTE(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
||||
func UpdatedAtLT(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldLT(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
||||
func UpdatedAtLTE(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldLTE(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// TypeEQ applies the EQ predicate on the "type" field.
|
||||
func TypeEQ(v Type) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldType), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldEQ(FieldType, v))
|
||||
}
|
||||
|
||||
// TypeNEQ applies the NEQ predicate on the "type" field.
|
||||
func TypeNEQ(v Type) predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldType), v))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldNEQ(FieldType, v))
|
||||
}
|
||||
|
||||
// TypeIn applies the In predicate on the "type" field.
|
||||
func TypeIn(vs ...Type) predicate.Attachment {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldType), v...))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldIn(FieldType, vs...))
|
||||
}
|
||||
|
||||
// TypeNotIn applies the NotIn predicate on the "type" field.
|
||||
func TypeNotIn(vs ...Type) predicate.Attachment {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldType), v...))
|
||||
})
|
||||
return predicate.Attachment(sql.FieldNotIn(FieldType, vs...))
|
||||
}
|
||||
|
||||
// HasItem applies the HasEdge predicate on the "item" edge.
|
||||
@@ -265,7 +171,6 @@ func HasItem() predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(ItemTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn),
|
||||
)
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
@@ -293,7 +198,6 @@ func HasDocument() predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(DocumentTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, DocumentTable, DocumentColumn),
|
||||
)
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
|
||||
@@ -108,50 +108,8 @@ func (ac *AttachmentCreate) Mutation() *AttachmentMutation {
|
||||
|
||||
// Save creates the Attachment in the database.
|
||||
func (ac *AttachmentCreate) Save(ctx context.Context) (*Attachment, error) {
|
||||
var (
|
||||
err error
|
||||
node *Attachment
|
||||
)
|
||||
ac.defaults()
|
||||
if len(ac.hooks) == 0 {
|
||||
if err = ac.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, err = ac.sqlSave(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*AttachmentMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
if err = ac.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ac.mutation = mutation
|
||||
if node, err = ac.sqlSave(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mutation.id = &node.ID
|
||||
mutation.done = true
|
||||
return node, err
|
||||
})
|
||||
for i := len(ac.hooks) - 1; i >= 0; i-- {
|
||||
if ac.hooks[i] == nil {
|
||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = ac.hooks[i](mut)
|
||||
}
|
||||
v, err := mut.Mutate(ctx, ac.mutation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nv, ok := v.(*Attachment)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected node type %T returned from AttachmentMutation", v)
|
||||
}
|
||||
node = nv
|
||||
}
|
||||
return node, err
|
||||
return withHooks[*Attachment, AttachmentMutation](ctx, ac.sqlSave, ac.mutation, ac.hooks)
|
||||
}
|
||||
|
||||
// SaveX calls Save and panics if Save returns an error.
|
||||
@@ -222,6 +180,9 @@ func (ac *AttachmentCreate) check() error {
|
||||
}
|
||||
|
||||
func (ac *AttachmentCreate) sqlSave(ctx context.Context) (*Attachment, error) {
|
||||
if err := ac.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_node, _spec := ac.createSpec()
|
||||
if err := sqlgraph.CreateNode(ctx, ac.driver, _spec); err != nil {
|
||||
if sqlgraph.IsConstraintError(err) {
|
||||
@@ -236,46 +197,30 @@ func (ac *AttachmentCreate) sqlSave(ctx context.Context) (*Attachment, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ac.mutation.id = &_node.ID
|
||||
ac.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
|
||||
var (
|
||||
_node = &Attachment{config: ac.config}
|
||||
_spec = &sqlgraph.CreateSpec{
|
||||
Table: attachment.Table,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
}
|
||||
_spec = sqlgraph.NewCreateSpec(attachment.Table, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
|
||||
)
|
||||
if id, ok := ac.mutation.ID(); ok {
|
||||
_node.ID = id
|
||||
_spec.ID.Value = &id
|
||||
}
|
||||
if value, ok := ac.mutation.CreatedAt(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: attachment.FieldCreatedAt,
|
||||
})
|
||||
_spec.SetField(attachment.FieldCreatedAt, field.TypeTime, value)
|
||||
_node.CreatedAt = value
|
||||
}
|
||||
if value, ok := ac.mutation.UpdatedAt(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: attachment.FieldUpdatedAt,
|
||||
})
|
||||
_spec.SetField(attachment.FieldUpdatedAt, field.TypeTime, value)
|
||||
_node.UpdatedAt = value
|
||||
}
|
||||
if value, ok := ac.mutation.GetType(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeEnum,
|
||||
Value: value,
|
||||
Column: attachment.FieldType,
|
||||
})
|
||||
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
||||
_node.Type = value
|
||||
}
|
||||
if nodes := ac.mutation.ItemIDs(); len(nodes) > 0 {
|
||||
@@ -286,10 +231,7 @@ func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
|
||||
Columns: []string{attachment.ItemColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: item.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(item.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -306,10 +248,7 @@ func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
|
||||
Columns: []string{attachment.DocumentColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: document.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
|
||||
@@ -4,7 +4,6 @@ package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
@@ -28,34 +27,7 @@ func (ad *AttachmentDelete) Where(ps ...predicate.Attachment) *AttachmentDelete
|
||||
|
||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||
func (ad *AttachmentDelete) Exec(ctx context.Context) (int, error) {
|
||||
var (
|
||||
err error
|
||||
affected int
|
||||
)
|
||||
if len(ad.hooks) == 0 {
|
||||
affected, err = ad.sqlExec(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*AttachmentMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
ad.mutation = mutation
|
||||
affected, err = ad.sqlExec(ctx)
|
||||
mutation.done = true
|
||||
return affected, err
|
||||
})
|
||||
for i := len(ad.hooks) - 1; i >= 0; i-- {
|
||||
if ad.hooks[i] == nil {
|
||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = ad.hooks[i](mut)
|
||||
}
|
||||
if _, err := mut.Mutate(ctx, ad.mutation); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return affected, err
|
||||
return withHooks[int, AttachmentMutation](ctx, ad.sqlExec, ad.mutation, ad.hooks)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
@@ -68,15 +40,7 @@ func (ad *AttachmentDelete) ExecX(ctx context.Context) int {
|
||||
}
|
||||
|
||||
func (ad *AttachmentDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
_spec := &sqlgraph.DeleteSpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: attachment.Table,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
_spec := sqlgraph.NewDeleteSpec(attachment.Table, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
|
||||
if ps := ad.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
@@ -88,6 +52,7 @@ func (ad *AttachmentDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
ad.mutation.done = true
|
||||
return affected, err
|
||||
}
|
||||
|
||||
@@ -96,6 +61,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)
|
||||
@@ -111,5 +82,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,9 @@ 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
|
||||
withDocument *DocumentQuery
|
||||
@@ -40,26 +38,26 @@ func (aq *AttachmentQuery) Where(ps ...predicate.Attachment) *AttachmentQuery {
|
||||
return aq
|
||||
}
|
||||
|
||||
// Limit adds a limit step to the query.
|
||||
// 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 adds an offset step to the query.
|
||||
// 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
|
||||
}
|
||||
|
||||
// Order adds an order step to the query.
|
||||
// Order specifies how the records should be ordered.
|
||||
func (aq *AttachmentQuery) Order(o ...OrderFunc) *AttachmentQuery {
|
||||
aq.order = append(aq.order, o...)
|
||||
return aq
|
||||
@@ -67,7 +65,7 @@ func (aq *AttachmentQuery) Order(o ...OrderFunc) *AttachmentQuery {
|
||||
|
||||
// QueryItem chains the current query on the "item" edge.
|
||||
func (aq *AttachmentQuery) QueryItem() *ItemQuery {
|
||||
query := &ItemQuery{config: aq.config}
|
||||
query := (&ItemClient{config: aq.config}).Query()
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := aq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
@@ -89,7 +87,7 @@ func (aq *AttachmentQuery) QueryItem() *ItemQuery {
|
||||
|
||||
// QueryDocument chains the current query on the "document" edge.
|
||||
func (aq *AttachmentQuery) QueryDocument() *DocumentQuery {
|
||||
query := &DocumentQuery{config: aq.config}
|
||||
query := (&DocumentClient{config: aq.config}).Query()
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := aq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
@@ -112,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(ctx)
|
||||
nodes, err := aq.Limit(1).All(setContextOp(ctx, aq.ctx, "First"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -135,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(ctx); err != nil {
|
||||
if ids, err = aq.Limit(1).IDs(setContextOp(ctx, aq.ctx, "FirstID")); err != nil {
|
||||
return
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
@@ -158,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(ctx)
|
||||
nodes, err := aq.Limit(2).All(setContextOp(ctx, aq.ctx, "Only"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -186,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(ctx); err != nil {
|
||||
if ids, err = aq.Limit(2).IDs(setContextOp(ctx, aq.ctx, "OnlyID")); err != nil {
|
||||
return
|
||||
}
|
||||
switch len(ids) {
|
||||
@@ -211,10 +209,12 @@ 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 = setContextOp(ctx, aq.ctx, "All")
|
||||
if err := aq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return aq.sqlAll(ctx)
|
||||
qr := querierAll[[]*Attachment, *AttachmentQuery]()
|
||||
return withInterceptors[[]*Attachment](ctx, aq, qr, aq.inters)
|
||||
}
|
||||
|
||||
// AllX is like All, but panics if an error occurs.
|
||||
@@ -227,9 +227,12 @@ 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
|
||||
if err := aq.Select(attachment.FieldID).Scan(ctx, &ids); err != nil {
|
||||
func (aq *AttachmentQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
|
||||
if aq.ctx.Unique == nil && aq.path != nil {
|
||||
aq.Unique(true)
|
||||
}
|
||||
ctx = setContextOp(ctx, aq.ctx, "IDs")
|
||||
if err = aq.Select(attachment.FieldID).Scan(ctx, &ids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
@@ -246,10 +249,11 @@ 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 = setContextOp(ctx, aq.ctx, "Count")
|
||||
if err := aq.prepareQuery(ctx); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return aq.sqlCount(ctx)
|
||||
return withInterceptors[int](ctx, aq, querierCount[*AttachmentQuery](), aq.inters)
|
||||
}
|
||||
|
||||
// CountX is like Count, but panics if an error occurs.
|
||||
@@ -263,10 +267,15 @@ 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) {
|
||||
if err := aq.prepareQuery(ctx); err != nil {
|
||||
return false, err
|
||||
ctx = setContextOp(ctx, aq.ctx, "Exist")
|
||||
switch _, err := aq.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
return aq.sqlExist(ctx)
|
||||
}
|
||||
|
||||
// ExistX is like Exist, but panics if an error occurs.
|
||||
@@ -286,23 +295,22 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
// WithItem tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "item" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (aq *AttachmentQuery) WithItem(opts ...func(*ItemQuery)) *AttachmentQuery {
|
||||
query := &ItemQuery{config: aq.config}
|
||||
query := (&ItemClient{config: aq.config}).Query()
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
@@ -313,7 +321,7 @@ func (aq *AttachmentQuery) WithItem(opts ...func(*ItemQuery)) *AttachmentQuery {
|
||||
// WithDocument tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "document" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (aq *AttachmentQuery) WithDocument(opts ...func(*DocumentQuery)) *AttachmentQuery {
|
||||
query := &DocumentQuery{config: aq.config}
|
||||
query := (&DocumentClient{config: aq.config}).Query()
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
@@ -336,16 +344,11 @@ func (aq *AttachmentQuery) WithDocument(opts ...func(*DocumentQuery)) *Attachmen
|
||||
// Aggregate(ent.Count()).
|
||||
// Scan(ctx, &v)
|
||||
func (aq *AttachmentQuery) GroupBy(field string, fields ...string) *AttachmentGroupBy {
|
||||
grbuild := &AttachmentGroupBy{config: aq.config}
|
||||
grbuild.fields = append([]string{field}, fields...)
|
||||
grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
|
||||
if err := aq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return aq.sqlQuery(ctx), nil
|
||||
}
|
||||
aq.ctx.Fields = append([]string{field}, fields...)
|
||||
grbuild := &AttachmentGroupBy{build: aq}
|
||||
grbuild.flds = &aq.ctx.Fields
|
||||
grbuild.label = attachment.Label
|
||||
grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
|
||||
grbuild.scan = grbuild.Scan
|
||||
return grbuild
|
||||
}
|
||||
|
||||
@@ -362,15 +365,30 @@ 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...)
|
||||
selbuild := &AttachmentSelect{AttachmentQuery: aq}
|
||||
selbuild.label = attachment.Label
|
||||
selbuild.flds, selbuild.scan = &aq.fields, selbuild.Scan
|
||||
return selbuild
|
||||
aq.ctx.Fields = append(aq.ctx.Fields, fields...)
|
||||
sbuild := &AttachmentSelect{AttachmentQuery: aq}
|
||||
sbuild.label = attachment.Label
|
||||
sbuild.flds, sbuild.scan = &aq.ctx.Fields, sbuild.Scan
|
||||
return sbuild
|
||||
}
|
||||
|
||||
// Aggregate returns a AttachmentSelect configured with the given aggregations.
|
||||
func (aq *AttachmentQuery) Aggregate(fns ...AggregateFunc) *AttachmentSelect {
|
||||
return aq.Select().Aggregate(fns...)
|
||||
}
|
||||
|
||||
func (aq *AttachmentQuery) prepareQuery(ctx context.Context) error {
|
||||
for _, f := range aq.fields {
|
||||
for _, inter := range aq.inters {
|
||||
if inter == nil {
|
||||
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
|
||||
}
|
||||
if trv, ok := inter.(Traverser); ok {
|
||||
if err := trv.Traverse(ctx, aq); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, f := range aq.ctx.Fields {
|
||||
if !attachment.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
@@ -447,6 +465,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 {
|
||||
@@ -476,6 +497,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 {
|
||||
@@ -495,41 +519,22 @@ 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)
|
||||
}
|
||||
|
||||
func (aq *AttachmentQuery) sqlExist(ctx context.Context) (bool, error) {
|
||||
switch _, err := aq.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (aq *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
|
||||
_spec := &sqlgraph.QuerySpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: attachment.Table,
|
||||
Columns: attachment.Columns,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
},
|
||||
From: aq.sql,
|
||||
Unique: true,
|
||||
}
|
||||
if unique := aq.unique; unique != nil {
|
||||
_spec := sqlgraph.NewQuerySpec(attachment.Table, attachment.Columns, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
|
||||
_spec.From = aq.sql
|
||||
if unique := aq.ctx.Unique; unique != nil {
|
||||
_spec.Unique = *unique
|
||||
} else if aq.path != nil {
|
||||
_spec.Unique = true
|
||||
}
|
||||
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 {
|
||||
@@ -545,10 +550,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 {
|
||||
@@ -564,7 +569,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
|
||||
}
|
||||
@@ -573,7 +578,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 {
|
||||
@@ -582,12 +587,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
|
||||
@@ -595,13 +600,8 @@ func (aq *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||
|
||||
// AttachmentGroupBy is the group-by builder for Attachment entities.
|
||||
type AttachmentGroupBy struct {
|
||||
config
|
||||
selector
|
||||
fields []string
|
||||
fns []AggregateFunc
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
path func(context.Context) (*sql.Selector, error)
|
||||
build *AttachmentQuery
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the group-by query.
|
||||
@@ -610,74 +610,77 @@ func (agb *AttachmentGroupBy) Aggregate(fns ...AggregateFunc) *AttachmentGroupBy
|
||||
return agb
|
||||
}
|
||||
|
||||
// Scan applies the group-by query and scans the result into the given value.
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (agb *AttachmentGroupBy) Scan(ctx context.Context, v any) error {
|
||||
query, err := agb.path(ctx)
|
||||
if err != nil {
|
||||
ctx = setContextOp(ctx, agb.build.ctx, "GroupBy")
|
||||
if err := agb.build.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
agb.sql = query
|
||||
return agb.sqlScan(ctx, v)
|
||||
return scanWithInterceptors[*AttachmentQuery, *AttachmentGroupBy](ctx, agb.build, agb, agb.build.inters, v)
|
||||
}
|
||||
|
||||
func (agb *AttachmentGroupBy) sqlScan(ctx context.Context, v any) error {
|
||||
for _, f := range agb.fields {
|
||||
if !attachment.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("invalid field %q for group-by", f)}
|
||||
}
|
||||
}
|
||||
selector := agb.sqlQuery()
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := agb.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
func (agb *AttachmentGroupBy) sqlQuery() *sql.Selector {
|
||||
selector := agb.sql.Select()
|
||||
func (agb *AttachmentGroupBy) sqlScan(ctx context.Context, root *AttachmentQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx).Select()
|
||||
aggregation := make([]string, 0, len(agb.fns))
|
||||
for _, fn := range agb.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
// If no columns were selected in a custom aggregation function, the default
|
||||
// selection is the fields used for "group-by", and the aggregation functions.
|
||||
if len(selector.SelectedColumns()) == 0 {
|
||||
columns := make([]string, 0, len(agb.fields)+len(agb.fns))
|
||||
for _, f := range agb.fields {
|
||||
columns := make([]string, 0, len(*agb.flds)+len(agb.fns))
|
||||
for _, f := range *agb.flds {
|
||||
columns = append(columns, selector.C(f))
|
||||
}
|
||||
columns = append(columns, aggregation...)
|
||||
selector.Select(columns...)
|
||||
}
|
||||
return selector.GroupBy(selector.Columns(agb.fields...)...)
|
||||
selector.GroupBy(selector.Columns(*agb.flds...)...)
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := agb.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
// AttachmentSelect is the builder for selecting fields of Attachment entities.
|
||||
type AttachmentSelect struct {
|
||||
*AttachmentQuery
|
||||
selector
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the selector query.
|
||||
func (as *AttachmentSelect) Aggregate(fns ...AggregateFunc) *AttachmentSelect {
|
||||
as.fns = append(as.fns, fns...)
|
||||
return as
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (as *AttachmentSelect) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, as.ctx, "Select")
|
||||
if err := as.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
as.sql = as.AttachmentQuery.sqlQuery(ctx)
|
||||
return as.sqlScan(ctx, v)
|
||||
return scanWithInterceptors[*AttachmentQuery, *AttachmentSelect](ctx, as.AttachmentQuery, as, as.inters, v)
|
||||
}
|
||||
|
||||
func (as *AttachmentSelect) sqlScan(ctx context.Context, v any) error {
|
||||
func (as *AttachmentSelect) sqlScan(ctx context.Context, root *AttachmentQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx)
|
||||
aggregation := make([]string, 0, len(as.fns))
|
||||
for _, fn := range as.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
switch n := len(*as.selector.flds); {
|
||||
case n == 0 && len(aggregation) > 0:
|
||||
selector.Select(aggregation...)
|
||||
case n != 0 && len(aggregation) > 0:
|
||||
selector.AppendSelect(aggregation...)
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := as.sql.Query()
|
||||
query, args := selector.Query()
|
||||
if err := as.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -92,41 +92,8 @@ func (au *AttachmentUpdate) ClearDocument() *AttachmentUpdate {
|
||||
|
||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||
func (au *AttachmentUpdate) Save(ctx context.Context) (int, error) {
|
||||
var (
|
||||
err error
|
||||
affected int
|
||||
)
|
||||
au.defaults()
|
||||
if len(au.hooks) == 0 {
|
||||
if err = au.check(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
affected, err = au.sqlSave(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*AttachmentMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
if err = au.check(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
au.mutation = mutation
|
||||
affected, err = au.sqlSave(ctx)
|
||||
mutation.done = true
|
||||
return affected, err
|
||||
})
|
||||
for i := len(au.hooks) - 1; i >= 0; i-- {
|
||||
if au.hooks[i] == nil {
|
||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = au.hooks[i](mut)
|
||||
}
|
||||
if _, err := mut.Mutate(ctx, au.mutation); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return affected, err
|
||||
return withHooks[int, AttachmentMutation](ctx, au.sqlSave, au.mutation, au.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
@@ -176,16 +143,10 @@ func (au *AttachmentUpdate) check() error {
|
||||
}
|
||||
|
||||
func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
_spec := &sqlgraph.UpdateSpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: attachment.Table,
|
||||
Columns: attachment.Columns,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
},
|
||||
if err := au.check(); err != nil {
|
||||
return n, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(attachment.Table, attachment.Columns, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
|
||||
if ps := au.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
@@ -194,18 +155,10 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
}
|
||||
}
|
||||
if value, ok := au.mutation.UpdatedAt(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: attachment.FieldUpdatedAt,
|
||||
})
|
||||
_spec.SetField(attachment.FieldUpdatedAt, field.TypeTime, value)
|
||||
}
|
||||
if value, ok := au.mutation.GetType(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeEnum,
|
||||
Value: value,
|
||||
Column: attachment.FieldType,
|
||||
})
|
||||
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
||||
}
|
||||
if au.mutation.ItemCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
@@ -215,10 +168,7 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{attachment.ItemColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: item.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(item.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
@@ -231,10 +181,7 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{attachment.ItemColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: item.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(item.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -250,10 +197,7 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{attachment.DocumentColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: document.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
@@ -266,10 +210,7 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{attachment.DocumentColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: document.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -285,6 +226,7 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
au.mutation.done = true
|
||||
return n, nil
|
||||
}
|
||||
|
||||
@@ -355,6 +297,12 @@ func (auo *AttachmentUpdateOne) ClearDocument() *AttachmentUpdateOne {
|
||||
return auo
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the AttachmentUpdate builder.
|
||||
func (auo *AttachmentUpdateOne) Where(ps ...predicate.Attachment) *AttachmentUpdateOne {
|
||||
auo.mutation.Where(ps...)
|
||||
return auo
|
||||
}
|
||||
|
||||
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||
// The default is selecting all fields defined in the entity schema.
|
||||
func (auo *AttachmentUpdateOne) Select(field string, fields ...string) *AttachmentUpdateOne {
|
||||
@@ -364,47 +312,8 @@ func (auo *AttachmentUpdateOne) Select(field string, fields ...string) *Attachme
|
||||
|
||||
// Save executes the query and returns the updated Attachment entity.
|
||||
func (auo *AttachmentUpdateOne) Save(ctx context.Context) (*Attachment, error) {
|
||||
var (
|
||||
err error
|
||||
node *Attachment
|
||||
)
|
||||
auo.defaults()
|
||||
if len(auo.hooks) == 0 {
|
||||
if err = auo.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, err = auo.sqlSave(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*AttachmentMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
if err = auo.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
auo.mutation = mutation
|
||||
node, err = auo.sqlSave(ctx)
|
||||
mutation.done = true
|
||||
return node, err
|
||||
})
|
||||
for i := len(auo.hooks) - 1; i >= 0; i-- {
|
||||
if auo.hooks[i] == nil {
|
||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = auo.hooks[i](mut)
|
||||
}
|
||||
v, err := mut.Mutate(ctx, auo.mutation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nv, ok := v.(*Attachment)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected node type %T returned from AttachmentMutation", v)
|
||||
}
|
||||
node = nv
|
||||
}
|
||||
return node, err
|
||||
return withHooks[*Attachment, AttachmentMutation](ctx, auo.sqlSave, auo.mutation, auo.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
@@ -454,16 +363,10 @@ func (auo *AttachmentUpdateOne) check() error {
|
||||
}
|
||||
|
||||
func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment, err error) {
|
||||
_spec := &sqlgraph.UpdateSpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: attachment.Table,
|
||||
Columns: attachment.Columns,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
},
|
||||
if err := auo.check(); err != nil {
|
||||
return _node, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(attachment.Table, attachment.Columns, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
|
||||
id, ok := auo.mutation.ID()
|
||||
if !ok {
|
||||
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Attachment.id" for update`)}
|
||||
@@ -489,18 +392,10 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
||||
}
|
||||
}
|
||||
if value, ok := auo.mutation.UpdatedAt(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: attachment.FieldUpdatedAt,
|
||||
})
|
||||
_spec.SetField(attachment.FieldUpdatedAt, field.TypeTime, value)
|
||||
}
|
||||
if value, ok := auo.mutation.GetType(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeEnum,
|
||||
Value: value,
|
||||
Column: attachment.FieldType,
|
||||
})
|
||||
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
||||
}
|
||||
if auo.mutation.ItemCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
@@ -510,10 +405,7 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
||||
Columns: []string{attachment.ItemColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: item.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(item.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
@@ -526,10 +418,7 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
||||
Columns: []string{attachment.ItemColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: item.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(item.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -545,10 +434,7 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
||||
Columns: []string{attachment.DocumentColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: document.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
@@ -561,10 +447,7 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
||||
Columns: []string{attachment.DocumentColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: document.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -583,5 +466,6 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
auo.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
135
backend/internal/data/ent/authroles.go
Normal file
135
backend/internal/data/ent/authroles.go
Normal file
@@ -0,0 +1,135 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||
)
|
||||
|
||||
// AuthRoles is the model entity for the AuthRoles schema.
|
||||
type AuthRoles struct {
|
||||
config `json:"-"`
|
||||
// ID of the ent.
|
||||
ID int `json:"id,omitempty"`
|
||||
// Role holds the value of the "role" field.
|
||||
Role authroles.Role `json:"role,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the AuthRolesQuery when eager-loading is set.
|
||||
Edges AuthRolesEdges `json:"edges"`
|
||||
auth_tokens_roles *uuid.UUID
|
||||
}
|
||||
|
||||
// AuthRolesEdges holds the relations/edges for other nodes in the graph.
|
||||
type AuthRolesEdges struct {
|
||||
// Token holds the value of the token edge.
|
||||
Token *AuthTokens `json:"token,omitempty"`
|
||||
// loadedTypes holds the information for reporting if a
|
||||
// type was loaded (or requested) in eager-loading or not.
|
||||
loadedTypes [1]bool
|
||||
}
|
||||
|
||||
// TokenOrErr returns the Token value or an error if the edge
|
||||
// was not loaded in eager-loading, or loaded but was not found.
|
||||
func (e AuthRolesEdges) TokenOrErr() (*AuthTokens, error) {
|
||||
if e.loadedTypes[0] {
|
||||
if e.Token == nil {
|
||||
// Edge was loaded but was not found.
|
||||
return nil, &NotFoundError{label: authtokens.Label}
|
||||
}
|
||||
return e.Token, nil
|
||||
}
|
||||
return nil, &NotLoadedError{edge: "token"}
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*AuthRoles) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case authroles.FieldID:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case authroles.FieldRole:
|
||||
values[i] = new(sql.NullString)
|
||||
case authroles.ForeignKeys[0]: // auth_tokens_roles
|
||||
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected column %q for type AuthRoles", columns[i])
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||
// to the AuthRoles fields.
|
||||
func (ar *AuthRoles) assignValues(columns []string, values []any) error {
|
||||
if m, n := len(values), len(columns); m < n {
|
||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||
}
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case authroles.FieldID:
|
||||
value, ok := values[i].(*sql.NullInt64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field id", value)
|
||||
}
|
||||
ar.ID = int(value.Int64)
|
||||
case authroles.FieldRole:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field role", values[i])
|
||||
} else if value.Valid {
|
||||
ar.Role = authroles.Role(value.String)
|
||||
}
|
||||
case authroles.ForeignKeys[0]:
|
||||
if value, ok := values[i].(*sql.NullScanner); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field auth_tokens_roles", values[i])
|
||||
} else if value.Valid {
|
||||
ar.auth_tokens_roles = new(uuid.UUID)
|
||||
*ar.auth_tokens_roles = *value.S.(*uuid.UUID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// QueryToken queries the "token" edge of the AuthRoles entity.
|
||||
func (ar *AuthRoles) QueryToken() *AuthTokensQuery {
|
||||
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 NewAuthRolesClient(ar.config).UpdateOne(ar)
|
||||
}
|
||||
|
||||
// Unwrap unwraps the AuthRoles entity that was returned from a transaction after it was closed,
|
||||
// so that all future queries will be executed through the driver which created the transaction.
|
||||
func (ar *AuthRoles) Unwrap() *AuthRoles {
|
||||
_tx, ok := ar.config.driver.(*txDriver)
|
||||
if !ok {
|
||||
panic("ent: AuthRoles is not a transactional entity")
|
||||
}
|
||||
ar.config.driver = _tx.drv
|
||||
return ar
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer.
|
||||
func (ar *AuthRoles) String() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString("AuthRoles(")
|
||||
builder.WriteString(fmt.Sprintf("id=%v, ", ar.ID))
|
||||
builder.WriteString("role=")
|
||||
builder.WriteString(fmt.Sprintf("%v", ar.Role))
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// AuthRolesSlice is a parsable slice of AuthRoles.
|
||||
type AuthRolesSlice []*AuthRoles
|
||||
81
backend/internal/data/ent/authroles/authroles.go
Normal file
81
backend/internal/data/ent/authroles/authroles.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package authroles
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
// Label holds the string label denoting the authroles type in the database.
|
||||
Label = "auth_roles"
|
||||
// FieldID holds the string denoting the id field in the database.
|
||||
FieldID = "id"
|
||||
// FieldRole holds the string denoting the role field in the database.
|
||||
FieldRole = "role"
|
||||
// EdgeToken holds the string denoting the token edge name in mutations.
|
||||
EdgeToken = "token"
|
||||
// Table holds the table name of the authroles in the database.
|
||||
Table = "auth_roles"
|
||||
// TokenTable is the table that holds the token relation/edge.
|
||||
TokenTable = "auth_roles"
|
||||
// TokenInverseTable is the table name for the AuthTokens entity.
|
||||
// It exists in this package in order to avoid circular dependency with the "authtokens" package.
|
||||
TokenInverseTable = "auth_tokens"
|
||||
// TokenColumn is the table column denoting the token relation/edge.
|
||||
TokenColumn = "auth_tokens_roles"
|
||||
)
|
||||
|
||||
// Columns holds all SQL columns for authroles fields.
|
||||
var Columns = []string{
|
||||
FieldID,
|
||||
FieldRole,
|
||||
}
|
||||
|
||||
// ForeignKeys holds the SQL foreign-keys that are owned by the "auth_roles"
|
||||
// table and are not defined as standalone fields in the schema.
|
||||
var ForeignKeys = []string{
|
||||
"auth_tokens_roles",
|
||||
}
|
||||
|
||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||
func ValidColumn(column string) bool {
|
||||
for i := range Columns {
|
||||
if column == Columns[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for i := range ForeignKeys {
|
||||
if column == ForeignKeys[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Role defines the type for the "role" enum field.
|
||||
type Role string
|
||||
|
||||
// RoleUser is the default value of the Role enum.
|
||||
const DefaultRole = RoleUser
|
||||
|
||||
// Role values.
|
||||
const (
|
||||
RoleAdmin Role = "admin"
|
||||
RoleUser Role = "user"
|
||||
RoleAttachments Role = "attachments"
|
||||
)
|
||||
|
||||
func (r Role) String() string {
|
||||
return string(r)
|
||||
}
|
||||
|
||||
// RoleValidator is a validator for the "role" field enum values. It is called by the builders before save.
|
||||
func RoleValidator(r Role) error {
|
||||
switch r {
|
||||
case RoleAdmin, RoleUser, RoleAttachments:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("authroles: invalid enum value for role field: %q", r)
|
||||
}
|
||||
}
|
||||
133
backend/internal/data/ent/authroles/where.go
Normal file
133
backend/internal/data/ent/authroles/where.go
Normal file
@@ -0,0 +1,133 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package authroles
|
||||
|
||||
import (
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||
)
|
||||
|
||||
// ID filters vertices based on their ID field.
|
||||
func ID(id int) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDEQ applies the EQ predicate on the ID field.
|
||||
func IDEQ(id int) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDNEQ applies the NEQ predicate on the ID field.
|
||||
func IDNEQ(id int) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldNEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDIn applies the In predicate on the ID field.
|
||||
func IDIn(ids ...int) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDNotIn applies the NotIn predicate on the ID field.
|
||||
func IDNotIn(ids ...int) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldNotIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDGT applies the GT predicate on the ID field.
|
||||
func IDGT(id int) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldGT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDGTE applies the GTE predicate on the ID field.
|
||||
func IDGTE(id int) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldGTE(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLT applies the LT predicate on the ID field.
|
||||
func IDLT(id int) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldLT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLTE applies the LTE predicate on the ID field.
|
||||
func IDLTE(id int) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldLTE(FieldID, id))
|
||||
}
|
||||
|
||||
// RoleEQ applies the EQ predicate on the "role" field.
|
||||
func RoleEQ(v Role) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldEQ(FieldRole, v))
|
||||
}
|
||||
|
||||
// RoleNEQ applies the NEQ predicate on the "role" field.
|
||||
func RoleNEQ(v Role) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldNEQ(FieldRole, v))
|
||||
}
|
||||
|
||||
// RoleIn applies the In predicate on the "role" field.
|
||||
func RoleIn(vs ...Role) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldIn(FieldRole, vs...))
|
||||
}
|
||||
|
||||
// RoleNotIn applies the NotIn predicate on the "role" field.
|
||||
func RoleNotIn(vs ...Role) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(sql.FieldNotIn(FieldRole, vs...))
|
||||
}
|
||||
|
||||
// HasToken applies the HasEdge predicate on the "token" edge.
|
||||
func HasToken() predicate.AuthRoles {
|
||||
return predicate.AuthRoles(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2O, true, TokenTable, TokenColumn),
|
||||
)
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
})
|
||||
}
|
||||
|
||||
// HasTokenWith applies the HasEdge predicate on the "token" edge with a given conditions (other predicates).
|
||||
func HasTokenWith(preds ...predicate.AuthTokens) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(TokenInverseTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2O, true, TokenTable, TokenColumn),
|
||||
)
|
||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||
for _, p := range preds {
|
||||
p(s)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// And groups predicates with the AND operator between them.
|
||||
func And(predicates ...predicate.AuthRoles) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(func(s *sql.Selector) {
|
||||
s1 := s.Clone().SetP(nil)
|
||||
for _, p := range predicates {
|
||||
p(s1)
|
||||
}
|
||||
s.Where(s1.P())
|
||||
})
|
||||
}
|
||||
|
||||
// Or groups predicates with the OR operator between them.
|
||||
func Or(predicates ...predicate.AuthRoles) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(func(s *sql.Selector) {
|
||||
s1 := s.Clone().SetP(nil)
|
||||
for i, p := range predicates {
|
||||
if i > 0 {
|
||||
s1.Or()
|
||||
}
|
||||
p(s1)
|
||||
}
|
||||
s.Where(s1.P())
|
||||
})
|
||||
}
|
||||
|
||||
// Not applies the not operator on the given predicate.
|
||||
func Not(p predicate.AuthRoles) predicate.AuthRoles {
|
||||
return predicate.AuthRoles(func(s *sql.Selector) {
|
||||
p(s.Not())
|
||||
})
|
||||
}
|
||||
240
backend/internal/data/ent/authroles_create.go
Normal file
240
backend/internal/data/ent/authroles_create.go
Normal file
@@ -0,0 +1,240 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||
)
|
||||
|
||||
// AuthRolesCreate is the builder for creating a AuthRoles entity.
|
||||
type AuthRolesCreate struct {
|
||||
config
|
||||
mutation *AuthRolesMutation
|
||||
hooks []Hook
|
||||
}
|
||||
|
||||
// SetRole sets the "role" field.
|
||||
func (arc *AuthRolesCreate) SetRole(a authroles.Role) *AuthRolesCreate {
|
||||
arc.mutation.SetRole(a)
|
||||
return arc
|
||||
}
|
||||
|
||||
// SetNillableRole sets the "role" field if the given value is not nil.
|
||||
func (arc *AuthRolesCreate) SetNillableRole(a *authroles.Role) *AuthRolesCreate {
|
||||
if a != nil {
|
||||
arc.SetRole(*a)
|
||||
}
|
||||
return arc
|
||||
}
|
||||
|
||||
// SetTokenID sets the "token" edge to the AuthTokens entity by ID.
|
||||
func (arc *AuthRolesCreate) SetTokenID(id uuid.UUID) *AuthRolesCreate {
|
||||
arc.mutation.SetTokenID(id)
|
||||
return arc
|
||||
}
|
||||
|
||||
// SetNillableTokenID sets the "token" edge to the AuthTokens entity by ID if the given value is not nil.
|
||||
func (arc *AuthRolesCreate) SetNillableTokenID(id *uuid.UUID) *AuthRolesCreate {
|
||||
if id != nil {
|
||||
arc = arc.SetTokenID(*id)
|
||||
}
|
||||
return arc
|
||||
}
|
||||
|
||||
// SetToken sets the "token" edge to the AuthTokens entity.
|
||||
func (arc *AuthRolesCreate) SetToken(a *AuthTokens) *AuthRolesCreate {
|
||||
return arc.SetTokenID(a.ID)
|
||||
}
|
||||
|
||||
// Mutation returns the AuthRolesMutation object of the builder.
|
||||
func (arc *AuthRolesCreate) Mutation() *AuthRolesMutation {
|
||||
return arc.mutation
|
||||
}
|
||||
|
||||
// Save creates the AuthRoles in the database.
|
||||
func (arc *AuthRolesCreate) Save(ctx context.Context) (*AuthRoles, error) {
|
||||
arc.defaults()
|
||||
return withHooks[*AuthRoles, AuthRolesMutation](ctx, arc.sqlSave, arc.mutation, arc.hooks)
|
||||
}
|
||||
|
||||
// SaveX calls Save and panics if Save returns an error.
|
||||
func (arc *AuthRolesCreate) SaveX(ctx context.Context) *AuthRoles {
|
||||
v, err := arc.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (arc *AuthRolesCreate) Exec(ctx context.Context) error {
|
||||
_, err := arc.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (arc *AuthRolesCreate) ExecX(ctx context.Context) {
|
||||
if err := arc.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// defaults sets the default values of the builder before save.
|
||||
func (arc *AuthRolesCreate) defaults() {
|
||||
if _, ok := arc.mutation.Role(); !ok {
|
||||
v := authroles.DefaultRole
|
||||
arc.mutation.SetRole(v)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (arc *AuthRolesCreate) check() error {
|
||||
if _, ok := arc.mutation.Role(); !ok {
|
||||
return &ValidationError{Name: "role", err: errors.New(`ent: missing required field "AuthRoles.role"`)}
|
||||
}
|
||||
if v, ok := arc.mutation.Role(); ok {
|
||||
if err := authroles.RoleValidator(v); err != nil {
|
||||
return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "AuthRoles.role": %w`, err)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (arc *AuthRolesCreate) sqlSave(ctx context.Context) (*AuthRoles, error) {
|
||||
if err := arc.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_node, _spec := arc.createSpec()
|
||||
if err := sqlgraph.CreateNode(ctx, arc.driver, _spec); err != nil {
|
||||
if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
id := _spec.ID.Value.(int64)
|
||||
_node.ID = int(id)
|
||||
arc.mutation.id = &_node.ID
|
||||
arc.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
func (arc *AuthRolesCreate) createSpec() (*AuthRoles, *sqlgraph.CreateSpec) {
|
||||
var (
|
||||
_node = &AuthRoles{config: arc.config}
|
||||
_spec = sqlgraph.NewCreateSpec(authroles.Table, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
|
||||
)
|
||||
if value, ok := arc.mutation.Role(); ok {
|
||||
_spec.SetField(authroles.FieldRole, field.TypeEnum, value)
|
||||
_node.Role = value
|
||||
}
|
||||
if nodes := arc.mutation.TokenIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2O,
|
||||
Inverse: true,
|
||||
Table: authroles.TokenTable,
|
||||
Columns: []string{authroles.TokenColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_node.auth_tokens_roles = &nodes[0]
|
||||
_spec.Edges = append(_spec.Edges, edge)
|
||||
}
|
||||
return _node, _spec
|
||||
}
|
||||
|
||||
// AuthRolesCreateBulk is the builder for creating many AuthRoles entities in bulk.
|
||||
type AuthRolesCreateBulk struct {
|
||||
config
|
||||
builders []*AuthRolesCreate
|
||||
}
|
||||
|
||||
// Save creates the AuthRoles entities in the database.
|
||||
func (arcb *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) {
|
||||
specs := make([]*sqlgraph.CreateSpec, len(arcb.builders))
|
||||
nodes := make([]*AuthRoles, len(arcb.builders))
|
||||
mutators := make([]Mutator, len(arcb.builders))
|
||||
for i := range arcb.builders {
|
||||
func(i int, root context.Context) {
|
||||
builder := arcb.builders[i]
|
||||
builder.defaults()
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*AuthRolesMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
if err := builder.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
builder.mutation = mutation
|
||||
nodes[i], specs[i] = builder.createSpec()
|
||||
var err error
|
||||
if i < len(mutators)-1 {
|
||||
_, err = mutators[i+1].Mutate(root, arcb.builders[i+1].mutation)
|
||||
} else {
|
||||
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
|
||||
// Invoke the actual operation on the latest mutation in the chain.
|
||||
if err = sqlgraph.BatchCreate(ctx, arcb.driver, spec); err != nil {
|
||||
if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mutation.id = &nodes[i].ID
|
||||
if specs[i].ID.Value != nil {
|
||||
id := specs[i].ID.Value.(int64)
|
||||
nodes[i].ID = int(id)
|
||||
}
|
||||
mutation.done = true
|
||||
return nodes[i], nil
|
||||
})
|
||||
for i := len(builder.hooks) - 1; i >= 0; i-- {
|
||||
mut = builder.hooks[i](mut)
|
||||
}
|
||||
mutators[i] = mut
|
||||
}(i, ctx)
|
||||
}
|
||||
if len(mutators) > 0 {
|
||||
if _, err := mutators[0].Mutate(ctx, arcb.builders[0].mutation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
func (arcb *AuthRolesCreateBulk) SaveX(ctx context.Context) []*AuthRoles {
|
||||
v, err := arcb.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (arcb *AuthRolesCreateBulk) Exec(ctx context.Context) error {
|
||||
_, err := arcb.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (arcb *AuthRolesCreateBulk) ExecX(ctx context.Context) {
|
||||
if err := arcb.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
88
backend/internal/data/ent/authroles_delete.go
Normal file
88
backend/internal/data/ent/authroles_delete.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||
)
|
||||
|
||||
// AuthRolesDelete is the builder for deleting a AuthRoles entity.
|
||||
type AuthRolesDelete struct {
|
||||
config
|
||||
hooks []Hook
|
||||
mutation *AuthRolesMutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the AuthRolesDelete builder.
|
||||
func (ard *AuthRolesDelete) Where(ps ...predicate.AuthRoles) *AuthRolesDelete {
|
||||
ard.mutation.Where(ps...)
|
||||
return ard
|
||||
}
|
||||
|
||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||
func (ard *AuthRolesDelete) Exec(ctx context.Context) (int, error) {
|
||||
return withHooks[int, AuthRolesMutation](ctx, ard.sqlExec, ard.mutation, ard.hooks)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (ard *AuthRolesDelete) ExecX(ctx context.Context) int {
|
||||
n, err := ard.Exec(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (ard *AuthRolesDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
_spec := sqlgraph.NewDeleteSpec(authroles.Table, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
|
||||
if ps := ard.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
affected, err := sqlgraph.DeleteNodes(ctx, ard.driver, _spec)
|
||||
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
ard.mutation.done = true
|
||||
return affected, err
|
||||
}
|
||||
|
||||
// AuthRolesDeleteOne is the builder for deleting a single AuthRoles entity.
|
||||
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)
|
||||
switch {
|
||||
case err != nil:
|
||||
return err
|
||||
case n == 0:
|
||||
return &NotFoundError{authroles.Label}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (ardo *AuthRolesDeleteOne) ExecX(ctx context.Context) {
|
||||
if err := ardo.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
614
backend/internal/data/ent/authroles_query.go
Normal file
614
backend/internal/data/ent/authroles_query.go
Normal file
@@ -0,0 +1,614 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||
)
|
||||
|
||||
// AuthRolesQuery is the builder for querying AuthRoles entities.
|
||||
type AuthRolesQuery struct {
|
||||
config
|
||||
ctx *QueryContext
|
||||
order []OrderFunc
|
||||
inters []Interceptor
|
||||
predicates []predicate.AuthRoles
|
||||
withToken *AuthTokensQuery
|
||||
withFKs bool
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
path func(context.Context) (*sql.Selector, error)
|
||||
}
|
||||
|
||||
// Where adds a new predicate for the AuthRolesQuery builder.
|
||||
func (arq *AuthRolesQuery) Where(ps ...predicate.AuthRoles) *AuthRolesQuery {
|
||||
arq.predicates = append(arq.predicates, ps...)
|
||||
return arq
|
||||
}
|
||||
|
||||
// Limit the number of records to be returned by this query.
|
||||
func (arq *AuthRolesQuery) Limit(limit int) *AuthRolesQuery {
|
||||
arq.ctx.Limit = &limit
|
||||
return arq
|
||||
}
|
||||
|
||||
// Offset to start from.
|
||||
func (arq *AuthRolesQuery) Offset(offset int) *AuthRolesQuery {
|
||||
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.ctx.Unique = &unique
|
||||
return arq
|
||||
}
|
||||
|
||||
// Order specifies how the records should be ordered.
|
||||
func (arq *AuthRolesQuery) Order(o ...OrderFunc) *AuthRolesQuery {
|
||||
arq.order = append(arq.order, o...)
|
||||
return arq
|
||||
}
|
||||
|
||||
// QueryToken chains the current query on the "token" edge.
|
||||
func (arq *AuthRolesQuery) QueryToken() *AuthTokensQuery {
|
||||
query := (&AuthTokensClient{config: arq.config}).Query()
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := arq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selector := arq.sqlQuery(ctx)
|
||||
if err := selector.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(authroles.Table, authroles.FieldID, selector),
|
||||
sqlgraph.To(authtokens.Table, authtokens.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2O, true, authroles.TokenTable, authroles.TokenColumn),
|
||||
)
|
||||
fromU = sqlgraph.SetNeighbors(arq.driver.Dialect(), step)
|
||||
return fromU, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// 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(setContextOp(ctx, arq.ctx, "First"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return nil, &NotFoundError{authroles.Label}
|
||||
}
|
||||
return nodes[0], nil
|
||||
}
|
||||
|
||||
// FirstX is like First, but panics if an error occurs.
|
||||
func (arq *AuthRolesQuery) FirstX(ctx context.Context) *AuthRoles {
|
||||
node, err := arq.First(ctx)
|
||||
if err != nil && !IsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// FirstID returns the first AuthRoles ID from the query.
|
||||
// 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(setContextOp(ctx, arq.ctx, "FirstID")); err != nil {
|
||||
return
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
err = &NotFoundError{authroles.Label}
|
||||
return
|
||||
}
|
||||
return ids[0], nil
|
||||
}
|
||||
|
||||
// FirstIDX is like FirstID, but panics if an error occurs.
|
||||
func (arq *AuthRolesQuery) FirstIDX(ctx context.Context) int {
|
||||
id, err := arq.FirstID(ctx)
|
||||
if err != nil && !IsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// Only returns a single AuthRoles entity found by the query, ensuring it only returns one.
|
||||
// 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(setContextOp(ctx, arq.ctx, "Only"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch len(nodes) {
|
||||
case 1:
|
||||
return nodes[0], nil
|
||||
case 0:
|
||||
return nil, &NotFoundError{authroles.Label}
|
||||
default:
|
||||
return nil, &NotSingularError{authroles.Label}
|
||||
}
|
||||
}
|
||||
|
||||
// OnlyX is like Only, but panics if an error occurs.
|
||||
func (arq *AuthRolesQuery) OnlyX(ctx context.Context) *AuthRoles {
|
||||
node, err := arq.Only(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// OnlyID is like Only, but returns the only AuthRoles ID in the query.
|
||||
// Returns a *NotSingularError when more than one AuthRoles ID is found.
|
||||
// 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(setContextOp(ctx, arq.ctx, "OnlyID")); err != nil {
|
||||
return
|
||||
}
|
||||
switch len(ids) {
|
||||
case 1:
|
||||
id = ids[0]
|
||||
case 0:
|
||||
err = &NotFoundError{authroles.Label}
|
||||
default:
|
||||
err = &NotSingularError{authroles.Label}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OnlyIDX is like OnlyID, but panics if an error occurs.
|
||||
func (arq *AuthRolesQuery) OnlyIDX(ctx context.Context) int {
|
||||
id, err := arq.OnlyID(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// All executes the query and returns a list of AuthRolesSlice.
|
||||
func (arq *AuthRolesQuery) All(ctx context.Context) ([]*AuthRoles, error) {
|
||||
ctx = setContextOp(ctx, arq.ctx, "All")
|
||||
if err := arq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
qr := querierAll[[]*AuthRoles, *AuthRolesQuery]()
|
||||
return withInterceptors[[]*AuthRoles](ctx, arq, qr, arq.inters)
|
||||
}
|
||||
|
||||
// AllX is like All, but panics if an error occurs.
|
||||
func (arq *AuthRolesQuery) AllX(ctx context.Context) []*AuthRoles {
|
||||
nodes, err := arq.All(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
// IDs executes the query and returns a list of AuthRoles IDs.
|
||||
func (arq *AuthRolesQuery) IDs(ctx context.Context) (ids []int, err error) {
|
||||
if arq.ctx.Unique == nil && arq.path != nil {
|
||||
arq.Unique(true)
|
||||
}
|
||||
ctx = setContextOp(ctx, arq.ctx, "IDs")
|
||||
if err = arq.Select(authroles.FieldID).Scan(ctx, &ids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// IDsX is like IDs, but panics if an error occurs.
|
||||
func (arq *AuthRolesQuery) IDsX(ctx context.Context) []int {
|
||||
ids, err := arq.IDs(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// Count returns the count of the given query.
|
||||
func (arq *AuthRolesQuery) Count(ctx context.Context) (int, error) {
|
||||
ctx = setContextOp(ctx, arq.ctx, "Count")
|
||||
if err := arq.prepareQuery(ctx); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return withInterceptors[int](ctx, arq, querierCount[*AuthRolesQuery](), arq.inters)
|
||||
}
|
||||
|
||||
// CountX is like Count, but panics if an error occurs.
|
||||
func (arq *AuthRolesQuery) CountX(ctx context.Context) int {
|
||||
count, err := arq.Count(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// Exist returns true if the query has elements in the graph.
|
||||
func (arq *AuthRolesQuery) Exist(ctx context.Context) (bool, error) {
|
||||
ctx = setContextOp(ctx, arq.ctx, "Exist")
|
||||
switch _, err := arq.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExistX is like Exist, but panics if an error occurs.
|
||||
func (arq *AuthRolesQuery) ExistX(ctx context.Context) bool {
|
||||
exist, err := arq.Exist(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return exist
|
||||
}
|
||||
|
||||
// Clone returns a duplicate of the AuthRolesQuery builder, including all associated steps. It can be
|
||||
// used to prepare common query builders and use them differently after the clone is made.
|
||||
func (arq *AuthRolesQuery) Clone() *AuthRolesQuery {
|
||||
if arq == nil {
|
||||
return nil
|
||||
}
|
||||
return &AuthRolesQuery{
|
||||
config: arq.config,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
// WithToken tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "token" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (arq *AuthRolesQuery) WithToken(opts ...func(*AuthTokensQuery)) *AuthRolesQuery {
|
||||
query := (&AuthTokensClient{config: arq.config}).Query()
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
arq.withToken = query
|
||||
return arq
|
||||
}
|
||||
|
||||
// GroupBy is used to group vertices by one or more fields/columns.
|
||||
// It is often used with aggregate functions, like: count, max, mean, min, sum.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var v []struct {
|
||||
// Role authroles.Role `json:"role,omitempty"`
|
||||
// Count int `json:"count,omitempty"`
|
||||
// }
|
||||
//
|
||||
// client.AuthRoles.Query().
|
||||
// GroupBy(authroles.FieldRole).
|
||||
// Aggregate(ent.Count()).
|
||||
// Scan(ctx, &v)
|
||||
func (arq *AuthRolesQuery) GroupBy(field string, fields ...string) *AuthRolesGroupBy {
|
||||
arq.ctx.Fields = append([]string{field}, fields...)
|
||||
grbuild := &AuthRolesGroupBy{build: arq}
|
||||
grbuild.flds = &arq.ctx.Fields
|
||||
grbuild.label = authroles.Label
|
||||
grbuild.scan = grbuild.Scan
|
||||
return grbuild
|
||||
}
|
||||
|
||||
// Select allows the selection one or more fields/columns for the given query,
|
||||
// instead of selecting all fields in the entity.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var v []struct {
|
||||
// Role authroles.Role `json:"role,omitempty"`
|
||||
// }
|
||||
//
|
||||
// client.AuthRoles.Query().
|
||||
// Select(authroles.FieldRole).
|
||||
// Scan(ctx, &v)
|
||||
func (arq *AuthRolesQuery) Select(fields ...string) *AuthRolesSelect {
|
||||
arq.ctx.Fields = append(arq.ctx.Fields, fields...)
|
||||
sbuild := &AuthRolesSelect{AuthRolesQuery: arq}
|
||||
sbuild.label = authroles.Label
|
||||
sbuild.flds, sbuild.scan = &arq.ctx.Fields, sbuild.Scan
|
||||
return sbuild
|
||||
}
|
||||
|
||||
// Aggregate returns a AuthRolesSelect configured with the given aggregations.
|
||||
func (arq *AuthRolesQuery) Aggregate(fns ...AggregateFunc) *AuthRolesSelect {
|
||||
return arq.Select().Aggregate(fns...)
|
||||
}
|
||||
|
||||
func (arq *AuthRolesQuery) prepareQuery(ctx context.Context) error {
|
||||
for _, inter := range arq.inters {
|
||||
if inter == nil {
|
||||
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
|
||||
}
|
||||
if trv, ok := inter.(Traverser); ok {
|
||||
if err := trv.Traverse(ctx, arq); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, f := range arq.ctx.Fields {
|
||||
if !authroles.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
}
|
||||
if arq.path != nil {
|
||||
prev, err := arq.path(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
arq.sql = prev
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (arq *AuthRolesQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*AuthRoles, error) {
|
||||
var (
|
||||
nodes = []*AuthRoles{}
|
||||
withFKs = arq.withFKs
|
||||
_spec = arq.querySpec()
|
||||
loadedTypes = [1]bool{
|
||||
arq.withToken != nil,
|
||||
}
|
||||
)
|
||||
if arq.withToken != nil {
|
||||
withFKs = true
|
||||
}
|
||||
if withFKs {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, authroles.ForeignKeys...)
|
||||
}
|
||||
_spec.ScanValues = func(columns []string) ([]any, error) {
|
||||
return (*AuthRoles).scanValues(nil, columns)
|
||||
}
|
||||
_spec.Assign = func(columns []string, values []any) error {
|
||||
node := &AuthRoles{config: arq.config}
|
||||
nodes = append(nodes, node)
|
||||
node.Edges.loadedTypes = loadedTypes
|
||||
return node.assignValues(columns, values)
|
||||
}
|
||||
for i := range hooks {
|
||||
hooks[i](ctx, _spec)
|
||||
}
|
||||
if err := sqlgraph.QueryNodes(ctx, arq.driver, _spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return nodes, nil
|
||||
}
|
||||
if query := arq.withToken; query != nil {
|
||||
if err := arq.loadToken(ctx, query, nodes, nil,
|
||||
func(n *AuthRoles, e *AuthTokens) { n.Edges.Token = e }); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (arq *AuthRolesQuery) loadToken(ctx context.Context, query *AuthTokensQuery, nodes []*AuthRoles, init func(*AuthRoles), assign func(*AuthRoles, *AuthTokens)) error {
|
||||
ids := make([]uuid.UUID, 0, len(nodes))
|
||||
nodeids := make(map[uuid.UUID][]*AuthRoles)
|
||||
for i := range nodes {
|
||||
if nodes[i].auth_tokens_roles == nil {
|
||||
continue
|
||||
}
|
||||
fk := *nodes[i].auth_tokens_roles
|
||||
if _, ok := nodeids[fk]; !ok {
|
||||
ids = append(ids, fk)
|
||||
}
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
nodes, ok := nodeids[n.ID]
|
||||
if !ok {
|
||||
return fmt.Errorf(`unexpected foreign-key "auth_tokens_roles" returned %v`, n.ID)
|
||||
}
|
||||
for i := range nodes {
|
||||
assign(nodes[i], n)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (arq *AuthRolesQuery) sqlCount(ctx context.Context) (int, error) {
|
||||
_spec := arq.querySpec()
|
||||
_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)
|
||||
}
|
||||
|
||||
func (arq *AuthRolesQuery) querySpec() *sqlgraph.QuerySpec {
|
||||
_spec := sqlgraph.NewQuerySpec(authroles.Table, authroles.Columns, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
|
||||
_spec.From = arq.sql
|
||||
if unique := arq.ctx.Unique; unique != nil {
|
||||
_spec.Unique = *unique
|
||||
} else if arq.path != nil {
|
||||
_spec.Unique = true
|
||||
}
|
||||
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 {
|
||||
if fields[i] != authroles.FieldID {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
if ps := arq.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if limit := arq.ctx.Limit; limit != nil {
|
||||
_spec.Limit = *limit
|
||||
}
|
||||
if offset := arq.ctx.Offset; offset != nil {
|
||||
_spec.Offset = *offset
|
||||
}
|
||||
if ps := arq.order; len(ps) > 0 {
|
||||
_spec.Order = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
return _spec
|
||||
}
|
||||
|
||||
func (arq *AuthRolesQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||
builder := sql.Dialect(arq.driver.Dialect())
|
||||
t1 := builder.Table(authroles.Table)
|
||||
columns := arq.ctx.Fields
|
||||
if len(columns) == 0 {
|
||||
columns = authroles.Columns
|
||||
}
|
||||
selector := builder.Select(t1.Columns(columns...)...).From(t1)
|
||||
if arq.sql != nil {
|
||||
selector = arq.sql
|
||||
selector.Select(selector.Columns(columns...)...)
|
||||
}
|
||||
if arq.ctx.Unique != nil && *arq.ctx.Unique {
|
||||
selector.Distinct()
|
||||
}
|
||||
for _, p := range arq.predicates {
|
||||
p(selector)
|
||||
}
|
||||
for _, p := range arq.order {
|
||||
p(selector)
|
||||
}
|
||||
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.ctx.Limit; limit != nil {
|
||||
selector.Limit(*limit)
|
||||
}
|
||||
return selector
|
||||
}
|
||||
|
||||
// AuthRolesGroupBy is the group-by builder for AuthRoles entities.
|
||||
type AuthRolesGroupBy struct {
|
||||
selector
|
||||
build *AuthRolesQuery
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the group-by query.
|
||||
func (argb *AuthRolesGroupBy) Aggregate(fns ...AggregateFunc) *AuthRolesGroupBy {
|
||||
argb.fns = append(argb.fns, fns...)
|
||||
return argb
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (argb *AuthRolesGroupBy) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, argb.build.ctx, "GroupBy")
|
||||
if err := argb.build.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanWithInterceptors[*AuthRolesQuery, *AuthRolesGroupBy](ctx, argb.build, argb, argb.build.inters, v)
|
||||
}
|
||||
|
||||
func (argb *AuthRolesGroupBy) sqlScan(ctx context.Context, root *AuthRolesQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx).Select()
|
||||
aggregation := make([]string, 0, len(argb.fns))
|
||||
for _, fn := range argb.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
if len(selector.SelectedColumns()) == 0 {
|
||||
columns := make([]string, 0, len(*argb.flds)+len(argb.fns))
|
||||
for _, f := range *argb.flds {
|
||||
columns = append(columns, selector.C(f))
|
||||
}
|
||||
columns = append(columns, aggregation...)
|
||||
selector.Select(columns...)
|
||||
}
|
||||
selector.GroupBy(selector.Columns(*argb.flds...)...)
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := argb.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
// AuthRolesSelect is the builder for selecting fields of AuthRoles entities.
|
||||
type AuthRolesSelect struct {
|
||||
*AuthRolesQuery
|
||||
selector
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the selector query.
|
||||
func (ars *AuthRolesSelect) Aggregate(fns ...AggregateFunc) *AuthRolesSelect {
|
||||
ars.fns = append(ars.fns, fns...)
|
||||
return ars
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (ars *AuthRolesSelect) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, ars.ctx, "Select")
|
||||
if err := ars.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanWithInterceptors[*AuthRolesQuery, *AuthRolesSelect](ctx, ars.AuthRolesQuery, ars, ars.inters, v)
|
||||
}
|
||||
|
||||
func (ars *AuthRolesSelect) sqlScan(ctx context.Context, root *AuthRolesQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx)
|
||||
aggregation := make([]string, 0, len(ars.fns))
|
||||
for _, fn := range ars.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
switch n := len(*ars.selector.flds); {
|
||||
case n == 0 && len(aggregation) > 0:
|
||||
selector.Select(aggregation...)
|
||||
case n != 0 && len(aggregation) > 0:
|
||||
selector.AppendSelect(aggregation...)
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := ars.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
345
backend/internal/data/ent/authroles_update.go
Normal file
345
backend/internal/data/ent/authroles_update.go
Normal file
@@ -0,0 +1,345 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||
)
|
||||
|
||||
// AuthRolesUpdate is the builder for updating AuthRoles entities.
|
||||
type AuthRolesUpdate struct {
|
||||
config
|
||||
hooks []Hook
|
||||
mutation *AuthRolesMutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the AuthRolesUpdate builder.
|
||||
func (aru *AuthRolesUpdate) Where(ps ...predicate.AuthRoles) *AuthRolesUpdate {
|
||||
aru.mutation.Where(ps...)
|
||||
return aru
|
||||
}
|
||||
|
||||
// SetRole sets the "role" field.
|
||||
func (aru *AuthRolesUpdate) SetRole(a authroles.Role) *AuthRolesUpdate {
|
||||
aru.mutation.SetRole(a)
|
||||
return aru
|
||||
}
|
||||
|
||||
// SetNillableRole sets the "role" field if the given value is not nil.
|
||||
func (aru *AuthRolesUpdate) SetNillableRole(a *authroles.Role) *AuthRolesUpdate {
|
||||
if a != nil {
|
||||
aru.SetRole(*a)
|
||||
}
|
||||
return aru
|
||||
}
|
||||
|
||||
// SetTokenID sets the "token" edge to the AuthTokens entity by ID.
|
||||
func (aru *AuthRolesUpdate) SetTokenID(id uuid.UUID) *AuthRolesUpdate {
|
||||
aru.mutation.SetTokenID(id)
|
||||
return aru
|
||||
}
|
||||
|
||||
// SetNillableTokenID sets the "token" edge to the AuthTokens entity by ID if the given value is not nil.
|
||||
func (aru *AuthRolesUpdate) SetNillableTokenID(id *uuid.UUID) *AuthRolesUpdate {
|
||||
if id != nil {
|
||||
aru = aru.SetTokenID(*id)
|
||||
}
|
||||
return aru
|
||||
}
|
||||
|
||||
// SetToken sets the "token" edge to the AuthTokens entity.
|
||||
func (aru *AuthRolesUpdate) SetToken(a *AuthTokens) *AuthRolesUpdate {
|
||||
return aru.SetTokenID(a.ID)
|
||||
}
|
||||
|
||||
// Mutation returns the AuthRolesMutation object of the builder.
|
||||
func (aru *AuthRolesUpdate) Mutation() *AuthRolesMutation {
|
||||
return aru.mutation
|
||||
}
|
||||
|
||||
// ClearToken clears the "token" edge to the AuthTokens entity.
|
||||
func (aru *AuthRolesUpdate) ClearToken() *AuthRolesUpdate {
|
||||
aru.mutation.ClearToken()
|
||||
return aru
|
||||
}
|
||||
|
||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||
func (aru *AuthRolesUpdate) Save(ctx context.Context) (int, error) {
|
||||
return withHooks[int, AuthRolesMutation](ctx, aru.sqlSave, aru.mutation, aru.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
func (aru *AuthRolesUpdate) SaveX(ctx context.Context) int {
|
||||
affected, err := aru.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return affected
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (aru *AuthRolesUpdate) Exec(ctx context.Context) error {
|
||||
_, err := aru.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (aru *AuthRolesUpdate) ExecX(ctx context.Context) {
|
||||
if err := aru.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (aru *AuthRolesUpdate) check() error {
|
||||
if v, ok := aru.mutation.Role(); ok {
|
||||
if err := authroles.RoleValidator(v); err != nil {
|
||||
return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "AuthRoles.role": %w`, err)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (aru *AuthRolesUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
if err := aru.check(); err != nil {
|
||||
return n, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(authroles.Table, authroles.Columns, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
|
||||
if ps := aru.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if value, ok := aru.mutation.Role(); ok {
|
||||
_spec.SetField(authroles.FieldRole, field.TypeEnum, value)
|
||||
}
|
||||
if aru.mutation.TokenCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2O,
|
||||
Inverse: true,
|
||||
Table: authroles.TokenTable,
|
||||
Columns: []string{authroles.TokenColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := aru.mutation.TokenIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2O,
|
||||
Inverse: true,
|
||||
Table: authroles.TokenTable,
|
||||
Columns: []string{authroles.TokenColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||
}
|
||||
if n, err = sqlgraph.UpdateNodes(ctx, aru.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{authroles.Label}
|
||||
} else if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
aru.mutation.done = true
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// AuthRolesUpdateOne is the builder for updating a single AuthRoles entity.
|
||||
type AuthRolesUpdateOne struct {
|
||||
config
|
||||
fields []string
|
||||
hooks []Hook
|
||||
mutation *AuthRolesMutation
|
||||
}
|
||||
|
||||
// SetRole sets the "role" field.
|
||||
func (aruo *AuthRolesUpdateOne) SetRole(a authroles.Role) *AuthRolesUpdateOne {
|
||||
aruo.mutation.SetRole(a)
|
||||
return aruo
|
||||
}
|
||||
|
||||
// SetNillableRole sets the "role" field if the given value is not nil.
|
||||
func (aruo *AuthRolesUpdateOne) SetNillableRole(a *authroles.Role) *AuthRolesUpdateOne {
|
||||
if a != nil {
|
||||
aruo.SetRole(*a)
|
||||
}
|
||||
return aruo
|
||||
}
|
||||
|
||||
// SetTokenID sets the "token" edge to the AuthTokens entity by ID.
|
||||
func (aruo *AuthRolesUpdateOne) SetTokenID(id uuid.UUID) *AuthRolesUpdateOne {
|
||||
aruo.mutation.SetTokenID(id)
|
||||
return aruo
|
||||
}
|
||||
|
||||
// SetNillableTokenID sets the "token" edge to the AuthTokens entity by ID if the given value is not nil.
|
||||
func (aruo *AuthRolesUpdateOne) SetNillableTokenID(id *uuid.UUID) *AuthRolesUpdateOne {
|
||||
if id != nil {
|
||||
aruo = aruo.SetTokenID(*id)
|
||||
}
|
||||
return aruo
|
||||
}
|
||||
|
||||
// SetToken sets the "token" edge to the AuthTokens entity.
|
||||
func (aruo *AuthRolesUpdateOne) SetToken(a *AuthTokens) *AuthRolesUpdateOne {
|
||||
return aruo.SetTokenID(a.ID)
|
||||
}
|
||||
|
||||
// Mutation returns the AuthRolesMutation object of the builder.
|
||||
func (aruo *AuthRolesUpdateOne) Mutation() *AuthRolesMutation {
|
||||
return aruo.mutation
|
||||
}
|
||||
|
||||
// ClearToken clears the "token" edge to the AuthTokens entity.
|
||||
func (aruo *AuthRolesUpdateOne) ClearToken() *AuthRolesUpdateOne {
|
||||
aruo.mutation.ClearToken()
|
||||
return aruo
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the AuthRolesUpdate builder.
|
||||
func (aruo *AuthRolesUpdateOne) Where(ps ...predicate.AuthRoles) *AuthRolesUpdateOne {
|
||||
aruo.mutation.Where(ps...)
|
||||
return aruo
|
||||
}
|
||||
|
||||
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||
// The default is selecting all fields defined in the entity schema.
|
||||
func (aruo *AuthRolesUpdateOne) Select(field string, fields ...string) *AuthRolesUpdateOne {
|
||||
aruo.fields = append([]string{field}, fields...)
|
||||
return aruo
|
||||
}
|
||||
|
||||
// Save executes the query and returns the updated AuthRoles entity.
|
||||
func (aruo *AuthRolesUpdateOne) Save(ctx context.Context) (*AuthRoles, error) {
|
||||
return withHooks[*AuthRoles, AuthRolesMutation](ctx, aruo.sqlSave, aruo.mutation, aruo.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
func (aruo *AuthRolesUpdateOne) SaveX(ctx context.Context) *AuthRoles {
|
||||
node, err := aruo.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// Exec executes the query on the entity.
|
||||
func (aruo *AuthRolesUpdateOne) Exec(ctx context.Context) error {
|
||||
_, err := aruo.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (aruo *AuthRolesUpdateOne) ExecX(ctx context.Context) {
|
||||
if err := aruo.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (aruo *AuthRolesUpdateOne) check() error {
|
||||
if v, ok := aruo.mutation.Role(); ok {
|
||||
if err := authroles.RoleValidator(v); err != nil {
|
||||
return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "AuthRoles.role": %w`, err)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (aruo *AuthRolesUpdateOne) sqlSave(ctx context.Context) (_node *AuthRoles, err error) {
|
||||
if err := aruo.check(); err != nil {
|
||||
return _node, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(authroles.Table, authroles.Columns, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
|
||||
id, ok := aruo.mutation.ID()
|
||||
if !ok {
|
||||
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "AuthRoles.id" for update`)}
|
||||
}
|
||||
_spec.Node.ID.Value = id
|
||||
if fields := aruo.fields; len(fields) > 0 {
|
||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, authroles.FieldID)
|
||||
for _, f := range fields {
|
||||
if !authroles.ValidColumn(f) {
|
||||
return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
if f != authroles.FieldID {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ps := aruo.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if value, ok := aruo.mutation.Role(); ok {
|
||||
_spec.SetField(authroles.FieldRole, field.TypeEnum, value)
|
||||
}
|
||||
if aruo.mutation.TokenCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2O,
|
||||
Inverse: true,
|
||||
Table: authroles.TokenTable,
|
||||
Columns: []string{authroles.TokenColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := aruo.mutation.TokenIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2O,
|
||||
Inverse: true,
|
||||
Table: authroles.TokenTable,
|
||||
Columns: []string{authroles.TokenColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||
}
|
||||
_node = &AuthRoles{config: aruo.config}
|
||||
_spec.Assign = _node.assignValues
|
||||
_spec.ScanValues = _node.scanValues
|
||||
if err = sqlgraph.UpdateNode(ctx, aruo.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{authroles.Label}
|
||||
} else if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
aruo.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
||||
)
|
||||
@@ -36,9 +37,11 @@ type AuthTokens struct {
|
||||
type AuthTokensEdges struct {
|
||||
// User holds the value of the user edge.
|
||||
User *User `json:"user,omitempty"`
|
||||
// Roles holds the value of the roles edge.
|
||||
Roles *AuthRoles `json:"roles,omitempty"`
|
||||
// loadedTypes holds the information for reporting if a
|
||||
// type was loaded (or requested) in eager-loading or not.
|
||||
loadedTypes [1]bool
|
||||
loadedTypes [2]bool
|
||||
}
|
||||
|
||||
// UserOrErr returns the User value or an error if the edge
|
||||
@@ -54,6 +57,19 @@ func (e AuthTokensEdges) UserOrErr() (*User, error) {
|
||||
return nil, &NotLoadedError{edge: "user"}
|
||||
}
|
||||
|
||||
// RolesOrErr returns the Roles value or an error if the edge
|
||||
// was not loaded in eager-loading, or loaded but was not found.
|
||||
func (e AuthTokensEdges) RolesOrErr() (*AuthRoles, error) {
|
||||
if e.loadedTypes[1] {
|
||||
if e.Roles == nil {
|
||||
// Edge was loaded but was not found.
|
||||
return nil, &NotFoundError{label: authroles.Label}
|
||||
}
|
||||
return e.Roles, nil
|
||||
}
|
||||
return nil, &NotLoadedError{edge: "roles"}
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*AuthTokens) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
@@ -126,14 +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 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,
|
||||
@@ -169,9 +190,3 @@ func (at *AuthTokens) String() string {
|
||||
|
||||
// AuthTokensSlice is a parsable slice of AuthTokens.
|
||||
type AuthTokensSlice []*AuthTokens
|
||||
|
||||
func (at AuthTokensSlice) config(cfg config) {
|
||||
for _i := range at {
|
||||
at[_i].config = cfg
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ const (
|
||||
FieldExpiresAt = "expires_at"
|
||||
// EdgeUser holds the string denoting the user edge name in mutations.
|
||||
EdgeUser = "user"
|
||||
// EdgeRoles holds the string denoting the roles edge name in mutations.
|
||||
EdgeRoles = "roles"
|
||||
// Table holds the table name of the authtokens in the database.
|
||||
Table = "auth_tokens"
|
||||
// UserTable is the table that holds the user relation/edge.
|
||||
@@ -32,6 +34,13 @@ const (
|
||||
UserInverseTable = "users"
|
||||
// UserColumn is the table column denoting the user relation/edge.
|
||||
UserColumn = "user_auth_tokens"
|
||||
// RolesTable is the table that holds the roles relation/edge.
|
||||
RolesTable = "auth_roles"
|
||||
// RolesInverseTable is the table name for the AuthRoles entity.
|
||||
// It exists in this package in order to avoid circular dependency with the "authroles" package.
|
||||
RolesInverseTable = "auth_roles"
|
||||
// RolesColumn is the table column denoting the roles relation/edge.
|
||||
RolesColumn = "auth_tokens_roles"
|
||||
)
|
||||
|
||||
// Columns holds all SQL columns for authtokens fields.
|
||||
|
||||
@@ -13,357 +13,227 @@ import (
|
||||
|
||||
// ID filters vertices based on their ID field.
|
||||
func ID(id uuid.UUID) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDEQ applies the EQ predicate on the ID field.
|
||||
func IDEQ(id uuid.UUID) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDNEQ applies the NEQ predicate on the ID field.
|
||||
func IDNEQ(id uuid.UUID) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldNEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDIn applies the In predicate on the ID field.
|
||||
func IDIn(ids ...uuid.UUID) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
v := make([]any, len(ids))
|
||||
for i := range v {
|
||||
v[i] = ids[i]
|
||||
}
|
||||
s.Where(sql.In(s.C(FieldID), v...))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDNotIn applies the NotIn predicate on the ID field.
|
||||
func IDNotIn(ids ...uuid.UUID) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
v := make([]any, len(ids))
|
||||
for i := range v {
|
||||
v[i] = ids[i]
|
||||
}
|
||||
s.Where(sql.NotIn(s.C(FieldID), v...))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldNotIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDGT applies the GT predicate on the ID field.
|
||||
func IDGT(id uuid.UUID) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldGT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDGTE applies the GTE predicate on the ID field.
|
||||
func IDGTE(id uuid.UUID) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldGTE(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLT applies the LT predicate on the ID field.
|
||||
func IDLT(id uuid.UUID) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldLT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLTE applies the LTE predicate on the ID field.
|
||||
func IDLTE(id uuid.UUID) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldLTE(FieldID, id))
|
||||
}
|
||||
|
||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||
func CreatedAt(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
||||
func UpdatedAt(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// Token applies equality check predicate on the "token" field. It's identical to TokenEQ.
|
||||
func Token(v []byte) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldToken), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldEQ(FieldToken, v))
|
||||
}
|
||||
|
||||
// ExpiresAt applies equality check predicate on the "expires_at" field. It's identical to ExpiresAtEQ.
|
||||
func ExpiresAt(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldExpiresAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldEQ(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||
func CreatedAtNEQ(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldNEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||
func CreatedAtIn(vs ...time.Time) predicate.AuthTokens {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldCreatedAt), v...))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||
func CreatedAtNotIn(vs ...time.Time) predicate.AuthTokens {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldCreatedAt), v...))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||
func CreatedAtGT(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldGT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||
func CreatedAtGTE(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldGTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||
func CreatedAtLT(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldLT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||
func CreatedAtLTE(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldLTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
||||
func UpdatedAtEQ(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
||||
func UpdatedAtNEQ(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldNEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
||||
func UpdatedAtIn(vs ...time.Time) predicate.AuthTokens {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldUpdatedAt), v...))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldIn(FieldUpdatedAt, vs...))
|
||||
}
|
||||
|
||||
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
||||
func UpdatedAtNotIn(vs ...time.Time) predicate.AuthTokens {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldUpdatedAt), v...))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldNotIn(FieldUpdatedAt, vs...))
|
||||
}
|
||||
|
||||
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
||||
func UpdatedAtGT(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldGT(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
||||
func UpdatedAtGTE(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldGTE(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
||||
func UpdatedAtLT(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldLT(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
||||
func UpdatedAtLTE(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldLTE(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// TokenEQ applies the EQ predicate on the "token" field.
|
||||
func TokenEQ(v []byte) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldToken), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldEQ(FieldToken, v))
|
||||
}
|
||||
|
||||
// TokenNEQ applies the NEQ predicate on the "token" field.
|
||||
func TokenNEQ(v []byte) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldToken), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldNEQ(FieldToken, v))
|
||||
}
|
||||
|
||||
// TokenIn applies the In predicate on the "token" field.
|
||||
func TokenIn(vs ...[]byte) predicate.AuthTokens {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldToken), v...))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldIn(FieldToken, vs...))
|
||||
}
|
||||
|
||||
// TokenNotIn applies the NotIn predicate on the "token" field.
|
||||
func TokenNotIn(vs ...[]byte) predicate.AuthTokens {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldToken), v...))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldNotIn(FieldToken, vs...))
|
||||
}
|
||||
|
||||
// TokenGT applies the GT predicate on the "token" field.
|
||||
func TokenGT(v []byte) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldToken), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldGT(FieldToken, v))
|
||||
}
|
||||
|
||||
// TokenGTE applies the GTE predicate on the "token" field.
|
||||
func TokenGTE(v []byte) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldToken), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldGTE(FieldToken, v))
|
||||
}
|
||||
|
||||
// TokenLT applies the LT predicate on the "token" field.
|
||||
func TokenLT(v []byte) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldToken), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldLT(FieldToken, v))
|
||||
}
|
||||
|
||||
// TokenLTE applies the LTE predicate on the "token" field.
|
||||
func TokenLTE(v []byte) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldToken), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldLTE(FieldToken, v))
|
||||
}
|
||||
|
||||
// ExpiresAtEQ applies the EQ predicate on the "expires_at" field.
|
||||
func ExpiresAtEQ(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldExpiresAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldEQ(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtNEQ applies the NEQ predicate on the "expires_at" field.
|
||||
func ExpiresAtNEQ(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldExpiresAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldNEQ(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtIn applies the In predicate on the "expires_at" field.
|
||||
func ExpiresAtIn(vs ...time.Time) predicate.AuthTokens {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldExpiresAt), v...))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldIn(FieldExpiresAt, vs...))
|
||||
}
|
||||
|
||||
// ExpiresAtNotIn applies the NotIn predicate on the "expires_at" field.
|
||||
func ExpiresAtNotIn(vs ...time.Time) predicate.AuthTokens {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldExpiresAt), v...))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldNotIn(FieldExpiresAt, vs...))
|
||||
}
|
||||
|
||||
// ExpiresAtGT applies the GT predicate on the "expires_at" field.
|
||||
func ExpiresAtGT(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldExpiresAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldGT(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtGTE applies the GTE predicate on the "expires_at" field.
|
||||
func ExpiresAtGTE(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldExpiresAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldGTE(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtLT applies the LT predicate on the "expires_at" field.
|
||||
func ExpiresAtLT(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldExpiresAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldLT(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtLTE applies the LTE predicate on the "expires_at" field.
|
||||
func ExpiresAtLTE(v time.Time) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldExpiresAt), v))
|
||||
})
|
||||
return predicate.AuthTokens(sql.FieldLTE(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// HasUser applies the HasEdge predicate on the "user" edge.
|
||||
@@ -371,7 +241,6 @@ func HasUser() predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(UserTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
|
||||
)
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
@@ -394,6 +263,33 @@ func HasUserWith(preds ...predicate.User) predicate.AuthTokens {
|
||||
})
|
||||
}
|
||||
|
||||
// HasRoles applies the HasEdge predicate on the "roles" edge.
|
||||
func HasRoles() predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2O, false, RolesTable, RolesColumn),
|
||||
)
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
})
|
||||
}
|
||||
|
||||
// HasRolesWith applies the HasEdge predicate on the "roles" edge with a given conditions (other predicates).
|
||||
func HasRolesWith(preds ...predicate.AuthRoles) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(RolesInverseTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2O, false, RolesTable, RolesColumn),
|
||||
)
|
||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||
for _, p := range preds {
|
||||
p(s)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// And groups predicates with the AND operator between them.
|
||||
func And(predicates ...predicate.AuthTokens) predicate.AuthTokens {
|
||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
||||
)
|
||||
@@ -103,6 +104,25 @@ func (atc *AuthTokensCreate) SetUser(u *User) *AuthTokensCreate {
|
||||
return atc.SetUserID(u.ID)
|
||||
}
|
||||
|
||||
// SetRolesID sets the "roles" edge to the AuthRoles entity by ID.
|
||||
func (atc *AuthTokensCreate) SetRolesID(id int) *AuthTokensCreate {
|
||||
atc.mutation.SetRolesID(id)
|
||||
return atc
|
||||
}
|
||||
|
||||
// SetNillableRolesID sets the "roles" edge to the AuthRoles entity by ID if the given value is not nil.
|
||||
func (atc *AuthTokensCreate) SetNillableRolesID(id *int) *AuthTokensCreate {
|
||||
if id != nil {
|
||||
atc = atc.SetRolesID(*id)
|
||||
}
|
||||
return atc
|
||||
}
|
||||
|
||||
// SetRoles sets the "roles" edge to the AuthRoles entity.
|
||||
func (atc *AuthTokensCreate) SetRoles(a *AuthRoles) *AuthTokensCreate {
|
||||
return atc.SetRolesID(a.ID)
|
||||
}
|
||||
|
||||
// Mutation returns the AuthTokensMutation object of the builder.
|
||||
func (atc *AuthTokensCreate) Mutation() *AuthTokensMutation {
|
||||
return atc.mutation
|
||||
@@ -110,50 +130,8 @@ func (atc *AuthTokensCreate) Mutation() *AuthTokensMutation {
|
||||
|
||||
// Save creates the AuthTokens in the database.
|
||||
func (atc *AuthTokensCreate) Save(ctx context.Context) (*AuthTokens, error) {
|
||||
var (
|
||||
err error
|
||||
node *AuthTokens
|
||||
)
|
||||
atc.defaults()
|
||||
if len(atc.hooks) == 0 {
|
||||
if err = atc.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, err = atc.sqlSave(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*AuthTokensMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
if err = atc.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
atc.mutation = mutation
|
||||
if node, err = atc.sqlSave(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mutation.id = &node.ID
|
||||
mutation.done = true
|
||||
return node, err
|
||||
})
|
||||
for i := len(atc.hooks) - 1; i >= 0; i-- {
|
||||
if atc.hooks[i] == nil {
|
||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = atc.hooks[i](mut)
|
||||
}
|
||||
v, err := mut.Mutate(ctx, atc.mutation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nv, ok := v.(*AuthTokens)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected node type %T returned from AuthTokensMutation", v)
|
||||
}
|
||||
node = nv
|
||||
}
|
||||
return node, err
|
||||
return withHooks[*AuthTokens, AuthTokensMutation](ctx, atc.sqlSave, atc.mutation, atc.hooks)
|
||||
}
|
||||
|
||||
// SaveX calls Save and panics if Save returns an error.
|
||||
@@ -216,6 +194,9 @@ func (atc *AuthTokensCreate) check() error {
|
||||
}
|
||||
|
||||
func (atc *AuthTokensCreate) sqlSave(ctx context.Context) (*AuthTokens, error) {
|
||||
if err := atc.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_node, _spec := atc.createSpec()
|
||||
if err := sqlgraph.CreateNode(ctx, atc.driver, _spec); err != nil {
|
||||
if sqlgraph.IsConstraintError(err) {
|
||||
@@ -230,54 +211,34 @@ func (atc *AuthTokensCreate) sqlSave(ctx context.Context) (*AuthTokens, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
atc.mutation.id = &_node.ID
|
||||
atc.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
func (atc *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
|
||||
var (
|
||||
_node = &AuthTokens{config: atc.config}
|
||||
_spec = &sqlgraph.CreateSpec{
|
||||
Table: authtokens.Table,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: authtokens.FieldID,
|
||||
},
|
||||
}
|
||||
_spec = sqlgraph.NewCreateSpec(authtokens.Table, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
|
||||
)
|
||||
if id, ok := atc.mutation.ID(); ok {
|
||||
_node.ID = id
|
||||
_spec.ID.Value = &id
|
||||
}
|
||||
if value, ok := atc.mutation.CreatedAt(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: authtokens.FieldCreatedAt,
|
||||
})
|
||||
_spec.SetField(authtokens.FieldCreatedAt, field.TypeTime, value)
|
||||
_node.CreatedAt = value
|
||||
}
|
||||
if value, ok := atc.mutation.UpdatedAt(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: authtokens.FieldUpdatedAt,
|
||||
})
|
||||
_spec.SetField(authtokens.FieldUpdatedAt, field.TypeTime, value)
|
||||
_node.UpdatedAt = value
|
||||
}
|
||||
if value, ok := atc.mutation.Token(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeBytes,
|
||||
Value: value,
|
||||
Column: authtokens.FieldToken,
|
||||
})
|
||||
_spec.SetField(authtokens.FieldToken, field.TypeBytes, value)
|
||||
_node.Token = value
|
||||
}
|
||||
if value, ok := atc.mutation.ExpiresAt(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: authtokens.FieldExpiresAt,
|
||||
})
|
||||
_spec.SetField(authtokens.FieldExpiresAt, field.TypeTime, value)
|
||||
_node.ExpiresAt = value
|
||||
}
|
||||
if nodes := atc.mutation.UserIDs(); len(nodes) > 0 {
|
||||
@@ -288,10 +249,7 @@ func (atc *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
|
||||
Columns: []string{authtokens.UserColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: user.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -300,6 +258,22 @@ func (atc *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
|
||||
_node.user_auth_tokens = &nodes[0]
|
||||
_spec.Edges = append(_spec.Edges, edge)
|
||||
}
|
||||
if nodes := atc.mutation.RolesIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2O,
|
||||
Inverse: false,
|
||||
Table: authtokens.RolesTable,
|
||||
Columns: []string{authtokens.RolesColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges = append(_spec.Edges, edge)
|
||||
}
|
||||
return _node, _spec
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
@@ -28,34 +27,7 @@ func (atd *AuthTokensDelete) Where(ps ...predicate.AuthTokens) *AuthTokensDelete
|
||||
|
||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||
func (atd *AuthTokensDelete) Exec(ctx context.Context) (int, error) {
|
||||
var (
|
||||
err error
|
||||
affected int
|
||||
)
|
||||
if len(atd.hooks) == 0 {
|
||||
affected, err = atd.sqlExec(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*AuthTokensMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
atd.mutation = mutation
|
||||
affected, err = atd.sqlExec(ctx)
|
||||
mutation.done = true
|
||||
return affected, err
|
||||
})
|
||||
for i := len(atd.hooks) - 1; i >= 0; i-- {
|
||||
if atd.hooks[i] == nil {
|
||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = atd.hooks[i](mut)
|
||||
}
|
||||
if _, err := mut.Mutate(ctx, atd.mutation); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return affected, err
|
||||
return withHooks[int, AuthTokensMutation](ctx, atd.sqlExec, atd.mutation, atd.hooks)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
@@ -68,15 +40,7 @@ func (atd *AuthTokensDelete) ExecX(ctx context.Context) int {
|
||||
}
|
||||
|
||||
func (atd *AuthTokensDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
_spec := &sqlgraph.DeleteSpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: authtokens.Table,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: authtokens.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
_spec := sqlgraph.NewDeleteSpec(authtokens.Table, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
|
||||
if ps := atd.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
@@ -88,6 +52,7 @@ func (atd *AuthTokensDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
atd.mutation.done = true
|
||||
return affected, err
|
||||
}
|
||||
|
||||
@@ -96,6 +61,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)
|
||||
@@ -111,5 +82,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
||||
@@ -19,13 +21,12 @@ 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
|
||||
withRoles *AuthRolesQuery
|
||||
withFKs bool
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
@@ -38,26 +39,26 @@ func (atq *AuthTokensQuery) Where(ps ...predicate.AuthTokens) *AuthTokensQuery {
|
||||
return atq
|
||||
}
|
||||
|
||||
// Limit adds a limit step to the query.
|
||||
// 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 adds an offset step to the query.
|
||||
// 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
|
||||
}
|
||||
|
||||
// Order adds an order step to the query.
|
||||
// Order specifies how the records should be ordered.
|
||||
func (atq *AuthTokensQuery) Order(o ...OrderFunc) *AuthTokensQuery {
|
||||
atq.order = append(atq.order, o...)
|
||||
return atq
|
||||
@@ -65,7 +66,7 @@ func (atq *AuthTokensQuery) Order(o ...OrderFunc) *AuthTokensQuery {
|
||||
|
||||
// QueryUser chains the current query on the "user" edge.
|
||||
func (atq *AuthTokensQuery) QueryUser() *UserQuery {
|
||||
query := &UserQuery{config: atq.config}
|
||||
query := (&UserClient{config: atq.config}).Query()
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := atq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
@@ -85,10 +86,32 @@ func (atq *AuthTokensQuery) QueryUser() *UserQuery {
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryRoles chains the current query on the "roles" edge.
|
||||
func (atq *AuthTokensQuery) QueryRoles() *AuthRolesQuery {
|
||||
query := (&AuthRolesClient{config: atq.config}).Query()
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := atq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selector := atq.sqlQuery(ctx)
|
||||
if err := selector.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(authtokens.Table, authtokens.FieldID, selector),
|
||||
sqlgraph.To(authroles.Table, authroles.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2O, false, authtokens.RolesTable, authtokens.RolesColumn),
|
||||
)
|
||||
fromU = sqlgraph.SetNeighbors(atq.driver.Dialect(), step)
|
||||
return fromU, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// 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(ctx)
|
||||
nodes, err := atq.Limit(1).All(setContextOp(ctx, atq.ctx, "First"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -111,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(ctx); err != nil {
|
||||
if ids, err = atq.Limit(1).IDs(setContextOp(ctx, atq.ctx, "FirstID")); err != nil {
|
||||
return
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
@@ -134,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(ctx)
|
||||
nodes, err := atq.Limit(2).All(setContextOp(ctx, atq.ctx, "Only"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -162,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(ctx); err != nil {
|
||||
if ids, err = atq.Limit(2).IDs(setContextOp(ctx, atq.ctx, "OnlyID")); err != nil {
|
||||
return
|
||||
}
|
||||
switch len(ids) {
|
||||
@@ -187,10 +210,12 @@ 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 = setContextOp(ctx, atq.ctx, "All")
|
||||
if err := atq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return atq.sqlAll(ctx)
|
||||
qr := querierAll[[]*AuthTokens, *AuthTokensQuery]()
|
||||
return withInterceptors[[]*AuthTokens](ctx, atq, qr, atq.inters)
|
||||
}
|
||||
|
||||
// AllX is like All, but panics if an error occurs.
|
||||
@@ -203,9 +228,12 @@ 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
|
||||
if err := atq.Select(authtokens.FieldID).Scan(ctx, &ids); err != nil {
|
||||
func (atq *AuthTokensQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
|
||||
if atq.ctx.Unique == nil && atq.path != nil {
|
||||
atq.Unique(true)
|
||||
}
|
||||
ctx = setContextOp(ctx, atq.ctx, "IDs")
|
||||
if err = atq.Select(authtokens.FieldID).Scan(ctx, &ids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
@@ -222,10 +250,11 @@ 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 = setContextOp(ctx, atq.ctx, "Count")
|
||||
if err := atq.prepareQuery(ctx); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return atq.sqlCount(ctx)
|
||||
return withInterceptors[int](ctx, atq, querierCount[*AuthTokensQuery](), atq.inters)
|
||||
}
|
||||
|
||||
// CountX is like Count, but panics if an error occurs.
|
||||
@@ -239,10 +268,15 @@ 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) {
|
||||
if err := atq.prepareQuery(ctx); err != nil {
|
||||
return false, err
|
||||
ctx = setContextOp(ctx, atq.ctx, "Exist")
|
||||
switch _, err := atq.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
return atq.sqlExist(ctx)
|
||||
}
|
||||
|
||||
// ExistX is like Exist, but panics if an error occurs.
|
||||
@@ -262,22 +296,22 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
// WithUser tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "user" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (atq *AuthTokensQuery) WithUser(opts ...func(*UserQuery)) *AuthTokensQuery {
|
||||
query := &UserQuery{config: atq.config}
|
||||
query := (&UserClient{config: atq.config}).Query()
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
@@ -285,6 +319,17 @@ func (atq *AuthTokensQuery) WithUser(opts ...func(*UserQuery)) *AuthTokensQuery
|
||||
return atq
|
||||
}
|
||||
|
||||
// WithRoles tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "roles" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (atq *AuthTokensQuery) WithRoles(opts ...func(*AuthRolesQuery)) *AuthTokensQuery {
|
||||
query := (&AuthRolesClient{config: atq.config}).Query()
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
atq.withRoles = query
|
||||
return atq
|
||||
}
|
||||
|
||||
// GroupBy is used to group vertices by one or more fields/columns.
|
||||
// It is often used with aggregate functions, like: count, max, mean, min, sum.
|
||||
//
|
||||
@@ -300,16 +345,11 @@ func (atq *AuthTokensQuery) WithUser(opts ...func(*UserQuery)) *AuthTokensQuery
|
||||
// Aggregate(ent.Count()).
|
||||
// Scan(ctx, &v)
|
||||
func (atq *AuthTokensQuery) GroupBy(field string, fields ...string) *AuthTokensGroupBy {
|
||||
grbuild := &AuthTokensGroupBy{config: atq.config}
|
||||
grbuild.fields = append([]string{field}, fields...)
|
||||
grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
|
||||
if err := atq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return atq.sqlQuery(ctx), nil
|
||||
}
|
||||
atq.ctx.Fields = append([]string{field}, fields...)
|
||||
grbuild := &AuthTokensGroupBy{build: atq}
|
||||
grbuild.flds = &atq.ctx.Fields
|
||||
grbuild.label = authtokens.Label
|
||||
grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
|
||||
grbuild.scan = grbuild.Scan
|
||||
return grbuild
|
||||
}
|
||||
|
||||
@@ -326,15 +366,30 @@ 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...)
|
||||
selbuild := &AuthTokensSelect{AuthTokensQuery: atq}
|
||||
selbuild.label = authtokens.Label
|
||||
selbuild.flds, selbuild.scan = &atq.fields, selbuild.Scan
|
||||
return selbuild
|
||||
atq.ctx.Fields = append(atq.ctx.Fields, fields...)
|
||||
sbuild := &AuthTokensSelect{AuthTokensQuery: atq}
|
||||
sbuild.label = authtokens.Label
|
||||
sbuild.flds, sbuild.scan = &atq.ctx.Fields, sbuild.Scan
|
||||
return sbuild
|
||||
}
|
||||
|
||||
// Aggregate returns a AuthTokensSelect configured with the given aggregations.
|
||||
func (atq *AuthTokensQuery) Aggregate(fns ...AggregateFunc) *AuthTokensSelect {
|
||||
return atq.Select().Aggregate(fns...)
|
||||
}
|
||||
|
||||
func (atq *AuthTokensQuery) prepareQuery(ctx context.Context) error {
|
||||
for _, f := range atq.fields {
|
||||
for _, inter := range atq.inters {
|
||||
if inter == nil {
|
||||
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
|
||||
}
|
||||
if trv, ok := inter.(Traverser); ok {
|
||||
if err := trv.Traverse(ctx, atq); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, f := range atq.ctx.Fields {
|
||||
if !authtokens.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
@@ -354,8 +409,9 @@ func (atq *AuthTokensQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*
|
||||
nodes = []*AuthTokens{}
|
||||
withFKs = atq.withFKs
|
||||
_spec = atq.querySpec()
|
||||
loadedTypes = [1]bool{
|
||||
loadedTypes = [2]bool{
|
||||
atq.withUser != nil,
|
||||
atq.withRoles != nil,
|
||||
}
|
||||
)
|
||||
if atq.withUser != nil {
|
||||
@@ -388,6 +444,12 @@ func (atq *AuthTokensQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if query := atq.withRoles; query != nil {
|
||||
if err := atq.loadRoles(ctx, query, nodes, nil,
|
||||
func(n *AuthTokens, e *AuthRoles) { n.Edges.Roles = e }); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
@@ -404,6 +466,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 {
|
||||
@@ -420,44 +485,53 @@ func (atq *AuthTokensQuery) loadUser(ctx context.Context, query *UserQuery, node
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (atq *AuthTokensQuery) loadRoles(ctx context.Context, query *AuthRolesQuery, nodes []*AuthTokens, init func(*AuthTokens), assign func(*AuthTokens, *AuthRoles)) error {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
nodeids := make(map[uuid.UUID]*AuthTokens)
|
||||
for i := range nodes {
|
||||
fks = append(fks, nodes[i].ID)
|
||||
nodeids[nodes[i].ID] = nodes[i]
|
||||
}
|
||||
query.withFKs = true
|
||||
query.Where(predicate.AuthRoles(func(s *sql.Selector) {
|
||||
s.Where(sql.InValues(authtokens.RolesColumn, fks...))
|
||||
}))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
fk := n.auth_tokens_roles
|
||||
if fk == nil {
|
||||
return fmt.Errorf(`foreign-key "auth_tokens_roles" is nil for node %v`, n.ID)
|
||||
}
|
||||
node, ok := nodeids[*fk]
|
||||
if !ok {
|
||||
return fmt.Errorf(`unexpected foreign-key "auth_tokens_roles" returned %v for node %v`, *fk, n.ID)
|
||||
}
|
||||
assign(node, n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func (atq *AuthTokensQuery) sqlExist(ctx context.Context) (bool, error) {
|
||||
switch _, err := atq.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (atq *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
|
||||
_spec := &sqlgraph.QuerySpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: authtokens.Table,
|
||||
Columns: authtokens.Columns,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: authtokens.FieldID,
|
||||
},
|
||||
},
|
||||
From: atq.sql,
|
||||
Unique: true,
|
||||
}
|
||||
if unique := atq.unique; unique != nil {
|
||||
_spec := sqlgraph.NewQuerySpec(authtokens.Table, authtokens.Columns, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
|
||||
_spec.From = atq.sql
|
||||
if unique := atq.ctx.Unique; unique != nil {
|
||||
_spec.Unique = *unique
|
||||
} else if atq.path != nil {
|
||||
_spec.Unique = true
|
||||
}
|
||||
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 {
|
||||
@@ -473,10 +547,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 {
|
||||
@@ -492,7 +566,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
|
||||
}
|
||||
@@ -501,7 +575,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 {
|
||||
@@ -510,12 +584,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
|
||||
@@ -523,13 +597,8 @@ func (atq *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||
|
||||
// AuthTokensGroupBy is the group-by builder for AuthTokens entities.
|
||||
type AuthTokensGroupBy struct {
|
||||
config
|
||||
selector
|
||||
fields []string
|
||||
fns []AggregateFunc
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
path func(context.Context) (*sql.Selector, error)
|
||||
build *AuthTokensQuery
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the group-by query.
|
||||
@@ -538,74 +607,77 @@ func (atgb *AuthTokensGroupBy) Aggregate(fns ...AggregateFunc) *AuthTokensGroupB
|
||||
return atgb
|
||||
}
|
||||
|
||||
// Scan applies the group-by query and scans the result into the given value.
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (atgb *AuthTokensGroupBy) Scan(ctx context.Context, v any) error {
|
||||
query, err := atgb.path(ctx)
|
||||
if err != nil {
|
||||
ctx = setContextOp(ctx, atgb.build.ctx, "GroupBy")
|
||||
if err := atgb.build.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
atgb.sql = query
|
||||
return atgb.sqlScan(ctx, v)
|
||||
return scanWithInterceptors[*AuthTokensQuery, *AuthTokensGroupBy](ctx, atgb.build, atgb, atgb.build.inters, v)
|
||||
}
|
||||
|
||||
func (atgb *AuthTokensGroupBy) sqlScan(ctx context.Context, v any) error {
|
||||
for _, f := range atgb.fields {
|
||||
if !authtokens.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("invalid field %q for group-by", f)}
|
||||
}
|
||||
}
|
||||
selector := atgb.sqlQuery()
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := atgb.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
func (atgb *AuthTokensGroupBy) sqlQuery() *sql.Selector {
|
||||
selector := atgb.sql.Select()
|
||||
func (atgb *AuthTokensGroupBy) sqlScan(ctx context.Context, root *AuthTokensQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx).Select()
|
||||
aggregation := make([]string, 0, len(atgb.fns))
|
||||
for _, fn := range atgb.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
// If no columns were selected in a custom aggregation function, the default
|
||||
// selection is the fields used for "group-by", and the aggregation functions.
|
||||
if len(selector.SelectedColumns()) == 0 {
|
||||
columns := make([]string, 0, len(atgb.fields)+len(atgb.fns))
|
||||
for _, f := range atgb.fields {
|
||||
columns := make([]string, 0, len(*atgb.flds)+len(atgb.fns))
|
||||
for _, f := range *atgb.flds {
|
||||
columns = append(columns, selector.C(f))
|
||||
}
|
||||
columns = append(columns, aggregation...)
|
||||
selector.Select(columns...)
|
||||
}
|
||||
return selector.GroupBy(selector.Columns(atgb.fields...)...)
|
||||
selector.GroupBy(selector.Columns(*atgb.flds...)...)
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := atgb.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
// AuthTokensSelect is the builder for selecting fields of AuthTokens entities.
|
||||
type AuthTokensSelect struct {
|
||||
*AuthTokensQuery
|
||||
selector
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the selector query.
|
||||
func (ats *AuthTokensSelect) Aggregate(fns ...AggregateFunc) *AuthTokensSelect {
|
||||
ats.fns = append(ats.fns, fns...)
|
||||
return ats
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (ats *AuthTokensSelect) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, ats.ctx, "Select")
|
||||
if err := ats.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
ats.sql = ats.AuthTokensQuery.sqlQuery(ctx)
|
||||
return ats.sqlScan(ctx, v)
|
||||
return scanWithInterceptors[*AuthTokensQuery, *AuthTokensSelect](ctx, ats.AuthTokensQuery, ats, ats.inters, v)
|
||||
}
|
||||
|
||||
func (ats *AuthTokensSelect) sqlScan(ctx context.Context, v any) error {
|
||||
func (ats *AuthTokensSelect) sqlScan(ctx context.Context, root *AuthTokensQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx)
|
||||
aggregation := make([]string, 0, len(ats.fns))
|
||||
for _, fn := range ats.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
switch n := len(*ats.selector.flds); {
|
||||
case n == 0 && len(aggregation) > 0:
|
||||
selector.Select(aggregation...)
|
||||
case n != 0 && len(aggregation) > 0:
|
||||
selector.AppendSelect(aggregation...)
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := ats.sql.Query()
|
||||
query, args := selector.Query()
|
||||
if err := ats.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
||||
@@ -75,6 +76,25 @@ func (atu *AuthTokensUpdate) SetUser(u *User) *AuthTokensUpdate {
|
||||
return atu.SetUserID(u.ID)
|
||||
}
|
||||
|
||||
// SetRolesID sets the "roles" edge to the AuthRoles entity by ID.
|
||||
func (atu *AuthTokensUpdate) SetRolesID(id int) *AuthTokensUpdate {
|
||||
atu.mutation.SetRolesID(id)
|
||||
return atu
|
||||
}
|
||||
|
||||
// SetNillableRolesID sets the "roles" edge to the AuthRoles entity by ID if the given value is not nil.
|
||||
func (atu *AuthTokensUpdate) SetNillableRolesID(id *int) *AuthTokensUpdate {
|
||||
if id != nil {
|
||||
atu = atu.SetRolesID(*id)
|
||||
}
|
||||
return atu
|
||||
}
|
||||
|
||||
// SetRoles sets the "roles" edge to the AuthRoles entity.
|
||||
func (atu *AuthTokensUpdate) SetRoles(a *AuthRoles) *AuthTokensUpdate {
|
||||
return atu.SetRolesID(a.ID)
|
||||
}
|
||||
|
||||
// Mutation returns the AuthTokensMutation object of the builder.
|
||||
func (atu *AuthTokensUpdate) Mutation() *AuthTokensMutation {
|
||||
return atu.mutation
|
||||
@@ -86,37 +106,16 @@ func (atu *AuthTokensUpdate) ClearUser() *AuthTokensUpdate {
|
||||
return atu
|
||||
}
|
||||
|
||||
// ClearRoles clears the "roles" edge to the AuthRoles entity.
|
||||
func (atu *AuthTokensUpdate) ClearRoles() *AuthTokensUpdate {
|
||||
atu.mutation.ClearRoles()
|
||||
return atu
|
||||
}
|
||||
|
||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||
func (atu *AuthTokensUpdate) Save(ctx context.Context) (int, error) {
|
||||
var (
|
||||
err error
|
||||
affected int
|
||||
)
|
||||
atu.defaults()
|
||||
if len(atu.hooks) == 0 {
|
||||
affected, err = atu.sqlSave(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*AuthTokensMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
atu.mutation = mutation
|
||||
affected, err = atu.sqlSave(ctx)
|
||||
mutation.done = true
|
||||
return affected, err
|
||||
})
|
||||
for i := len(atu.hooks) - 1; i >= 0; i-- {
|
||||
if atu.hooks[i] == nil {
|
||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = atu.hooks[i](mut)
|
||||
}
|
||||
if _, err := mut.Mutate(ctx, atu.mutation); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return affected, err
|
||||
return withHooks[int, AuthTokensMutation](ctx, atu.sqlSave, atu.mutation, atu.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
@@ -150,16 +149,7 @@ func (atu *AuthTokensUpdate) defaults() {
|
||||
}
|
||||
|
||||
func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
_spec := &sqlgraph.UpdateSpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: authtokens.Table,
|
||||
Columns: authtokens.Columns,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: authtokens.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(authtokens.Table, authtokens.Columns, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
|
||||
if ps := atu.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
@@ -168,25 +158,13 @@ func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
}
|
||||
}
|
||||
if value, ok := atu.mutation.UpdatedAt(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: authtokens.FieldUpdatedAt,
|
||||
})
|
||||
_spec.SetField(authtokens.FieldUpdatedAt, field.TypeTime, value)
|
||||
}
|
||||
if value, ok := atu.mutation.Token(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeBytes,
|
||||
Value: value,
|
||||
Column: authtokens.FieldToken,
|
||||
})
|
||||
_spec.SetField(authtokens.FieldToken, field.TypeBytes, value)
|
||||
}
|
||||
if value, ok := atu.mutation.ExpiresAt(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: authtokens.FieldExpiresAt,
|
||||
})
|
||||
_spec.SetField(authtokens.FieldExpiresAt, field.TypeTime, value)
|
||||
}
|
||||
if atu.mutation.UserCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
@@ -196,10 +174,7 @@ func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{authtokens.UserColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: user.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
@@ -212,10 +187,36 @@ func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{authtokens.UserColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: user.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||
}
|
||||
if atu.mutation.RolesCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2O,
|
||||
Inverse: false,
|
||||
Table: authtokens.RolesTable,
|
||||
Columns: []string{authtokens.RolesColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := atu.mutation.RolesIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2O,
|
||||
Inverse: false,
|
||||
Table: authtokens.RolesTable,
|
||||
Columns: []string{authtokens.RolesColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -231,6 +232,7 @@ func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
atu.mutation.done = true
|
||||
return n, nil
|
||||
}
|
||||
|
||||
@@ -287,6 +289,25 @@ func (atuo *AuthTokensUpdateOne) SetUser(u *User) *AuthTokensUpdateOne {
|
||||
return atuo.SetUserID(u.ID)
|
||||
}
|
||||
|
||||
// SetRolesID sets the "roles" edge to the AuthRoles entity by ID.
|
||||
func (atuo *AuthTokensUpdateOne) SetRolesID(id int) *AuthTokensUpdateOne {
|
||||
atuo.mutation.SetRolesID(id)
|
||||
return atuo
|
||||
}
|
||||
|
||||
// SetNillableRolesID sets the "roles" edge to the AuthRoles entity by ID if the given value is not nil.
|
||||
func (atuo *AuthTokensUpdateOne) SetNillableRolesID(id *int) *AuthTokensUpdateOne {
|
||||
if id != nil {
|
||||
atuo = atuo.SetRolesID(*id)
|
||||
}
|
||||
return atuo
|
||||
}
|
||||
|
||||
// SetRoles sets the "roles" edge to the AuthRoles entity.
|
||||
func (atuo *AuthTokensUpdateOne) SetRoles(a *AuthRoles) *AuthTokensUpdateOne {
|
||||
return atuo.SetRolesID(a.ID)
|
||||
}
|
||||
|
||||
// Mutation returns the AuthTokensMutation object of the builder.
|
||||
func (atuo *AuthTokensUpdateOne) Mutation() *AuthTokensMutation {
|
||||
return atuo.mutation
|
||||
@@ -298,6 +319,18 @@ func (atuo *AuthTokensUpdateOne) ClearUser() *AuthTokensUpdateOne {
|
||||
return atuo
|
||||
}
|
||||
|
||||
// ClearRoles clears the "roles" edge to the AuthRoles entity.
|
||||
func (atuo *AuthTokensUpdateOne) ClearRoles() *AuthTokensUpdateOne {
|
||||
atuo.mutation.ClearRoles()
|
||||
return atuo
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the AuthTokensUpdate builder.
|
||||
func (atuo *AuthTokensUpdateOne) Where(ps ...predicate.AuthTokens) *AuthTokensUpdateOne {
|
||||
atuo.mutation.Where(ps...)
|
||||
return atuo
|
||||
}
|
||||
|
||||
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||
// The default is selecting all fields defined in the entity schema.
|
||||
func (atuo *AuthTokensUpdateOne) Select(field string, fields ...string) *AuthTokensUpdateOne {
|
||||
@@ -307,41 +340,8 @@ func (atuo *AuthTokensUpdateOne) Select(field string, fields ...string) *AuthTok
|
||||
|
||||
// Save executes the query and returns the updated AuthTokens entity.
|
||||
func (atuo *AuthTokensUpdateOne) Save(ctx context.Context) (*AuthTokens, error) {
|
||||
var (
|
||||
err error
|
||||
node *AuthTokens
|
||||
)
|
||||
atuo.defaults()
|
||||
if len(atuo.hooks) == 0 {
|
||||
node, err = atuo.sqlSave(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*AuthTokensMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
atuo.mutation = mutation
|
||||
node, err = atuo.sqlSave(ctx)
|
||||
mutation.done = true
|
||||
return node, err
|
||||
})
|
||||
for i := len(atuo.hooks) - 1; i >= 0; i-- {
|
||||
if atuo.hooks[i] == nil {
|
||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = atuo.hooks[i](mut)
|
||||
}
|
||||
v, err := mut.Mutate(ctx, atuo.mutation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nv, ok := v.(*AuthTokens)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected node type %T returned from AuthTokensMutation", v)
|
||||
}
|
||||
node = nv
|
||||
}
|
||||
return node, err
|
||||
return withHooks[*AuthTokens, AuthTokensMutation](ctx, atuo.sqlSave, atuo.mutation, atuo.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
@@ -375,16 +375,7 @@ func (atuo *AuthTokensUpdateOne) defaults() {
|
||||
}
|
||||
|
||||
func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens, err error) {
|
||||
_spec := &sqlgraph.UpdateSpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: authtokens.Table,
|
||||
Columns: authtokens.Columns,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: authtokens.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(authtokens.Table, authtokens.Columns, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
|
||||
id, ok := atuo.mutation.ID()
|
||||
if !ok {
|
||||
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "AuthTokens.id" for update`)}
|
||||
@@ -410,25 +401,13 @@ func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens
|
||||
}
|
||||
}
|
||||
if value, ok := atuo.mutation.UpdatedAt(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: authtokens.FieldUpdatedAt,
|
||||
})
|
||||
_spec.SetField(authtokens.FieldUpdatedAt, field.TypeTime, value)
|
||||
}
|
||||
if value, ok := atuo.mutation.Token(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeBytes,
|
||||
Value: value,
|
||||
Column: authtokens.FieldToken,
|
||||
})
|
||||
_spec.SetField(authtokens.FieldToken, field.TypeBytes, value)
|
||||
}
|
||||
if value, ok := atuo.mutation.ExpiresAt(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: authtokens.FieldExpiresAt,
|
||||
})
|
||||
_spec.SetField(authtokens.FieldExpiresAt, field.TypeTime, value)
|
||||
}
|
||||
if atuo.mutation.UserCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
@@ -438,10 +417,7 @@ func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens
|
||||
Columns: []string{authtokens.UserColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: user.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
@@ -454,10 +430,36 @@ func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens
|
||||
Columns: []string{authtokens.UserColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: user.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||
}
|
||||
if atuo.mutation.RolesCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2O,
|
||||
Inverse: false,
|
||||
Table: authtokens.RolesTable,
|
||||
Columns: []string{authtokens.RolesColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := atuo.mutation.RolesIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2O,
|
||||
Inverse: false,
|
||||
Table: authtokens.RolesTable,
|
||||
Columns: []string{authtokens.RolesColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -476,5 +478,6 @@ func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
atuo.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,69 +0,0 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect"
|
||||
)
|
||||
|
||||
// Option function to configure the client.
|
||||
type Option func(*config)
|
||||
|
||||
// Config is the configuration for the client and its builder.
|
||||
type config struct {
|
||||
// driver used for executing database requests.
|
||||
driver dialect.Driver
|
||||
// debug enable a debug logging.
|
||||
debug bool
|
||||
// log used for logging on debug mode.
|
||||
log func(...any)
|
||||
// hooks to execute on mutations.
|
||||
hooks *hooks
|
||||
}
|
||||
|
||||
// hooks per client, for fast access.
|
||||
type hooks struct {
|
||||
Attachment []ent.Hook
|
||||
AuthTokens []ent.Hook
|
||||
Document []ent.Hook
|
||||
DocumentToken []ent.Hook
|
||||
Group []ent.Hook
|
||||
GroupInvitationToken []ent.Hook
|
||||
Item []ent.Hook
|
||||
ItemField []ent.Hook
|
||||
Label []ent.Hook
|
||||
Location []ent.Hook
|
||||
User []ent.Hook
|
||||
}
|
||||
|
||||
// Options applies the options on the config object.
|
||||
func (c *config) options(opts ...Option) {
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
if c.debug {
|
||||
c.driver = dialect.Debug(c.driver, c.log)
|
||||
}
|
||||
}
|
||||
|
||||
// Debug enables debug logging on the ent.Driver.
|
||||
func Debug() Option {
|
||||
return func(c *config) {
|
||||
c.debug = true
|
||||
}
|
||||
}
|
||||
|
||||
// Log sets the logging function for debug mode.
|
||||
func Log(fn func(...any)) Option {
|
||||
return func(c *config) {
|
||||
c.log = fn
|
||||
}
|
||||
}
|
||||
|
||||
// Driver configures the client driver.
|
||||
func Driver(driver dialect.Driver) Option {
|
||||
return func(c *config) {
|
||||
c.driver = driver
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type clientCtxKey struct{}
|
||||
|
||||
// FromContext returns a Client stored inside a context, or nil if there isn't one.
|
||||
func FromContext(ctx context.Context) *Client {
|
||||
c, _ := ctx.Value(clientCtxKey{}).(*Client)
|
||||
return c
|
||||
}
|
||||
|
||||
// NewContext returns a new context with the given Client attached.
|
||||
func NewContext(parent context.Context, c *Client) context.Context {
|
||||
return context.WithValue(parent, clientCtxKey{}, c)
|
||||
}
|
||||
|
||||
type txCtxKey struct{}
|
||||
|
||||
// TxFromContext returns a Tx stored inside a context, or nil if there isn't one.
|
||||
func TxFromContext(ctx context.Context) *Tx {
|
||||
tx, _ := ctx.Value(txCtxKey{}).(*Tx)
|
||||
return tx
|
||||
}
|
||||
|
||||
// NewTxContext returns a new context with the given Tx attached.
|
||||
func NewTxContext(parent context.Context, tx *Tx) context.Context {
|
||||
return context.WithValue(parent, txCtxKey{}, tx)
|
||||
}
|
||||
@@ -36,13 +36,11 @@ type Document struct {
|
||||
type DocumentEdges struct {
|
||||
// Group holds the value of the group edge.
|
||||
Group *Group `json:"group,omitempty"`
|
||||
// DocumentTokens holds the value of the document_tokens edge.
|
||||
DocumentTokens []*DocumentToken `json:"document_tokens,omitempty"`
|
||||
// Attachments holds the value of the attachments edge.
|
||||
Attachments []*Attachment `json:"attachments,omitempty"`
|
||||
// loadedTypes holds the information for reporting if a
|
||||
// type was loaded (or requested) in eager-loading or not.
|
||||
loadedTypes [3]bool
|
||||
loadedTypes [2]bool
|
||||
}
|
||||
|
||||
// GroupOrErr returns the Group value or an error if the edge
|
||||
@@ -58,19 +56,10 @@ func (e DocumentEdges) GroupOrErr() (*Group, error) {
|
||||
return nil, &NotLoadedError{edge: "group"}
|
||||
}
|
||||
|
||||
// DocumentTokensOrErr returns the DocumentTokens value or an error if the edge
|
||||
// was not loaded in eager-loading.
|
||||
func (e DocumentEdges) DocumentTokensOrErr() ([]*DocumentToken, error) {
|
||||
if e.loadedTypes[1] {
|
||||
return e.DocumentTokens, nil
|
||||
}
|
||||
return nil, &NotLoadedError{edge: "document_tokens"}
|
||||
}
|
||||
|
||||
// AttachmentsOrErr returns the Attachments value or an error if the edge
|
||||
// was not loaded in eager-loading.
|
||||
func (e DocumentEdges) AttachmentsOrErr() ([]*Attachment, error) {
|
||||
if e.loadedTypes[2] {
|
||||
if e.loadedTypes[1] {
|
||||
return e.Attachments, nil
|
||||
}
|
||||
return nil, &NotLoadedError{edge: "attachments"}
|
||||
@@ -148,24 +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)
|
||||
}
|
||||
|
||||
// QueryDocumentTokens queries the "document_tokens" edge of the Document entity.
|
||||
func (d *Document) QueryDocumentTokens() *DocumentTokenQuery {
|
||||
return (&DocumentClient{config: d.config}).QueryDocumentTokens(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,
|
||||
@@ -201,9 +185,3 @@ func (d *Document) String() string {
|
||||
|
||||
// Documents is a parsable slice of Document.
|
||||
type Documents []*Document
|
||||
|
||||
func (d Documents) config(cfg config) {
|
||||
for _i := range d {
|
||||
d[_i].config = cfg
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ const (
|
||||
FieldPath = "path"
|
||||
// EdgeGroup holds the string denoting the group edge name in mutations.
|
||||
EdgeGroup = "group"
|
||||
// EdgeDocumentTokens holds the string denoting the document_tokens edge name in mutations.
|
||||
EdgeDocumentTokens = "document_tokens"
|
||||
// EdgeAttachments holds the string denoting the attachments edge name in mutations.
|
||||
EdgeAttachments = "attachments"
|
||||
// Table holds the table name of the document in the database.
|
||||
@@ -36,13 +34,6 @@ const (
|
||||
GroupInverseTable = "groups"
|
||||
// GroupColumn is the table column denoting the group relation/edge.
|
||||
GroupColumn = "group_documents"
|
||||
// DocumentTokensTable is the table that holds the document_tokens relation/edge.
|
||||
DocumentTokensTable = "document_tokens"
|
||||
// DocumentTokensInverseTable is the table name for the DocumentToken entity.
|
||||
// It exists in this package in order to avoid circular dependency with the "documenttoken" package.
|
||||
DocumentTokensInverseTable = "document_tokens"
|
||||
// DocumentTokensColumn is the table column denoting the document_tokens relation/edge.
|
||||
DocumentTokensColumn = "document_document_tokens"
|
||||
// AttachmentsTable is the table that holds the attachments relation/edge.
|
||||
AttachmentsTable = "attachments"
|
||||
// AttachmentsInverseTable is the table name for the Attachment entity.
|
||||
|
||||
@@ -13,427 +13,277 @@ import (
|
||||
|
||||
// ID filters vertices based on their ID field.
|
||||
func ID(id uuid.UUID) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Document(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDEQ applies the EQ predicate on the ID field.
|
||||
func IDEQ(id uuid.UUID) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Document(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDNEQ applies the NEQ predicate on the ID field.
|
||||
func IDNEQ(id uuid.UUID) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Document(sql.FieldNEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDIn applies the In predicate on the ID field.
|
||||
func IDIn(ids ...uuid.UUID) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
v := make([]any, len(ids))
|
||||
for i := range v {
|
||||
v[i] = ids[i]
|
||||
}
|
||||
s.Where(sql.In(s.C(FieldID), v...))
|
||||
})
|
||||
return predicate.Document(sql.FieldIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDNotIn applies the NotIn predicate on the ID field.
|
||||
func IDNotIn(ids ...uuid.UUID) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
v := make([]any, len(ids))
|
||||
for i := range v {
|
||||
v[i] = ids[i]
|
||||
}
|
||||
s.Where(sql.NotIn(s.C(FieldID), v...))
|
||||
})
|
||||
return predicate.Document(sql.FieldNotIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDGT applies the GT predicate on the ID field.
|
||||
func IDGT(id uuid.UUID) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Document(sql.FieldGT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDGTE applies the GTE predicate on the ID field.
|
||||
func IDGTE(id uuid.UUID) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Document(sql.FieldGTE(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLT applies the LT predicate on the ID field.
|
||||
func IDLT(id uuid.UUID) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Document(sql.FieldLT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLTE applies the LTE predicate on the ID field.
|
||||
func IDLTE(id uuid.UUID) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldID), id))
|
||||
})
|
||||
return predicate.Document(sql.FieldLTE(FieldID, id))
|
||||
}
|
||||
|
||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||
func CreatedAt(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
||||
func UpdatedAt(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// Title applies equality check predicate on the "title" field. It's identical to TitleEQ.
|
||||
func Title(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldEQ(FieldTitle, v))
|
||||
}
|
||||
|
||||
// Path applies equality check predicate on the "path" field. It's identical to PathEQ.
|
||||
func Path(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldEQ(FieldPath, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||
func CreatedAtNEQ(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldNEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||
func CreatedAtIn(vs ...time.Time) predicate.Document {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldCreatedAt), v...))
|
||||
})
|
||||
return predicate.Document(sql.FieldIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||
func CreatedAtNotIn(vs ...time.Time) predicate.Document {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldCreatedAt), v...))
|
||||
})
|
||||
return predicate.Document(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||
func CreatedAtGT(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldGT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||
func CreatedAtGTE(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldGTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||
func CreatedAtLT(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldLT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||
func CreatedAtLTE(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldCreatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldLTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
||||
func UpdatedAtEQ(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
||||
func UpdatedAtNEQ(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldNEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
||||
func UpdatedAtIn(vs ...time.Time) predicate.Document {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldUpdatedAt), v...))
|
||||
})
|
||||
return predicate.Document(sql.FieldIn(FieldUpdatedAt, vs...))
|
||||
}
|
||||
|
||||
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
||||
func UpdatedAtNotIn(vs ...time.Time) predicate.Document {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldUpdatedAt), v...))
|
||||
})
|
||||
return predicate.Document(sql.FieldNotIn(FieldUpdatedAt, vs...))
|
||||
}
|
||||
|
||||
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
||||
func UpdatedAtGT(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldGT(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
||||
func UpdatedAtGTE(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldGTE(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
||||
func UpdatedAtLT(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldLT(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
||||
func UpdatedAtLTE(v time.Time) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldUpdatedAt), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldLTE(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// TitleEQ applies the EQ predicate on the "title" field.
|
||||
func TitleEQ(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldEQ(FieldTitle, v))
|
||||
}
|
||||
|
||||
// TitleNEQ applies the NEQ predicate on the "title" field.
|
||||
func TitleNEQ(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldNEQ(FieldTitle, v))
|
||||
}
|
||||
|
||||
// TitleIn applies the In predicate on the "title" field.
|
||||
func TitleIn(vs ...string) predicate.Document {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldTitle), v...))
|
||||
})
|
||||
return predicate.Document(sql.FieldIn(FieldTitle, vs...))
|
||||
}
|
||||
|
||||
// TitleNotIn applies the NotIn predicate on the "title" field.
|
||||
func TitleNotIn(vs ...string) predicate.Document {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldTitle), v...))
|
||||
})
|
||||
return predicate.Document(sql.FieldNotIn(FieldTitle, vs...))
|
||||
}
|
||||
|
||||
// TitleGT applies the GT predicate on the "title" field.
|
||||
func TitleGT(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldGT(FieldTitle, v))
|
||||
}
|
||||
|
||||
// TitleGTE applies the GTE predicate on the "title" field.
|
||||
func TitleGTE(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldGTE(FieldTitle, v))
|
||||
}
|
||||
|
||||
// TitleLT applies the LT predicate on the "title" field.
|
||||
func TitleLT(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldLT(FieldTitle, v))
|
||||
}
|
||||
|
||||
// TitleLTE applies the LTE predicate on the "title" field.
|
||||
func TitleLTE(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldLTE(FieldTitle, v))
|
||||
}
|
||||
|
||||
// TitleContains applies the Contains predicate on the "title" field.
|
||||
func TitleContains(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.Contains(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldContains(FieldTitle, v))
|
||||
}
|
||||
|
||||
// TitleHasPrefix applies the HasPrefix predicate on the "title" field.
|
||||
func TitleHasPrefix(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.HasPrefix(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldHasPrefix(FieldTitle, v))
|
||||
}
|
||||
|
||||
// TitleHasSuffix applies the HasSuffix predicate on the "title" field.
|
||||
func TitleHasSuffix(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.HasSuffix(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldHasSuffix(FieldTitle, v))
|
||||
}
|
||||
|
||||
// TitleEqualFold applies the EqualFold predicate on the "title" field.
|
||||
func TitleEqualFold(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EqualFold(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldEqualFold(FieldTitle, v))
|
||||
}
|
||||
|
||||
// TitleContainsFold applies the ContainsFold predicate on the "title" field.
|
||||
func TitleContainsFold(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.ContainsFold(s.C(FieldTitle), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldContainsFold(FieldTitle, v))
|
||||
}
|
||||
|
||||
// PathEQ applies the EQ predicate on the "path" field.
|
||||
func PathEQ(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EQ(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldEQ(FieldPath, v))
|
||||
}
|
||||
|
||||
// PathNEQ applies the NEQ predicate on the "path" field.
|
||||
func PathNEQ(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.NEQ(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldNEQ(FieldPath, v))
|
||||
}
|
||||
|
||||
// PathIn applies the In predicate on the "path" field.
|
||||
func PathIn(vs ...string) predicate.Document {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.In(s.C(FieldPath), v...))
|
||||
})
|
||||
return predicate.Document(sql.FieldIn(FieldPath, vs...))
|
||||
}
|
||||
|
||||
// PathNotIn applies the NotIn predicate on the "path" field.
|
||||
func PathNotIn(vs ...string) predicate.Document {
|
||||
v := make([]any, len(vs))
|
||||
for i := range v {
|
||||
v[i] = vs[i]
|
||||
}
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.NotIn(s.C(FieldPath), v...))
|
||||
})
|
||||
return predicate.Document(sql.FieldNotIn(FieldPath, vs...))
|
||||
}
|
||||
|
||||
// PathGT applies the GT predicate on the "path" field.
|
||||
func PathGT(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.GT(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldGT(FieldPath, v))
|
||||
}
|
||||
|
||||
// PathGTE applies the GTE predicate on the "path" field.
|
||||
func PathGTE(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.GTE(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldGTE(FieldPath, v))
|
||||
}
|
||||
|
||||
// PathLT applies the LT predicate on the "path" field.
|
||||
func PathLT(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.LT(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldLT(FieldPath, v))
|
||||
}
|
||||
|
||||
// PathLTE applies the LTE predicate on the "path" field.
|
||||
func PathLTE(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.LTE(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldLTE(FieldPath, v))
|
||||
}
|
||||
|
||||
// PathContains applies the Contains predicate on the "path" field.
|
||||
func PathContains(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.Contains(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldContains(FieldPath, v))
|
||||
}
|
||||
|
||||
// PathHasPrefix applies the HasPrefix predicate on the "path" field.
|
||||
func PathHasPrefix(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.HasPrefix(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldHasPrefix(FieldPath, v))
|
||||
}
|
||||
|
||||
// PathHasSuffix applies the HasSuffix predicate on the "path" field.
|
||||
func PathHasSuffix(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.HasSuffix(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldHasSuffix(FieldPath, v))
|
||||
}
|
||||
|
||||
// PathEqualFold applies the EqualFold predicate on the "path" field.
|
||||
func PathEqualFold(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.EqualFold(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldEqualFold(FieldPath, v))
|
||||
}
|
||||
|
||||
// PathContainsFold applies the ContainsFold predicate on the "path" field.
|
||||
func PathContainsFold(v string) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
s.Where(sql.ContainsFold(s.C(FieldPath), v))
|
||||
})
|
||||
return predicate.Document(sql.FieldContainsFold(FieldPath, v))
|
||||
}
|
||||
|
||||
// HasGroup applies the HasEdge predicate on the "group" edge.
|
||||
@@ -441,7 +291,6 @@ func HasGroup() predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(GroupTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
|
||||
)
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
@@ -464,40 +313,11 @@ func HasGroupWith(preds ...predicate.Group) predicate.Document {
|
||||
})
|
||||
}
|
||||
|
||||
// HasDocumentTokens applies the HasEdge predicate on the "document_tokens" edge.
|
||||
func HasDocumentTokens() predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(DocumentTokensTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, DocumentTokensTable, DocumentTokensColumn),
|
||||
)
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
})
|
||||
}
|
||||
|
||||
// HasDocumentTokensWith applies the HasEdge predicate on the "document_tokens" edge with a given conditions (other predicates).
|
||||
func HasDocumentTokensWith(preds ...predicate.DocumentToken) predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(DocumentTokensInverseTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, DocumentTokensTable, DocumentTokensColumn),
|
||||
)
|
||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||
for _, p := range preds {
|
||||
p(s)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// HasAttachments applies the HasEdge predicate on the "attachments" edge.
|
||||
func HasAttachments() predicate.Document {
|
||||
return predicate.Document(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(AttachmentsTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, AttachmentsTable, AttachmentsColumn),
|
||||
)
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/document"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/group"
|
||||
)
|
||||
|
||||
@@ -89,21 +88,6 @@ func (dc *DocumentCreate) SetGroup(g *Group) *DocumentCreate {
|
||||
return dc.SetGroupID(g.ID)
|
||||
}
|
||||
|
||||
// AddDocumentTokenIDs adds the "document_tokens" edge to the DocumentToken entity by IDs.
|
||||
func (dc *DocumentCreate) AddDocumentTokenIDs(ids ...uuid.UUID) *DocumentCreate {
|
||||
dc.mutation.AddDocumentTokenIDs(ids...)
|
||||
return dc
|
||||
}
|
||||
|
||||
// AddDocumentTokens adds the "document_tokens" edges to the DocumentToken entity.
|
||||
func (dc *DocumentCreate) AddDocumentTokens(d ...*DocumentToken) *DocumentCreate {
|
||||
ids := make([]uuid.UUID, len(d))
|
||||
for i := range d {
|
||||
ids[i] = d[i].ID
|
||||
}
|
||||
return dc.AddDocumentTokenIDs(ids...)
|
||||
}
|
||||
|
||||
// AddAttachmentIDs adds the "attachments" edge to the Attachment entity by IDs.
|
||||
func (dc *DocumentCreate) AddAttachmentIDs(ids ...uuid.UUID) *DocumentCreate {
|
||||
dc.mutation.AddAttachmentIDs(ids...)
|
||||
@@ -126,50 +110,8 @@ func (dc *DocumentCreate) Mutation() *DocumentMutation {
|
||||
|
||||
// Save creates the Document in the database.
|
||||
func (dc *DocumentCreate) Save(ctx context.Context) (*Document, error) {
|
||||
var (
|
||||
err error
|
||||
node *Document
|
||||
)
|
||||
dc.defaults()
|
||||
if len(dc.hooks) == 0 {
|
||||
if err = dc.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, err = dc.sqlSave(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*DocumentMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
if err = dc.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dc.mutation = mutation
|
||||
if node, err = dc.sqlSave(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mutation.id = &node.ID
|
||||
mutation.done = true
|
||||
return node, err
|
||||
})
|
||||
for i := len(dc.hooks) - 1; i >= 0; i-- {
|
||||
if dc.hooks[i] == nil {
|
||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = dc.hooks[i](mut)
|
||||
}
|
||||
v, err := mut.Mutate(ctx, dc.mutation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nv, ok := v.(*Document)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected node type %T returned from DocumentMutation", v)
|
||||
}
|
||||
node = nv
|
||||
}
|
||||
return node, err
|
||||
return withHooks[*Document, DocumentMutation](ctx, dc.sqlSave, dc.mutation, dc.hooks)
|
||||
}
|
||||
|
||||
// SaveX calls Save and panics if Save returns an error.
|
||||
@@ -241,6 +183,9 @@ func (dc *DocumentCreate) check() error {
|
||||
}
|
||||
|
||||
func (dc *DocumentCreate) sqlSave(ctx context.Context) (*Document, error) {
|
||||
if err := dc.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_node, _spec := dc.createSpec()
|
||||
if err := sqlgraph.CreateNode(ctx, dc.driver, _spec); err != nil {
|
||||
if sqlgraph.IsConstraintError(err) {
|
||||
@@ -255,54 +200,34 @@ func (dc *DocumentCreate) sqlSave(ctx context.Context) (*Document, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.mutation.id = &_node.ID
|
||||
dc.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
|
||||
var (
|
||||
_node = &Document{config: dc.config}
|
||||
_spec = &sqlgraph.CreateSpec{
|
||||
Table: document.Table,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: document.FieldID,
|
||||
},
|
||||
}
|
||||
_spec = sqlgraph.NewCreateSpec(document.Table, sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID))
|
||||
)
|
||||
if id, ok := dc.mutation.ID(); ok {
|
||||
_node.ID = id
|
||||
_spec.ID.Value = &id
|
||||
}
|
||||
if value, ok := dc.mutation.CreatedAt(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: document.FieldCreatedAt,
|
||||
})
|
||||
_spec.SetField(document.FieldCreatedAt, field.TypeTime, value)
|
||||
_node.CreatedAt = value
|
||||
}
|
||||
if value, ok := dc.mutation.UpdatedAt(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: document.FieldUpdatedAt,
|
||||
})
|
||||
_spec.SetField(document.FieldUpdatedAt, field.TypeTime, value)
|
||||
_node.UpdatedAt = value
|
||||
}
|
||||
if value, ok := dc.mutation.Title(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: document.FieldTitle,
|
||||
})
|
||||
_spec.SetField(document.FieldTitle, field.TypeString, value)
|
||||
_node.Title = value
|
||||
}
|
||||
if value, ok := dc.mutation.Path(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: document.FieldPath,
|
||||
})
|
||||
_spec.SetField(document.FieldPath, field.TypeString, value)
|
||||
_node.Path = value
|
||||
}
|
||||
if nodes := dc.mutation.GroupIDs(); len(nodes) > 0 {
|
||||
@@ -313,10 +238,7 @@ func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
|
||||
Columns: []string{document.GroupColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: group.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -325,25 +247,6 @@ func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
|
||||
_node.group_documents = &nodes[0]
|
||||
_spec.Edges = append(_spec.Edges, edge)
|
||||
}
|
||||
if nodes := dc.mutation.DocumentTokensIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: document.DocumentTokensTable,
|
||||
Columns: []string{document.DocumentTokensColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: documenttoken.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges = append(_spec.Edges, edge)
|
||||
}
|
||||
if nodes := dc.mutation.AttachmentsIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
@@ -352,10 +255,7 @@ func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
|
||||
Columns: []string{document.AttachmentsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
|
||||
@@ -4,7 +4,6 @@ package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
@@ -28,34 +27,7 @@ func (dd *DocumentDelete) Where(ps ...predicate.Document) *DocumentDelete {
|
||||
|
||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||
func (dd *DocumentDelete) Exec(ctx context.Context) (int, error) {
|
||||
var (
|
||||
err error
|
||||
affected int
|
||||
)
|
||||
if len(dd.hooks) == 0 {
|
||||
affected, err = dd.sqlExec(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*DocumentMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
dd.mutation = mutation
|
||||
affected, err = dd.sqlExec(ctx)
|
||||
mutation.done = true
|
||||
return affected, err
|
||||
})
|
||||
for i := len(dd.hooks) - 1; i >= 0; i-- {
|
||||
if dd.hooks[i] == nil {
|
||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = dd.hooks[i](mut)
|
||||
}
|
||||
if _, err := mut.Mutate(ctx, dd.mutation); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return affected, err
|
||||
return withHooks[int, DocumentMutation](ctx, dd.sqlExec, dd.mutation, dd.hooks)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
@@ -68,15 +40,7 @@ func (dd *DocumentDelete) ExecX(ctx context.Context) int {
|
||||
}
|
||||
|
||||
func (dd *DocumentDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
_spec := &sqlgraph.DeleteSpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: document.Table,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: document.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
_spec := sqlgraph.NewDeleteSpec(document.Table, sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID))
|
||||
if ps := dd.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
@@ -88,6 +52,7 @@ func (dd *DocumentDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
dd.mutation.done = true
|
||||
return affected, err
|
||||
}
|
||||
|
||||
@@ -96,6 +61,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)
|
||||
@@ -111,5 +82,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/document"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/group"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||
)
|
||||
@@ -22,16 +21,13 @@ import (
|
||||
// DocumentQuery is the builder for querying Document entities.
|
||||
type DocumentQuery struct {
|
||||
config
|
||||
limit *int
|
||||
offset *int
|
||||
unique *bool
|
||||
order []OrderFunc
|
||||
fields []string
|
||||
predicates []predicate.Document
|
||||
withGroup *GroupQuery
|
||||
withDocumentTokens *DocumentTokenQuery
|
||||
withAttachments *AttachmentQuery
|
||||
withFKs bool
|
||||
ctx *QueryContext
|
||||
order []OrderFunc
|
||||
inters []Interceptor
|
||||
predicates []predicate.Document
|
||||
withGroup *GroupQuery
|
||||
withAttachments *AttachmentQuery
|
||||
withFKs bool
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
path func(context.Context) (*sql.Selector, error)
|
||||
@@ -43,26 +39,26 @@ func (dq *DocumentQuery) Where(ps ...predicate.Document) *DocumentQuery {
|
||||
return dq
|
||||
}
|
||||
|
||||
// Limit adds a limit step to the query.
|
||||
// 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 adds an offset step to the query.
|
||||
// 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
|
||||
}
|
||||
|
||||
// Order adds an order step to the query.
|
||||
// Order specifies how the records should be ordered.
|
||||
func (dq *DocumentQuery) Order(o ...OrderFunc) *DocumentQuery {
|
||||
dq.order = append(dq.order, o...)
|
||||
return dq
|
||||
@@ -70,7 +66,7 @@ func (dq *DocumentQuery) Order(o ...OrderFunc) *DocumentQuery {
|
||||
|
||||
// QueryGroup chains the current query on the "group" edge.
|
||||
func (dq *DocumentQuery) QueryGroup() *GroupQuery {
|
||||
query := &GroupQuery{config: dq.config}
|
||||
query := (&GroupClient{config: dq.config}).Query()
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := dq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
@@ -90,31 +86,9 @@ func (dq *DocumentQuery) QueryGroup() *GroupQuery {
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryDocumentTokens chains the current query on the "document_tokens" edge.
|
||||
func (dq *DocumentQuery) QueryDocumentTokens() *DocumentTokenQuery {
|
||||
query := &DocumentTokenQuery{config: dq.config}
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := dq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selector := dq.sqlQuery(ctx)
|
||||
if err := selector.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(document.Table, document.FieldID, selector),
|
||||
sqlgraph.To(documenttoken.Table, documenttoken.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, document.DocumentTokensTable, document.DocumentTokensColumn),
|
||||
)
|
||||
fromU = sqlgraph.SetNeighbors(dq.driver.Dialect(), step)
|
||||
return fromU, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryAttachments chains the current query on the "attachments" edge.
|
||||
func (dq *DocumentQuery) QueryAttachments() *AttachmentQuery {
|
||||
query := &AttachmentQuery{config: dq.config}
|
||||
query := (&AttachmentClient{config: dq.config}).Query()
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := dq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
@@ -137,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(ctx)
|
||||
nodes, err := dq.Limit(1).All(setContextOp(ctx, dq.ctx, "First"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -160,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(ctx); err != nil {
|
||||
if ids, err = dq.Limit(1).IDs(setContextOp(ctx, dq.ctx, "FirstID")); err != nil {
|
||||
return
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
@@ -183,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(ctx)
|
||||
nodes, err := dq.Limit(2).All(setContextOp(ctx, dq.ctx, "Only"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -211,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(ctx); err != nil {
|
||||
if ids, err = dq.Limit(2).IDs(setContextOp(ctx, dq.ctx, "OnlyID")); err != nil {
|
||||
return
|
||||
}
|
||||
switch len(ids) {
|
||||
@@ -236,10 +210,12 @@ 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 = setContextOp(ctx, dq.ctx, "All")
|
||||
if err := dq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dq.sqlAll(ctx)
|
||||
qr := querierAll[[]*Document, *DocumentQuery]()
|
||||
return withInterceptors[[]*Document](ctx, dq, qr, dq.inters)
|
||||
}
|
||||
|
||||
// AllX is like All, but panics if an error occurs.
|
||||
@@ -252,9 +228,12 @@ 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
|
||||
if err := dq.Select(document.FieldID).Scan(ctx, &ids); err != nil {
|
||||
func (dq *DocumentQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
|
||||
if dq.ctx.Unique == nil && dq.path != nil {
|
||||
dq.Unique(true)
|
||||
}
|
||||
ctx = setContextOp(ctx, dq.ctx, "IDs")
|
||||
if err = dq.Select(document.FieldID).Scan(ctx, &ids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
@@ -271,10 +250,11 @@ 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 = setContextOp(ctx, dq.ctx, "Count")
|
||||
if err := dq.prepareQuery(ctx); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return dq.sqlCount(ctx)
|
||||
return withInterceptors[int](ctx, dq, querierCount[*DocumentQuery](), dq.inters)
|
||||
}
|
||||
|
||||
// CountX is like Count, but panics if an error occurs.
|
||||
@@ -288,10 +268,15 @@ 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) {
|
||||
if err := dq.prepareQuery(ctx); err != nil {
|
||||
return false, err
|
||||
ctx = setContextOp(ctx, dq.ctx, "Exist")
|
||||
switch _, err := dq.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
return dq.sqlExist(ctx)
|
||||
}
|
||||
|
||||
// ExistX is like Exist, but panics if an error occurs.
|
||||
@@ -310,25 +295,23 @@ func (dq *DocumentQuery) Clone() *DocumentQuery {
|
||||
return nil
|
||||
}
|
||||
return &DocumentQuery{
|
||||
config: dq.config,
|
||||
limit: dq.limit,
|
||||
offset: dq.offset,
|
||||
order: append([]OrderFunc{}, dq.order...),
|
||||
predicates: append([]predicate.Document{}, dq.predicates...),
|
||||
withGroup: dq.withGroup.Clone(),
|
||||
withDocumentTokens: dq.withDocumentTokens.Clone(),
|
||||
withAttachments: dq.withAttachments.Clone(),
|
||||
config: dq.config,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
// WithGroup tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "group" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (dq *DocumentQuery) WithGroup(opts ...func(*GroupQuery)) *DocumentQuery {
|
||||
query := &GroupQuery{config: dq.config}
|
||||
query := (&GroupClient{config: dq.config}).Query()
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
@@ -336,21 +319,10 @@ func (dq *DocumentQuery) WithGroup(opts ...func(*GroupQuery)) *DocumentQuery {
|
||||
return dq
|
||||
}
|
||||
|
||||
// WithDocumentTokens tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "document_tokens" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (dq *DocumentQuery) WithDocumentTokens(opts ...func(*DocumentTokenQuery)) *DocumentQuery {
|
||||
query := &DocumentTokenQuery{config: dq.config}
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
dq.withDocumentTokens = query
|
||||
return dq
|
||||
}
|
||||
|
||||
// WithAttachments tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "attachments" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (dq *DocumentQuery) WithAttachments(opts ...func(*AttachmentQuery)) *DocumentQuery {
|
||||
query := &AttachmentQuery{config: dq.config}
|
||||
query := (&AttachmentClient{config: dq.config}).Query()
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
@@ -373,16 +345,11 @@ func (dq *DocumentQuery) WithAttachments(opts ...func(*AttachmentQuery)) *Docume
|
||||
// Aggregate(ent.Count()).
|
||||
// Scan(ctx, &v)
|
||||
func (dq *DocumentQuery) GroupBy(field string, fields ...string) *DocumentGroupBy {
|
||||
grbuild := &DocumentGroupBy{config: dq.config}
|
||||
grbuild.fields = append([]string{field}, fields...)
|
||||
grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
|
||||
if err := dq.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dq.sqlQuery(ctx), nil
|
||||
}
|
||||
dq.ctx.Fields = append([]string{field}, fields...)
|
||||
grbuild := &DocumentGroupBy{build: dq}
|
||||
grbuild.flds = &dq.ctx.Fields
|
||||
grbuild.label = document.Label
|
||||
grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
|
||||
grbuild.scan = grbuild.Scan
|
||||
return grbuild
|
||||
}
|
||||
|
||||
@@ -399,15 +366,30 @@ 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...)
|
||||
selbuild := &DocumentSelect{DocumentQuery: dq}
|
||||
selbuild.label = document.Label
|
||||
selbuild.flds, selbuild.scan = &dq.fields, selbuild.Scan
|
||||
return selbuild
|
||||
dq.ctx.Fields = append(dq.ctx.Fields, fields...)
|
||||
sbuild := &DocumentSelect{DocumentQuery: dq}
|
||||
sbuild.label = document.Label
|
||||
sbuild.flds, sbuild.scan = &dq.ctx.Fields, sbuild.Scan
|
||||
return sbuild
|
||||
}
|
||||
|
||||
// Aggregate returns a DocumentSelect configured with the given aggregations.
|
||||
func (dq *DocumentQuery) Aggregate(fns ...AggregateFunc) *DocumentSelect {
|
||||
return dq.Select().Aggregate(fns...)
|
||||
}
|
||||
|
||||
func (dq *DocumentQuery) prepareQuery(ctx context.Context) error {
|
||||
for _, f := range dq.fields {
|
||||
for _, inter := range dq.inters {
|
||||
if inter == nil {
|
||||
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
|
||||
}
|
||||
if trv, ok := inter.(Traverser); ok {
|
||||
if err := trv.Traverse(ctx, dq); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, f := range dq.ctx.Fields {
|
||||
if !document.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
@@ -427,9 +409,8 @@ func (dq *DocumentQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Doc
|
||||
nodes = []*Document{}
|
||||
withFKs = dq.withFKs
|
||||
_spec = dq.querySpec()
|
||||
loadedTypes = [3]bool{
|
||||
loadedTypes = [2]bool{
|
||||
dq.withGroup != nil,
|
||||
dq.withDocumentTokens != nil,
|
||||
dq.withAttachments != nil,
|
||||
}
|
||||
)
|
||||
@@ -463,13 +444,6 @@ func (dq *DocumentQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Doc
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if query := dq.withDocumentTokens; query != nil {
|
||||
if err := dq.loadDocumentTokens(ctx, query, nodes,
|
||||
func(n *Document) { n.Edges.DocumentTokens = []*DocumentToken{} },
|
||||
func(n *Document, e *DocumentToken) { n.Edges.DocumentTokens = append(n.Edges.DocumentTokens, e) }); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if query := dq.withAttachments; query != nil {
|
||||
if err := dq.loadAttachments(ctx, query, nodes,
|
||||
func(n *Document) { n.Edges.Attachments = []*Attachment{} },
|
||||
@@ -493,6 +467,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 {
|
||||
@@ -509,37 +486,6 @@ func (dq *DocumentQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (dq *DocumentQuery) loadDocumentTokens(ctx context.Context, query *DocumentTokenQuery, nodes []*Document, init func(*Document), assign func(*Document, *DocumentToken)) error {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
nodeids := make(map[uuid.UUID]*Document)
|
||||
for i := range nodes {
|
||||
fks = append(fks, nodes[i].ID)
|
||||
nodeids[nodes[i].ID] = nodes[i]
|
||||
if init != nil {
|
||||
init(nodes[i])
|
||||
}
|
||||
}
|
||||
query.withFKs = true
|
||||
query.Where(predicate.DocumentToken(func(s *sql.Selector) {
|
||||
s.Where(sql.InValues(document.DocumentTokensColumn, fks...))
|
||||
}))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
fk := n.document_document_tokens
|
||||
if fk == nil {
|
||||
return fmt.Errorf(`foreign-key "document_document_tokens" is nil for node %v`, n.ID)
|
||||
}
|
||||
node, ok := nodeids[*fk]
|
||||
if !ok {
|
||||
return fmt.Errorf(`unexpected foreign-key "document_document_tokens" returned %v for node %v`, *fk, n.ID)
|
||||
}
|
||||
assign(node, n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (dq *DocumentQuery) loadAttachments(ctx context.Context, query *AttachmentQuery, nodes []*Document, init func(*Document), assign func(*Document, *Attachment)) error {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
nodeids := make(map[uuid.UUID]*Document)
|
||||
@@ -574,41 +520,22 @@ 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)
|
||||
}
|
||||
|
||||
func (dq *DocumentQuery) sqlExist(ctx context.Context) (bool, error) {
|
||||
switch _, err := dq.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (dq *DocumentQuery) querySpec() *sqlgraph.QuerySpec {
|
||||
_spec := &sqlgraph.QuerySpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: document.Table,
|
||||
Columns: document.Columns,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: document.FieldID,
|
||||
},
|
||||
},
|
||||
From: dq.sql,
|
||||
Unique: true,
|
||||
}
|
||||
if unique := dq.unique; unique != nil {
|
||||
_spec := sqlgraph.NewQuerySpec(document.Table, document.Columns, sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID))
|
||||
_spec.From = dq.sql
|
||||
if unique := dq.ctx.Unique; unique != nil {
|
||||
_spec.Unique = *unique
|
||||
} else if dq.path != nil {
|
||||
_spec.Unique = true
|
||||
}
|
||||
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 {
|
||||
@@ -624,10 +551,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 {
|
||||
@@ -643,7 +570,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
|
||||
}
|
||||
@@ -652,7 +579,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 {
|
||||
@@ -661,12 +588,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
|
||||
@@ -674,13 +601,8 @@ func (dq *DocumentQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||
|
||||
// DocumentGroupBy is the group-by builder for Document entities.
|
||||
type DocumentGroupBy struct {
|
||||
config
|
||||
selector
|
||||
fields []string
|
||||
fns []AggregateFunc
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
path func(context.Context) (*sql.Selector, error)
|
||||
build *DocumentQuery
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the group-by query.
|
||||
@@ -689,74 +611,77 @@ func (dgb *DocumentGroupBy) Aggregate(fns ...AggregateFunc) *DocumentGroupBy {
|
||||
return dgb
|
||||
}
|
||||
|
||||
// Scan applies the group-by query and scans the result into the given value.
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (dgb *DocumentGroupBy) Scan(ctx context.Context, v any) error {
|
||||
query, err := dgb.path(ctx)
|
||||
if err != nil {
|
||||
ctx = setContextOp(ctx, dgb.build.ctx, "GroupBy")
|
||||
if err := dgb.build.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
dgb.sql = query
|
||||
return dgb.sqlScan(ctx, v)
|
||||
return scanWithInterceptors[*DocumentQuery, *DocumentGroupBy](ctx, dgb.build, dgb, dgb.build.inters, v)
|
||||
}
|
||||
|
||||
func (dgb *DocumentGroupBy) sqlScan(ctx context.Context, v any) error {
|
||||
for _, f := range dgb.fields {
|
||||
if !document.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("invalid field %q for group-by", f)}
|
||||
}
|
||||
}
|
||||
selector := dgb.sqlQuery()
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := dgb.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
func (dgb *DocumentGroupBy) sqlQuery() *sql.Selector {
|
||||
selector := dgb.sql.Select()
|
||||
func (dgb *DocumentGroupBy) sqlScan(ctx context.Context, root *DocumentQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx).Select()
|
||||
aggregation := make([]string, 0, len(dgb.fns))
|
||||
for _, fn := range dgb.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
// If no columns were selected in a custom aggregation function, the default
|
||||
// selection is the fields used for "group-by", and the aggregation functions.
|
||||
if len(selector.SelectedColumns()) == 0 {
|
||||
columns := make([]string, 0, len(dgb.fields)+len(dgb.fns))
|
||||
for _, f := range dgb.fields {
|
||||
columns := make([]string, 0, len(*dgb.flds)+len(dgb.fns))
|
||||
for _, f := range *dgb.flds {
|
||||
columns = append(columns, selector.C(f))
|
||||
}
|
||||
columns = append(columns, aggregation...)
|
||||
selector.Select(columns...)
|
||||
}
|
||||
return selector.GroupBy(selector.Columns(dgb.fields...)...)
|
||||
selector.GroupBy(selector.Columns(*dgb.flds...)...)
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := dgb.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
// DocumentSelect is the builder for selecting fields of Document entities.
|
||||
type DocumentSelect struct {
|
||||
*DocumentQuery
|
||||
selector
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the selector query.
|
||||
func (ds *DocumentSelect) Aggregate(fns ...AggregateFunc) *DocumentSelect {
|
||||
ds.fns = append(ds.fns, fns...)
|
||||
return ds
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (ds *DocumentSelect) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, ds.ctx, "Select")
|
||||
if err := ds.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
ds.sql = ds.DocumentQuery.sqlQuery(ctx)
|
||||
return ds.sqlScan(ctx, v)
|
||||
return scanWithInterceptors[*DocumentQuery, *DocumentSelect](ctx, ds.DocumentQuery, ds, ds.inters, v)
|
||||
}
|
||||
|
||||
func (ds *DocumentSelect) sqlScan(ctx context.Context, v any) error {
|
||||
func (ds *DocumentSelect) sqlScan(ctx context.Context, root *DocumentQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx)
|
||||
aggregation := make([]string, 0, len(ds.fns))
|
||||
for _, fn := range ds.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
switch n := len(*ds.selector.flds); {
|
||||
case n == 0 && len(aggregation) > 0:
|
||||
selector.Select(aggregation...)
|
||||
case n != 0 && len(aggregation) > 0:
|
||||
selector.AppendSelect(aggregation...)
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := ds.sql.Query()
|
||||
query, args := selector.Query()
|
||||
if err := ds.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/document"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/group"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||
)
|
||||
@@ -61,21 +60,6 @@ func (du *DocumentUpdate) SetGroup(g *Group) *DocumentUpdate {
|
||||
return du.SetGroupID(g.ID)
|
||||
}
|
||||
|
||||
// AddDocumentTokenIDs adds the "document_tokens" edge to the DocumentToken entity by IDs.
|
||||
func (du *DocumentUpdate) AddDocumentTokenIDs(ids ...uuid.UUID) *DocumentUpdate {
|
||||
du.mutation.AddDocumentTokenIDs(ids...)
|
||||
return du
|
||||
}
|
||||
|
||||
// AddDocumentTokens adds the "document_tokens" edges to the DocumentToken entity.
|
||||
func (du *DocumentUpdate) AddDocumentTokens(d ...*DocumentToken) *DocumentUpdate {
|
||||
ids := make([]uuid.UUID, len(d))
|
||||
for i := range d {
|
||||
ids[i] = d[i].ID
|
||||
}
|
||||
return du.AddDocumentTokenIDs(ids...)
|
||||
}
|
||||
|
||||
// AddAttachmentIDs adds the "attachments" edge to the Attachment entity by IDs.
|
||||
func (du *DocumentUpdate) AddAttachmentIDs(ids ...uuid.UUID) *DocumentUpdate {
|
||||
du.mutation.AddAttachmentIDs(ids...)
|
||||
@@ -102,27 +86,6 @@ func (du *DocumentUpdate) ClearGroup() *DocumentUpdate {
|
||||
return du
|
||||
}
|
||||
|
||||
// ClearDocumentTokens clears all "document_tokens" edges to the DocumentToken entity.
|
||||
func (du *DocumentUpdate) ClearDocumentTokens() *DocumentUpdate {
|
||||
du.mutation.ClearDocumentTokens()
|
||||
return du
|
||||
}
|
||||
|
||||
// RemoveDocumentTokenIDs removes the "document_tokens" edge to DocumentToken entities by IDs.
|
||||
func (du *DocumentUpdate) RemoveDocumentTokenIDs(ids ...uuid.UUID) *DocumentUpdate {
|
||||
du.mutation.RemoveDocumentTokenIDs(ids...)
|
||||
return du
|
||||
}
|
||||
|
||||
// RemoveDocumentTokens removes "document_tokens" edges to DocumentToken entities.
|
||||
func (du *DocumentUpdate) RemoveDocumentTokens(d ...*DocumentToken) *DocumentUpdate {
|
||||
ids := make([]uuid.UUID, len(d))
|
||||
for i := range d {
|
||||
ids[i] = d[i].ID
|
||||
}
|
||||
return du.RemoveDocumentTokenIDs(ids...)
|
||||
}
|
||||
|
||||
// ClearAttachments clears all "attachments" edges to the Attachment entity.
|
||||
func (du *DocumentUpdate) ClearAttachments() *DocumentUpdate {
|
||||
du.mutation.ClearAttachments()
|
||||
@@ -146,41 +109,8 @@ func (du *DocumentUpdate) RemoveAttachments(a ...*Attachment) *DocumentUpdate {
|
||||
|
||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||
func (du *DocumentUpdate) Save(ctx context.Context) (int, error) {
|
||||
var (
|
||||
err error
|
||||
affected int
|
||||
)
|
||||
du.defaults()
|
||||
if len(du.hooks) == 0 {
|
||||
if err = du.check(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
affected, err = du.sqlSave(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*DocumentMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
if err = du.check(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
du.mutation = mutation
|
||||
affected, err = du.sqlSave(ctx)
|
||||
mutation.done = true
|
||||
return affected, err
|
||||
})
|
||||
for i := len(du.hooks) - 1; i >= 0; i-- {
|
||||
if du.hooks[i] == nil {
|
||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = du.hooks[i](mut)
|
||||
}
|
||||
if _, err := mut.Mutate(ctx, du.mutation); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return affected, err
|
||||
return withHooks[int, DocumentMutation](ctx, du.sqlSave, du.mutation, du.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
@@ -232,16 +162,10 @@ func (du *DocumentUpdate) check() error {
|
||||
}
|
||||
|
||||
func (du *DocumentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
_spec := &sqlgraph.UpdateSpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: document.Table,
|
||||
Columns: document.Columns,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: document.FieldID,
|
||||
},
|
||||
},
|
||||
if err := du.check(); err != nil {
|
||||
return n, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(document.Table, document.Columns, sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID))
|
||||
if ps := du.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
@@ -250,25 +174,13 @@ func (du *DocumentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
}
|
||||
}
|
||||
if value, ok := du.mutation.UpdatedAt(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: document.FieldUpdatedAt,
|
||||
})
|
||||
_spec.SetField(document.FieldUpdatedAt, field.TypeTime, value)
|
||||
}
|
||||
if value, ok := du.mutation.Title(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: document.FieldTitle,
|
||||
})
|
||||
_spec.SetField(document.FieldTitle, field.TypeString, value)
|
||||
}
|
||||
if value, ok := du.mutation.Path(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: document.FieldPath,
|
||||
})
|
||||
_spec.SetField(document.FieldPath, field.TypeString, value)
|
||||
}
|
||||
if du.mutation.GroupCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
@@ -278,10 +190,7 @@ func (du *DocumentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{document.GroupColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: group.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
@@ -294,64 +203,7 @@ func (du *DocumentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{document.GroupColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: group.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||
}
|
||||
if du.mutation.DocumentTokensCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: document.DocumentTokensTable,
|
||||
Columns: []string{document.DocumentTokensColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: documenttoken.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := du.mutation.RemovedDocumentTokensIDs(); len(nodes) > 0 && !du.mutation.DocumentTokensCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: document.DocumentTokensTable,
|
||||
Columns: []string{document.DocumentTokensColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: documenttoken.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := du.mutation.DocumentTokensIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: document.DocumentTokensTable,
|
||||
Columns: []string{document.DocumentTokensColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: documenttoken.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -367,10 +219,7 @@ func (du *DocumentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{document.AttachmentsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
@@ -383,10 +232,7 @@ func (du *DocumentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{document.AttachmentsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -402,10 +248,7 @@ func (du *DocumentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
Columns: []string{document.AttachmentsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -421,6 +264,7 @@ func (du *DocumentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
du.mutation.done = true
|
||||
return n, nil
|
||||
}
|
||||
|
||||
@@ -461,21 +305,6 @@ func (duo *DocumentUpdateOne) SetGroup(g *Group) *DocumentUpdateOne {
|
||||
return duo.SetGroupID(g.ID)
|
||||
}
|
||||
|
||||
// AddDocumentTokenIDs adds the "document_tokens" edge to the DocumentToken entity by IDs.
|
||||
func (duo *DocumentUpdateOne) AddDocumentTokenIDs(ids ...uuid.UUID) *DocumentUpdateOne {
|
||||
duo.mutation.AddDocumentTokenIDs(ids...)
|
||||
return duo
|
||||
}
|
||||
|
||||
// AddDocumentTokens adds the "document_tokens" edges to the DocumentToken entity.
|
||||
func (duo *DocumentUpdateOne) AddDocumentTokens(d ...*DocumentToken) *DocumentUpdateOne {
|
||||
ids := make([]uuid.UUID, len(d))
|
||||
for i := range d {
|
||||
ids[i] = d[i].ID
|
||||
}
|
||||
return duo.AddDocumentTokenIDs(ids...)
|
||||
}
|
||||
|
||||
// AddAttachmentIDs adds the "attachments" edge to the Attachment entity by IDs.
|
||||
func (duo *DocumentUpdateOne) AddAttachmentIDs(ids ...uuid.UUID) *DocumentUpdateOne {
|
||||
duo.mutation.AddAttachmentIDs(ids...)
|
||||
@@ -502,27 +331,6 @@ func (duo *DocumentUpdateOne) ClearGroup() *DocumentUpdateOne {
|
||||
return duo
|
||||
}
|
||||
|
||||
// ClearDocumentTokens clears all "document_tokens" edges to the DocumentToken entity.
|
||||
func (duo *DocumentUpdateOne) ClearDocumentTokens() *DocumentUpdateOne {
|
||||
duo.mutation.ClearDocumentTokens()
|
||||
return duo
|
||||
}
|
||||
|
||||
// RemoveDocumentTokenIDs removes the "document_tokens" edge to DocumentToken entities by IDs.
|
||||
func (duo *DocumentUpdateOne) RemoveDocumentTokenIDs(ids ...uuid.UUID) *DocumentUpdateOne {
|
||||
duo.mutation.RemoveDocumentTokenIDs(ids...)
|
||||
return duo
|
||||
}
|
||||
|
||||
// RemoveDocumentTokens removes "document_tokens" edges to DocumentToken entities.
|
||||
func (duo *DocumentUpdateOne) RemoveDocumentTokens(d ...*DocumentToken) *DocumentUpdateOne {
|
||||
ids := make([]uuid.UUID, len(d))
|
||||
for i := range d {
|
||||
ids[i] = d[i].ID
|
||||
}
|
||||
return duo.RemoveDocumentTokenIDs(ids...)
|
||||
}
|
||||
|
||||
// ClearAttachments clears all "attachments" edges to the Attachment entity.
|
||||
func (duo *DocumentUpdateOne) ClearAttachments() *DocumentUpdateOne {
|
||||
duo.mutation.ClearAttachments()
|
||||
@@ -544,6 +352,12 @@ func (duo *DocumentUpdateOne) RemoveAttachments(a ...*Attachment) *DocumentUpdat
|
||||
return duo.RemoveAttachmentIDs(ids...)
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the DocumentUpdate builder.
|
||||
func (duo *DocumentUpdateOne) Where(ps ...predicate.Document) *DocumentUpdateOne {
|
||||
duo.mutation.Where(ps...)
|
||||
return duo
|
||||
}
|
||||
|
||||
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||
// The default is selecting all fields defined in the entity schema.
|
||||
func (duo *DocumentUpdateOne) Select(field string, fields ...string) *DocumentUpdateOne {
|
||||
@@ -553,47 +367,8 @@ func (duo *DocumentUpdateOne) Select(field string, fields ...string) *DocumentUp
|
||||
|
||||
// Save executes the query and returns the updated Document entity.
|
||||
func (duo *DocumentUpdateOne) Save(ctx context.Context) (*Document, error) {
|
||||
var (
|
||||
err error
|
||||
node *Document
|
||||
)
|
||||
duo.defaults()
|
||||
if len(duo.hooks) == 0 {
|
||||
if err = duo.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, err = duo.sqlSave(ctx)
|
||||
} else {
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*DocumentMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
if err = duo.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
duo.mutation = mutation
|
||||
node, err = duo.sqlSave(ctx)
|
||||
mutation.done = true
|
||||
return node, err
|
||||
})
|
||||
for i := len(duo.hooks) - 1; i >= 0; i-- {
|
||||
if duo.hooks[i] == nil {
|
||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||
}
|
||||
mut = duo.hooks[i](mut)
|
||||
}
|
||||
v, err := mut.Mutate(ctx, duo.mutation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nv, ok := v.(*Document)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected node type %T returned from DocumentMutation", v)
|
||||
}
|
||||
node = nv
|
||||
}
|
||||
return node, err
|
||||
return withHooks[*Document, DocumentMutation](ctx, duo.sqlSave, duo.mutation, duo.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
@@ -645,16 +420,10 @@ func (duo *DocumentUpdateOne) check() error {
|
||||
}
|
||||
|
||||
func (duo *DocumentUpdateOne) sqlSave(ctx context.Context) (_node *Document, err error) {
|
||||
_spec := &sqlgraph.UpdateSpec{
|
||||
Node: &sqlgraph.NodeSpec{
|
||||
Table: document.Table,
|
||||
Columns: document.Columns,
|
||||
ID: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: document.FieldID,
|
||||
},
|
||||
},
|
||||
if err := duo.check(); err != nil {
|
||||
return _node, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(document.Table, document.Columns, sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID))
|
||||
id, ok := duo.mutation.ID()
|
||||
if !ok {
|
||||
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Document.id" for update`)}
|
||||
@@ -680,25 +449,13 @@ func (duo *DocumentUpdateOne) sqlSave(ctx context.Context) (_node *Document, err
|
||||
}
|
||||
}
|
||||
if value, ok := duo.mutation.UpdatedAt(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeTime,
|
||||
Value: value,
|
||||
Column: document.FieldUpdatedAt,
|
||||
})
|
||||
_spec.SetField(document.FieldUpdatedAt, field.TypeTime, value)
|
||||
}
|
||||
if value, ok := duo.mutation.Title(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: document.FieldTitle,
|
||||
})
|
||||
_spec.SetField(document.FieldTitle, field.TypeString, value)
|
||||
}
|
||||
if value, ok := duo.mutation.Path(); ok {
|
||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeString,
|
||||
Value: value,
|
||||
Column: document.FieldPath,
|
||||
})
|
||||
_spec.SetField(document.FieldPath, field.TypeString, value)
|
||||
}
|
||||
if duo.mutation.GroupCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
@@ -708,10 +465,7 @@ func (duo *DocumentUpdateOne) sqlSave(ctx context.Context) (_node *Document, err
|
||||
Columns: []string{document.GroupColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: group.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
@@ -724,64 +478,7 @@ func (duo *DocumentUpdateOne) sqlSave(ctx context.Context) (_node *Document, err
|
||||
Columns: []string{document.GroupColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: group.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||
}
|
||||
if duo.mutation.DocumentTokensCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: document.DocumentTokensTable,
|
||||
Columns: []string{document.DocumentTokensColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: documenttoken.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := duo.mutation.RemovedDocumentTokensIDs(); len(nodes) > 0 && !duo.mutation.DocumentTokensCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: document.DocumentTokensTable,
|
||||
Columns: []string{document.DocumentTokensColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: documenttoken.FieldID,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := duo.mutation.DocumentTokensIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: document.DocumentTokensTable,
|
||||
Columns: []string{document.DocumentTokensColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: documenttoken.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -797,10 +494,7 @@ func (duo *DocumentUpdateOne) sqlSave(ctx context.Context) (_node *Document, err
|
||||
Columns: []string{document.AttachmentsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
@@ -813,10 +507,7 @@ func (duo *DocumentUpdateOne) sqlSave(ctx context.Context) (_node *Document, err
|
||||
Columns: []string{document.AttachmentsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -832,10 +523,7 @@ func (duo *DocumentUpdateOne) sqlSave(ctx context.Context) (_node *Document, err
|
||||
Columns: []string{document.AttachmentsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: &sqlgraph.FieldSpec{
|
||||
Type: field.TypeUUID,
|
||||
Column: attachment.FieldID,
|
||||
},
|
||||
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
@@ -854,5 +542,6 @@ func (duo *DocumentUpdateOne) sqlSave(ctx context.Context) (_node *Document, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
duo.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/document"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken"
|
||||
)
|
||||
|
||||
// DocumentToken is the model entity for the DocumentToken schema.
|
||||
type DocumentToken struct {
|
||||
config `json:"-"`
|
||||
// ID of the ent.
|
||||
ID uuid.UUID `json:"id,omitempty"`
|
||||
// CreatedAt holds the value of the "created_at" field.
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
// UpdatedAt holds the value of the "updated_at" field.
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
// Token holds the value of the "token" field.
|
||||
Token []byte `json:"token,omitempty"`
|
||||
// Uses holds the value of the "uses" field.
|
||||
Uses int `json:"uses,omitempty"`
|
||||
// ExpiresAt holds the value of the "expires_at" field.
|
||||
ExpiresAt time.Time `json:"expires_at,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the DocumentTokenQuery when eager-loading is set.
|
||||
Edges DocumentTokenEdges `json:"edges"`
|
||||
document_document_tokens *uuid.UUID
|
||||
}
|
||||
|
||||
// DocumentTokenEdges holds the relations/edges for other nodes in the graph.
|
||||
type DocumentTokenEdges struct {
|
||||
// Document holds the value of the document edge.
|
||||
Document *Document `json:"document,omitempty"`
|
||||
// loadedTypes holds the information for reporting if a
|
||||
// type was loaded (or requested) in eager-loading or not.
|
||||
loadedTypes [1]bool
|
||||
}
|
||||
|
||||
// DocumentOrErr returns the Document value or an error if the edge
|
||||
// was not loaded in eager-loading, or loaded but was not found.
|
||||
func (e DocumentTokenEdges) DocumentOrErr() (*Document, error) {
|
||||
if e.loadedTypes[0] {
|
||||
if e.Document == nil {
|
||||
// Edge was loaded but was not found.
|
||||
return nil, &NotFoundError{label: document.Label}
|
||||
}
|
||||
return e.Document, nil
|
||||
}
|
||||
return nil, &NotLoadedError{edge: "document"}
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*DocumentToken) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case documenttoken.FieldToken:
|
||||
values[i] = new([]byte)
|
||||
case documenttoken.FieldUses:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case documenttoken.FieldCreatedAt, documenttoken.FieldUpdatedAt, documenttoken.FieldExpiresAt:
|
||||
values[i] = new(sql.NullTime)
|
||||
case documenttoken.FieldID:
|
||||
values[i] = new(uuid.UUID)
|
||||
case documenttoken.ForeignKeys[0]: // document_document_tokens
|
||||
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected column %q for type DocumentToken", columns[i])
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||
// to the DocumentToken fields.
|
||||
func (dt *DocumentToken) assignValues(columns []string, values []any) error {
|
||||
if m, n := len(values), len(columns); m < n {
|
||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||
}
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case documenttoken.FieldID:
|
||||
if value, ok := values[i].(*uuid.UUID); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field id", values[i])
|
||||
} else if value != nil {
|
||||
dt.ID = *value
|
||||
}
|
||||
case documenttoken.FieldCreatedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field created_at", values[i])
|
||||
} else if value.Valid {
|
||||
dt.CreatedAt = value.Time
|
||||
}
|
||||
case documenttoken.FieldUpdatedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
|
||||
} else if value.Valid {
|
||||
dt.UpdatedAt = value.Time
|
||||
}
|
||||
case documenttoken.FieldToken:
|
||||
if value, ok := values[i].(*[]byte); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field token", values[i])
|
||||
} else if value != nil {
|
||||
dt.Token = *value
|
||||
}
|
||||
case documenttoken.FieldUses:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field uses", values[i])
|
||||
} else if value.Valid {
|
||||
dt.Uses = int(value.Int64)
|
||||
}
|
||||
case documenttoken.FieldExpiresAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field expires_at", values[i])
|
||||
} else if value.Valid {
|
||||
dt.ExpiresAt = value.Time
|
||||
}
|
||||
case documenttoken.ForeignKeys[0]:
|
||||
if value, ok := values[i].(*sql.NullScanner); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field document_document_tokens", values[i])
|
||||
} else if value.Valid {
|
||||
dt.document_document_tokens = new(uuid.UUID)
|
||||
*dt.document_document_tokens = *value.S.(*uuid.UUID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// QueryDocument queries the "document" edge of the DocumentToken entity.
|
||||
func (dt *DocumentToken) QueryDocument() *DocumentQuery {
|
||||
return (&DocumentTokenClient{config: dt.config}).QueryDocument(dt)
|
||||
}
|
||||
|
||||
// Update returns a builder for updating this DocumentToken.
|
||||
// Note that you need to call DocumentToken.Unwrap() before calling this method if this DocumentToken
|
||||
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||
func (dt *DocumentToken) Update() *DocumentTokenUpdateOne {
|
||||
return (&DocumentTokenClient{config: dt.config}).UpdateOne(dt)
|
||||
}
|
||||
|
||||
// Unwrap unwraps the DocumentToken entity that was returned from a transaction after it was closed,
|
||||
// so that all future queries will be executed through the driver which created the transaction.
|
||||
func (dt *DocumentToken) Unwrap() *DocumentToken {
|
||||
_tx, ok := dt.config.driver.(*txDriver)
|
||||
if !ok {
|
||||
panic("ent: DocumentToken is not a transactional entity")
|
||||
}
|
||||
dt.config.driver = _tx.drv
|
||||
return dt
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer.
|
||||
func (dt *DocumentToken) String() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString("DocumentToken(")
|
||||
builder.WriteString(fmt.Sprintf("id=%v, ", dt.ID))
|
||||
builder.WriteString("created_at=")
|
||||
builder.WriteString(dt.CreatedAt.Format(time.ANSIC))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("updated_at=")
|
||||
builder.WriteString(dt.UpdatedAt.Format(time.ANSIC))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("token=")
|
||||
builder.WriteString(fmt.Sprintf("%v", dt.Token))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("uses=")
|
||||
builder.WriteString(fmt.Sprintf("%v", dt.Uses))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("expires_at=")
|
||||
builder.WriteString(dt.ExpiresAt.Format(time.ANSIC))
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// DocumentTokens is a parsable slice of DocumentToken.
|
||||
type DocumentTokens []*DocumentToken
|
||||
|
||||
func (dt DocumentTokens) config(cfg config) {
|
||||
for _i := range dt {
|
||||
dt[_i].config = cfg
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user